lib: Add diff API

This is a *third* implementation of rpm database diffs in the code,
but it is now a public introspectable shared library API.

Further commits will change the command line tools to use this, and
then after that we'll further deduplicate the `db diff` from this
code.
This commit is contained in:
Colin Walters 2015-04-17 18:30:35 -04:00
parent 28ab27caf7
commit 3326e13481
3 changed files with 152 additions and 0 deletions

View File

@ -140,3 +140,136 @@ rpm_ostree_db_query (OstreeRepo *repo,
return query_all_packages_in_sack (rsack); return query_all_packages_in_sack (rsack);
} }
/**
* rpm_ostree_db_diff:
* @repo: An OSTree repository
* @orig_ref: Original ref (branch or commit)
* @new_ref: New ref (branch or commit)
* @query: (allow-none): A query, currently must be %NULL
* @out_removed: (out) (transfer container) (element-type RpmOstreePackage): Return location for removed packages
* @out_added: (out) (transfer container) (element-type RpmOstreePackage): Return location for added packages
* @out_modified_old: (out) (transfer container) (element-type RpmOstreePackage): Return location for modified old packages
* @out_modified_new: (out) (transfer container) (element-type RpmOstreePackage): Return location for modified new packages
*
* Compute the RPM package delta between two commits. Currently you
* must use %NULL for the @query parameter; in a future version this
* function may allow looking at a subset of the packages.
*
* The @out_modified_old and @out_modified_new arrays will always be
* the same length, and indicies will refer to the same base package
* name. It is possible in RPM databases to have multiple packages
* installed with the same name; in this case, the behavior will
* depend on whether the package set is transitioning from 1 -> N or N
* -> 1. In the former case, an arbitrary single instance of one of
* the new packages will be in @out_modified_new. If the latter, then
* multiple entries with the same name will be returned in
* the array @out_modified_old, with each having a reference to the
* single corresponding new package.
*/
gboolean
rpm_ostree_db_diff (OstreeRepo *repo,
const char *orig_ref,
const char *new_ref,
GVariant *query,
GPtrArray **out_removed,
GPtrArray **out_added,
GPtrArray **out_modified_old,
GPtrArray **out_modified_new,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(RpmOstreeRefSack) orig_sack = NULL;
g_autoptr(RpmOstreeRefSack) new_sack = NULL;
_cleanup_hypackagelist_ HyPackageList orig_pkglist = NULL;
_cleanup_hypackagelist_ HyPackageList new_pkglist = NULL;
g_autoptr(GPtrArray) ret_removed = g_ptr_array_new_with_free_func (g_object_unref);
g_autoptr(GPtrArray) ret_added = g_ptr_array_new_with_free_func (g_object_unref);
g_autoptr(GPtrArray) ret_modified_old = g_ptr_array_new_with_free_func (g_object_unref);
g_autoptr(GPtrArray) ret_modified_new = g_ptr_array_new_with_free_func (g_object_unref);
guint i;
HyPackage pkg;
g_return_val_if_fail (query == NULL, FALSE);
g_return_val_if_fail (out_removed != NULL && out_added != NULL &&
out_modified_old != NULL && out_modified_new != NULL, FALSE);
orig_sack = get_refsack_for_commit (repo, orig_ref, cancellable, error);
if (!orig_sack)
goto out;
{ _cleanup_hyquery_ HyQuery query = hy_query_create (orig_sack->sack);
hy_query_filter (query, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME);
orig_pkglist = hy_query_run (query);
}
new_sack = get_refsack_for_commit (repo, new_ref, cancellable, error);
if (!new_sack)
goto out;
{ _cleanup_hyquery_ HyQuery query = hy_query_create (new_sack->sack);
hy_query_filter (query, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME);
new_pkglist = hy_query_run (query);
}
FOR_PACKAGELIST(pkg, new_pkglist, i)
{
_cleanup_hyquery_ HyQuery query = NULL;
_cleanup_hypackagelist_ HyPackageList pkglist = NULL;
guint count;
HyPackage oldpkg;
query = hy_query_create (orig_sack->sack);
hy_query_filter (query, HY_PKG_NAME, HY_EQ, hy_package_get_name (pkg));
hy_query_filter (query, HY_PKG_EVR, HY_NEQ, hy_package_get_evr (pkg));
hy_query_filter (query, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME);
pkglist = hy_query_run (query);
count = hy_packagelist_count (pkglist);
if (count > 0)
{
/* See comment above about transitions from N -> 1 */
oldpkg = hy_packagelist_get (pkglist, 0);
g_ptr_array_add (ret_modified_old, _rpm_ostree_package_new (orig_sack, oldpkg));
g_ptr_array_add (ret_modified_new, _rpm_ostree_package_new (new_sack, pkg));
}
}
FOR_PACKAGELIST(pkg, orig_pkglist, i)
{
_cleanup_hyquery_ HyQuery query = NULL;
_cleanup_hypackagelist_ HyPackageList pkglist = NULL;
query = hy_query_create (new_sack->sack);
hy_query_filter (query, HY_PKG_NAME, HY_EQ, hy_package_get_name (pkg));
hy_query_filter (query, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME);
pkglist = hy_query_run (query);
if (hy_packagelist_count (pkglist) == 0)
g_ptr_array_add (ret_removed, _rpm_ostree_package_new (orig_sack, pkg));
}
FOR_PACKAGELIST(pkg, new_pkglist, i)
{
_cleanup_hyquery_ HyQuery query = NULL;
_cleanup_hypackagelist_ HyPackageList pkglist = NULL;
query = hy_query_create (orig_sack->sack);
hy_query_filter (query, HY_PKG_NAME, HY_EQ, hy_package_get_name (pkg));
hy_query_filter (query, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME);
pkglist = hy_query_run (query);
if (hy_packagelist_count (pkglist) == 0)
g_ptr_array_add (ret_added, _rpm_ostree_package_new (new_sack, pkg));
}
ret = TRUE;
*out_removed = g_steal_pointer (&ret_removed);
*out_added = g_steal_pointer (&ret_added);
*out_modified_old = g_steal_pointer (&ret_modified_old);
*out_modified_new = g_steal_pointer (&ret_modified_new);
out:
return ret;
}

View File

@ -31,4 +31,15 @@ _RPMOSTREE_EXTERN GPtrArray *rpm_ostree_db_query (OstreeRepo *repo
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
_RPMOSTREE_EXTERN gboolean rpm_ostree_db_diff (OstreeRepo *repo,
const char *orig_ref,
const char *new_ref,
GVariant *query,
GPtrArray **out_removed,
GPtrArray **out_added,
GPtrArray **out_modified_old,
GPtrArray **out_modified_new,
GCancellable *cancellable,
GError **error);
G_END_DECLS G_END_DECLS

View File

@ -12,3 +12,11 @@ print "Package list: "
for p in qr: for p in qr:
print p.get_nevra() print p.get_nevra()
_,removed,added,modold,modnew = RpmOstree.db_diff(r, ref + '^', ref, None, None)
for p in removed:
print "D " + p.get_nevra()
for p in added:
print "A " + p.get_nevra()
for o,n in zip(modold, modnew):
print "M {0} {1} -> {2}".format(o.get_name(), o.get_evr(), n.get_evr())