From 075d6bdad0c08b2c4199df15411cafa3ff9c2f96 Mon Sep 17 00:00:00 2001 From: petervo Date: Tue, 9 Jun 2015 19:27:39 -0700 Subject: [PATCH] daemon: Implement package diff methods --- Makefile-daemon.am | 2 + src/daemon/deployment-utils.c | 61 ++- src/daemon/deployment-utils.h | 3 + src/daemon/errors.c | 2 + src/daemon/errors.h | 1 + src/daemon/org.projectatomic.rpmostree1.xml | 8 +- src/daemon/os.c | 396 +++++++++++++++++++- src/daemon/rpmostree-package-variants.c | 213 +++++++++++ src/daemon/rpmostree-package-variants.h | 48 +++ 9 files changed, 712 insertions(+), 22 deletions(-) create mode 100644 src/daemon/rpmostree-package-variants.c create mode 100644 src/daemon/rpmostree-package-variants.h diff --git a/Makefile-daemon.am b/Makefile-daemon.am index 366551ee..5030afe2 100644 --- a/Makefile-daemon.am +++ b/Makefile-daemon.am @@ -30,6 +30,8 @@ librpmostreed_la_SOURCES = \ src/daemon/auth.c \ src/daemon/deployment-utils.h \ src/daemon/deployment-utils.c \ + src/daemon/rpmostree-package-variants.h \ + src/daemon/rpmostree-package-variants.c \ src/daemon/os.h \ src/daemon/os.c \ $(NULL) diff --git a/src/daemon/deployment-utils.c b/src/daemon/deployment-utils.c index 2afa86c2..5bae9930 100644 --- a/src/daemon/deployment-utils.c +++ b/src/daemon/deployment-utils.c @@ -16,9 +16,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" + #include "deployment-utils.h" -#include "libgsystem.h" +#include char * deployment_generate_id (OstreeDeployment *deployment) @@ -42,8 +44,9 @@ deployment_gpg_results (OstreeRepo *repo, GError *error = NULL; GVariant *ret = NULL; - gs_free gchar *remote = NULL; - gs_unref_object OstreeGpgVerifyResult *result = NULL; + g_autofree gchar *remote = NULL; + glnx_unref_object OstreeGpgVerifyResult *result = NULL; + guint n_sigs, i; gboolean gpg_verify; GVariantBuilder builder; @@ -87,17 +90,47 @@ out: return ret; } +char * +deployment_get_refspec (OstreeDeployment *deployment) +{ + GKeyFile *origin = NULL; // owned by deployment + char *origin_refspec = NULL; + origin = ostree_deployment_get_origin (deployment); + + if (!origin) + goto out; + + origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL); + +out: + return origin_refspec; +} + +GVariant * +deployment_generate_blank_variant (void) +{ + GVariantBuilder builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); + g_variant_builder_add (&builder, "s", ""); + g_variant_builder_add (&builder, "s", ""); + g_variant_builder_add (&builder, "i", -1); + g_variant_builder_add (&builder, "s", ""); + g_variant_builder_add (&builder, "s", ""); + g_variant_builder_add (&builder, "t", 0); + g_variant_builder_add (&builder, "s", ""); + g_variant_builder_add_value (&builder, g_variant_new("av", NULL)); + return g_variant_builder_end (&builder); +} GVariant * deployment_generate_variant (OstreeDeployment *deployment, OstreeRepo *repo) { - gs_unref_variant GVariant *commit = NULL; - g_autoptr (GKeyFile) origin = NULL; + g_autoptr (GVariant) commit = NULL; - gs_free gchar *origin_refspec = NULL; - gs_free gchar *version_commit = NULL; - gs_free gchar *id = NULL; + g_autofree gchar *origin_refspec = NULL; + g_autofree gchar *version_commit = NULL; + g_autofree gchar *id = NULL; GVariant *sigs = NULL; // floating variant GError *error = NULL; @@ -116,7 +149,7 @@ deployment_generate_variant (OstreeDeployment *deployment, &commit, &error)) { - gs_unref_variant GVariant *metadata = NULL; + g_autoptr (GVariant) metadata = NULL; timestamp = ostree_commit_get_timestamp (commit); metadata = g_variant_get_child_value (commit, 0); if (metadata != NULL) @@ -128,13 +161,9 @@ deployment_generate_variant (OstreeDeployment *deployment, } g_clear_error (&error); - origin = ostree_deployment_get_origin (deployment); - if (origin) - { - origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL); - if (origin_refspec) - sigs = deployment_gpg_results (repo, origin_refspec, csum); - } + origin_refspec = deployment_get_refspec (deployment); + if (origin_refspec) + sigs = deployment_gpg_results (repo, origin_refspec, csum); if (!sigs) sigs = g_variant_new ("av", NULL); diff --git a/src/daemon/deployment-utils.h b/src/daemon/deployment-utils.h index bc81b5ac..3987295c 100644 --- a/src/daemon/deployment-utils.h +++ b/src/daemon/deployment-utils.h @@ -24,5 +24,8 @@ char * deployment_generate_id (OstreeDeployment *deployment); +char * deployment_get_refspec (OstreeDeployment *deployment); + +GVariant * deployment_generate_blank_variant (void); GVariant * deployment_generate_variant (OstreeDeployment *deployment, OstreeRepo *repo); diff --git a/src/daemon/errors.c b/src/daemon/errors.c index 99e32d7b..740ffabe 100644 --- a/src/daemon/errors.c +++ b/src/daemon/errors.c @@ -29,6 +29,8 @@ static const GDBusErrorEntry dbus_error_entries[] = "org.projectatomic.rpmostreed.Error.NotAuthorized"}, {RPM_OSTREED_ERROR_UPDATE_IN_PROGRESS, "org.projectatomic.rpmostreed.Error.UpdateInProgress"}, + {RPM_OSTREED_ERROR_INVALID_REFSPEC, + "org.projectatomic.rpmostreed.Error.InvalidRefspec"}, }; GQuark diff --git a/src/daemon/errors.h b/src/daemon/errors.h index 35c3aa9f..b710b42a 100644 --- a/src/daemon/errors.h +++ b/src/daemon/errors.h @@ -31,6 +31,7 @@ typedef enum { RPM_OSTREED_ERROR_INVALID_SYSROOT, RPM_OSTREED_ERROR_NOT_AUTHORIZED, RPM_OSTREED_ERROR_UPDATE_IN_PROGRESS, + RPM_OSTREED_ERROR_INVALID_REFSPEC, RPM_OSTREED_ERROR_NUM_ENTRIES, } RpmOstreedError; diff --git a/src/daemon/org.projectatomic.rpmostree1.xml b/src/daemon/org.projectatomic.rpmostree1.xml index 1bde78f8..ed2d93ab 100644 --- a/src/daemon/org.projectatomic.rpmostree1.xml +++ b/src/daemon/org.projectatomic.rpmostree1.xml @@ -38,12 +38,18 @@ + + + + + + + - diff --git a/src/daemon/os.c b/src/daemon/os.c index 8476e2d8..aead0bb2 100644 --- a/src/daemon/os.c +++ b/src/daemon/os.c @@ -67,6 +67,34 @@ G_DEFINE_TYPE_WITH_CODE (OSStub, osstub, RPMOSTREE_TYPE_OS_SKELETON, G_IMPLEMENT_INTERFACE (RPMOSTREE_TYPE_OS, osstub_iface_init)); +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * task_result_invoke: + * + * Completes a GTask where the user_data is + * an invocation and the task data or error is + * passed to the invocation when called back. + */ +static void +task_result_invoke (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + glnx_unref_object GTask *task = G_TASK (res); + GError *error = NULL; + + GDBusMethodInvocation *invocation = user_data; + + GVariant *result = g_task_propagate_pointer (task, &error); + + if (error) + g_dbus_method_invocation_take_error (invocation, error); + else + g_dbus_method_invocation_return_value (invocation, result); +} + + static void task_data_free (TaskData *data) { @@ -87,7 +115,7 @@ sysroot_changed (Sysroot *sysroot, gpointer user_data) { OSStub *self = OSSTUB (user_data); - g_return_val_if_fail (OSTREE_IS_SYSROOT (ot_sysroot), NULL); + g_return_if_fail (OSTREE_IS_SYSROOT (ot_sysroot)); osstub_load_internals (self, ot_sysroot); } @@ -199,6 +227,318 @@ out: return index_to_prepend; } + +/** + * refspec_parse_partial: + * @new_provided_refspec: The provided refspec + * @base_refspec: The refspec string to base on. + * @out_refspec: Pointer to the new refspec + * @error: Pointer to an error pointer. + * + * Takes a refspec string and adds any missing bits based on the + * base_refspec argument. Errors if a full valid refspec can't + * be derived. + * + * Returns: True on sucess. + */ +static gboolean +refspec_parse_partial (const gchar *new_provided_refspec, + gchar *base_refspec, + gchar **out_refspec, + GError **error) +{ + + g_autofree gchar *ref = NULL; + g_autofree gchar *remote = NULL; + g_autofree gchar *origin_ref = NULL; + g_autofree gchar *origin_remote = NULL; + GError *parse_error = NULL; + + gboolean ret = FALSE; + + /* Allow just switching remotes */ + if (g_str_has_suffix (new_provided_refspec, ":")) + { + remote = g_strdup (new_provided_refspec); + remote[strlen (remote) - 1] = '\0'; + } + else + { + if (!ostree_parse_refspec (new_provided_refspec, &remote, + &ref, &parse_error)) + { + g_set_error_literal (error, RPM_OSTREED_ERROR, + RPM_OSTREED_ERROR_INVALID_REFSPEC, + parse_error->message); + g_clear_error (&parse_error); + goto out; + } + } + + if (base_refspec != NULL) + { + if (!ostree_parse_refspec (base_refspec, &origin_remote, + &origin_ref, &parse_error)) + goto out; + } + + if (ref == NULL) + { + if (origin_ref) + { + ref = g_strdup (origin_ref); + } + + else + { + g_set_error (error, RPM_OSTREED_ERROR, + RPM_OSTREED_ERROR_INVALID_REFSPEC, + "Could not determine default ref to pull."); + goto out; + } + + } + else if (remote == NULL) + { + if (origin_remote) + { + remote = g_strdup (origin_remote); + } + else + { + g_set_error (error, RPM_OSTREED_ERROR, + RPM_OSTREED_ERROR_INVALID_REFSPEC, + "Could not determine default remote to pull."); + goto out; + } + } + + if (g_strcmp0 (origin_remote, remote) == 0 && + g_strcmp0 (origin_ref, ref) == 0) + { + g_set_error (error, RPM_OSTREED_ERROR, + RPM_OSTREED_ERROR_INVALID_REFSPEC, + "Old and new refs are equal: %s:%s", + remote, ref); + goto out; + } + + *out_refspec = g_strconcat (remote, ":", ref, NULL); + ret = TRUE; + +out: + return ret; +} + + +static OstreeDeployment * +get_deployment_for_id (OstreeSysroot *sysroot, + const gchar *deploy_id) +{ + g_autoptr (GPtrArray) deployments = NULL; + guint i; + + OstreeDeployment *deployment = NULL; + + deployments = ostree_sysroot_get_deployments (sysroot); + if (deployments == NULL) + goto out; + + for (i=0; ilen; i++) + { + g_autofree gchar *id = deployment_generate_id (deployments->pdata[i]); + if (g_strcmp0 (deploy_id, id) == 0) { + deployment = g_object_ref (deployments->pdata[i]); + } + } + +out: + return deployment; +} + +static void +set_diff_task_result (GTask *task, + GVariant *value, + GError *error) +{ + if (error == NULL) + { + g_task_return_pointer (task, + g_variant_new ("(@a(sua{sv}))", value), + NULL); + } + else + { + g_task_return_error (task, error); + } +} + +static void +get_rebase_diff_variant_in_thread (GTask *task, + gpointer object, + gpointer data_ptr, + GCancellable *cancellable) +{ + RPMOSTreeOS *self = RPMOSTREE_OS (object); + const gchar *name; + + glnx_unref_object OstreeSysroot *ot_sysroot = NULL; + glnx_unref_object OstreeRepo *ot_repo = NULL; + glnx_unref_object OstreeDeployment *base_deployment = NULL; + g_autofree gchar *comp_ref = NULL; + g_autofree gchar *base_refspec = NULL; + + GVariant *value = NULL; // freed when invoked + GError *error = NULL; // freed when invoked + gchar *refspec = data_ptr; // freed by task + + if (!utils_load_sysroot_and_repo (sysroot_get_sysroot_path ( sysroot_get ()), + cancellable, + &ot_sysroot, + &ot_repo, + &error)) + goto out; + + name = rpmostree_os_get_name (self); + base_deployment = ostree_sysroot_get_merge_deployment (ot_sysroot, name); + if (base_deployment == NULL) + { + g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No deployments found for os %s", name); + goto out; + } + + base_refspec = deployment_get_refspec (base_deployment); + if (!refspec_parse_partial (refspec, + base_refspec, + &comp_ref, + &error)) + goto out; + + value = rpm_ostree_db_diff_variant (ot_repo, + ostree_deployment_get_csum (base_deployment), + comp_ref, + cancellable, + &error); + +out: + set_diff_task_result (task, value, error); +} + +static void +get_upgrade_diff_variant_in_thread (GTask *task, + gpointer object, + gpointer data_ptr, + GCancellable *cancellable) +{ + RPMOSTreeOS *self = RPMOSTREE_OS (object); + const gchar *name; + + g_autofree gchar *comp_ref = NULL; + glnx_unref_object OstreeSysroot *ot_sysroot = NULL; + glnx_unref_object OstreeRepo *ot_repo = NULL; + glnx_unref_object OstreeDeployment *base_deployment = NULL; + + GVariant *value = NULL; // freed when invoked + GError *error = NULL; // freed when invoked + + if (!utils_load_sysroot_and_repo (sysroot_get_sysroot_path ( sysroot_get ()), + cancellable, + &ot_sysroot, + &ot_repo, + &error)) + goto out; + + name = rpmostree_os_get_name (self); + base_deployment = ostree_sysroot_get_merge_deployment (ot_sysroot, name); + if (base_deployment == NULL) + { + g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No deployments found for os %s", name); + goto out; + } + + comp_ref = deployment_get_refspec (base_deployment); + if (!comp_ref) + { + g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No upgrade remote found for os %s", name); + goto out; + } + + value = rpm_ostree_db_diff_variant (ot_repo, + ostree_deployment_get_csum (base_deployment), + comp_ref, + cancellable, + &error); + +out: + set_diff_task_result (task, value, error); +} + +static void +get_deployments_diff_variant_in_thread (GTask *task, + gpointer object, + gpointer data_ptr, + GCancellable *cancellable) +{ + const gchar *ref0; + const gchar *ref1; + + glnx_unref_object OstreeDeployment *deployment0 = NULL; + glnx_unref_object OstreeDeployment *deployment1 = NULL; + glnx_unref_object OstreeSysroot *ot_sysroot = NULL; + glnx_unref_object OstreeRepo *ot_repo = NULL; + + GVariant *value = NULL; // freed when invoked + GError *error = NULL; // freed when invoked + GPtrArray *compare_refs = data_ptr; // freed by task + + g_return_if_fail (compare_refs->len == 2); + + if (!utils_load_sysroot_and_repo (sysroot_get_sysroot_path ( sysroot_get ()), + cancellable, + &ot_sysroot, + &ot_repo, + &error)) + goto out; + + deployment0 = get_deployment_for_id (ot_sysroot, compare_refs->pdata[0]); + if (!deployment0) + { + gchar *id = compare_refs->pdata[0]; + g_set_error (&error, + RPM_OSTREED_ERROR, + RPM_OSTREED_ERROR_FAILED, + "Invalid deployment id %s", + id); + goto out; + } + ref0 = ostree_deployment_get_csum (deployment0); + + deployment1 = get_deployment_for_id (ot_sysroot, compare_refs->pdata[1]); + if (!deployment1) + { + gchar *id = compare_refs->pdata[1]; + g_set_error (&error, + RPM_OSTREED_ERROR, + RPM_OSTREED_ERROR_FAILED, + "Invalid deployment id %s", + id); + goto out; + } + ref1 = ostree_deployment_get_csum (deployment1); + + value = rpm_ostree_db_diff_variant (ot_repo, + ref0, + ref1, + cancellable, + &error); + +out: + set_diff_task_result (task, value, error); +} + static void osstub_upgrade_thread (GTask *task, gpointer source_object, @@ -282,12 +622,47 @@ osstub_transaction_complete (GObject *source_object, g_clear_error (&local_error); } + +static gboolean +handle_get_deployments_rpm_diff (RPMOSTreeOS *interface, + GDBusMethodInvocation *invocation, + const char *arg_deployid0, + const char *arg_deployid1) +{ + OSStub *self = OSSTUB (interface); + GPtrArray *compare_refs = NULL; // freed by task + GTask *task = NULL; + + glnx_unref_object GCancellable *cancellable = NULL; + + compare_refs = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (compare_refs, g_strdup (arg_deployid0)); + g_ptr_array_add (compare_refs, g_strdup (arg_deployid1)); + + task = g_task_new (self, cancellable, + task_result_invoke, + invocation); + g_task_set_task_data (task, + compare_refs, + (GDestroyNotify) g_ptr_array_unref); + g_task_run_in_thread (task, get_deployments_diff_variant_in_thread); + + return TRUE; +} + static gboolean osstub_handle_get_cached_update_rpm_diff (RPMOSTreeOS *interface, - GDBusMethodInvocation *invocation, - const char *arg_deployid) + GDBusMethodInvocation *invocation) { - /* FIXME */ + OSStub *self = OSSTUB (interface); + GTask *task = NULL; + + glnx_unref_object GCancellable *cancellable = NULL; + + task = g_task_new (self, cancellable, + task_result_invoke, + invocation); + g_task_run_in_thread (task, get_upgrade_diff_variant_in_thread); return TRUE; } @@ -476,7 +851,18 @@ osstub_handle_get_cached_rebase_rpm_diff (RPMOSTreeOS *interface, const char *arg_refspec, const char * const *arg_packages) { - /* FIXME */ + OSStub *self = OSSTUB (interface); + GTask *task = NULL; + glnx_unref_object GCancellable *cancellable = NULL; + + /* TODO: Totally ignoring packages for now */ + task = g_task_new (self, cancellable, + task_result_invoke, + invocation); + g_task_set_task_data (task, + g_strdup (arg_refspec), + g_free); + g_task_run_in_thread (task, get_rebase_diff_variant_in_thread); return TRUE; } diff --git a/src/daemon/rpmostree-package-variants.c b/src/daemon/rpmostree-package-variants.c new file mode 100644 index 00000000..5942d492 --- /dev/null +++ b/src/daemon/rpmostree-package-variants.c @@ -0,0 +1,213 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2015 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the licence or (at + * your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include "rpmostree-package-variants.h" +#include + +static GVariant * +build_diff_variant (const gchar *name, + guint type, + RpmOstreePackage *old_package, + RpmOstreePackage *new_package) +{ + GVariantBuilder options_builder; + GVariantBuilder builder; + g_variant_builder_init (&options_builder, G_VARIANT_TYPE ("a{sv}")); + + if (old_package) + { + g_variant_builder_add (&options_builder, "{sv}", "PreviousPackage", + rpm_ostree_package_to_variant (old_package)); + } + + if (new_package) + { + g_variant_builder_add (&options_builder, "{sv}", "NewPackage", + rpm_ostree_package_to_variant (new_package)); + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); + g_variant_builder_add (&builder, "s", name); + g_variant_builder_add (&builder, "u", type); + g_variant_builder_add_value (&builder, g_variant_builder_end (&options_builder)); + return g_variant_builder_end (&builder); +} + + +/** + * rpm_ostree_package_to_variant + * @package: RpmOstreePackage + * + * Returns: A GVariant of (sss) where values are + * (package name, evr, arch) + */ +GVariant * +rpm_ostree_package_to_variant (RpmOstreePackage *package) +{ + return g_variant_new ("(sss)", + rpm_ostree_package_get_name (package), + rpm_ostree_package_get_evr (package), + rpm_ostree_package_get_arch (package)); +} + + +int +rpm_ostree_db_diff_variant_compare_by_name (const void *v1, + const void *v2) + +{ + GVariant **v1pp = (GVariant**)v1; + GVariant *variant1 = *v1pp; + GVariant **v2pp = (GVariant**)v2; + GVariant *variant2 = *v2pp; + + gchar *name1 = NULL; + gchar *name2 = NULL; + g_variant_get_child (variant1, 0, "&s", &name1); + g_variant_get_child (variant2, 0, "&s", &name2); + + return g_strcmp0 (name1, name2); +} + +int +rpm_ostree_db_diff_variant_compare_by_type (const void *v1, + const void *v2) + +{ + GVariant **v1pp = (GVariant**)v1; + GVariant *variant1 = *v1pp; + GVariant **v2pp = (GVariant**)v2; + GVariant *variant2 = *v2pp; + + guint type1; + guint type2; + + g_variant_get_child (variant1, 1, "u", &type1); + g_variant_get_child (variant2, 1, "u", &type2); + + if (type1 == type2) + return rpm_ostree_db_diff_variant_compare_by_name (v1, v2); + + return type1 - type2; +} + +/** + * rpm_ostree_db_build_diff_variant + * @repo: A OstreeRepo + * @old_ref: old ref to use + * @new_ref: New ref to use + * GCancellable: *cancellable + * GError: **error + * + * Returns: A GVariant that represents the differences + * between the rpm databases on the given refs. + */ +GVariant * +rpm_ostree_db_diff_variant (OstreeRepo *repo, + const char *from_rev, + const char *to_rev, + GCancellable *cancellable, + GError **error) +{ + GVariant *variant = NULL; + GVariantBuilder builder; + + g_autoptr (GPtrArray) removed = NULL; + g_autoptr (GPtrArray) added = NULL; + g_autoptr (GPtrArray) modified_old = NULL; + g_autoptr (GPtrArray) modified_new = NULL; + g_autoptr (GPtrArray) found = NULL; + + guint i; + + found = g_ptr_array_new (); + + if (!rpm_ostree_db_diff (repo, from_rev, to_rev, + &removed, &added, &modified_old, + &modified_new, cancellable, error)) + goto out; + + if (modified_old->len > 0) + { + for (i = 0; i < modified_old->len; i++) + { + guint type = RPM_OSTREE_PACKAGE_UPGRADED; + RpmOstreePackage *oldpkg = modified_old->pdata[i]; + RpmOstreePackage *newpkg; + + const char *name = rpm_ostree_package_get_name (oldpkg); + g_assert_cmpuint (i, <, modified_new->len); + newpkg = modified_new->pdata[i]; + + if (rpm_ostree_package_cmp (oldpkg, newpkg) > 0) + type = RPM_OSTREE_PACKAGE_DOWNGRADED; + + g_ptr_array_add (found, + build_diff_variant (name, type, oldpkg, newpkg)); + } + } + + if (removed->len > 0) + { + for (i = 0; i < removed->len; i++) + { + RpmOstreePackage *pkg = removed->pdata[i]; + const char *name = rpm_ostree_package_get_name (pkg); + g_ptr_array_add (found, + build_diff_variant (name, + RPM_OSTREE_PACKAGE_REMOVED, + pkg, + NULL)); + } + } + + if (added->len > 0) + { + for (i = 0; i < added->len; i++) + { + RpmOstreePackage *pkg = added->pdata[i]; + const char *name = rpm_ostree_package_get_name (pkg); + g_ptr_array_add (found, + build_diff_variant (name, + RPM_OSTREE_PACKAGE_ADDED, + NULL, + pkg)); + } + } + + g_ptr_array_sort (found, rpm_ostree_db_diff_variant_compare_by_type); + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + for (i = 0; i < found->len; i++) + { + GVariant *v = found->pdata[i]; + g_variant_builder_add_value (&builder, v); + } + + if (found->len > 1) + variant = g_variant_builder_end (&builder); + else + variant = g_variant_new ("a(sua{sv})", NULL); + +out: + return variant; +} diff --git a/src/daemon/rpmostree-package-variants.h b/src/daemon/rpmostree-package-variants.h new file mode 100644 index 00000000..e5c76ade --- /dev/null +++ b/src/daemon/rpmostree-package-variants.h @@ -0,0 +1,48 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2015 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the licence or (at + * your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include + +typedef enum { + RPM_OSTREE_PACKAGE_ADDED, + RPM_OSTREE_PACKAGE_REMOVED, + RPM_OSTREE_PACKAGE_UPGRADED, + RPM_OSTREE_PACKAGE_DOWNGRADED +} RpmOstreePackageDiffTypes; + + +GVariant * rpm_ostree_db_diff_variant (OstreeRepo *repo, + const char *from_ref, + const char *to_ref, + GCancellable *cancellable, + GError **error); + +int rpm_ostree_db_diff_variant_compare_by_name (const void *v1, + const void *v2); + +int rpm_ostree_db_diff_variant_compare_by_type (const void *v1, + const void *v2); + + +_RPMOSTREE_EXTERN +GVariant * rpm_ostree_package_to_variant (RpmOstreePackage *package);