Start moving some jigdo logic into core

The jigdo ♲📦 effort really throws a spanner into the logic behind our whole
code layout; so far I mostly sidestepped that by having a lot of the new logic
in the CLI, with just some `_jigdo_xxx()` methods in core code.

But in order to start on having the "sysroot" side use jigdo, let's start
moving some bits into core.

Closes: #1144
Approved by: jlebon
This commit is contained in:
Colin Walters 2017-12-12 18:11:01 -05:00 committed by Atomic Bot
parent 879c5afefc
commit 1793480155
3 changed files with 193 additions and 104 deletions

View File

@ -141,15 +141,6 @@ commit_and_print (RpmOstreeJigdo2CommitContext *self,
return TRUE;
}
static int
compare_pkgs_reverse (gconstpointer ap,
gconstpointer bp)
{
DnfPackage **a = (gpointer)ap;
DnfPackage **b = (gpointer)bp;
return dnf_package_cmp (*b, *a); // Reverse
}
static int
compare_pkgs (gconstpointer ap,
gconstpointer bp)
@ -161,23 +152,15 @@ compare_pkgs (gconstpointer ap,
static gboolean
impl_jigdo2commit (RpmOstreeJigdo2CommitContext *self,
const char *repoid_and_oirpm_name,
const char *jigdo_id,
GCancellable *cancellable,
GError **error)
{
g_autofree char *oirpm_repoid = NULL;
g_autofree char *oirpm_name = NULL;
/* We expect REPOID:OIRPM-NAME */
{ const char *colon = strchr (repoid_and_oirpm_name, ':');
if (!colon)
return glnx_throw (error, "Invalid OIRPM spec '%s', expected repoid:name", repoid_and_oirpm_name);
oirpm_repoid = g_strndup (repoid_and_oirpm_name, colon - repoid_and_oirpm_name);
oirpm_name = g_strdup (colon + 1);
}
g_autoptr(GKeyFile) tsk = g_key_file_new ();
g_key_file_set_string (tsk, "tree", "jigdo", jigdo_id);
if (opt_oirpm_version)
g_key_file_set_string (tsk, "tree", "jigdo-version", opt_oirpm_version);
if (opt_releasever)
g_key_file_set_string (tsk, "tree", "releasever", opt_releasever);
if (opt_enable_rpmmdrepo)
@ -188,67 +171,16 @@ impl_jigdo2commit (RpmOstreeJigdo2CommitContext *self,
if (!treespec)
return FALSE;
/* We're also "pure" jigdo - this adds assertions that we don't depsolve for example */
if (!rpmostree_context_setup (self->ctx, NULL, NULL, treespec, cancellable, error))
return FALSE;
if (!rpmostree_context_download_metadata (self->ctx, cancellable, error))
if (!rpmostree_context_prepare_jigdo (self->ctx, cancellable, error))
return FALSE;
DnfPackage* oirpm_pkg = rpmostree_context_get_jigdo_pkg (self->ctx);
const char *provided_commit = rpmostree_context_get_jigdo_checksum (self->ctx);
DnfContext *dnfctx = rpmostree_context_get_dnf (self->ctx);
g_autoptr(DnfPackage) oirpm_pkg = NULL;
g_autofree char *provided_commit = NULL;
{ hy_autoquery HyQuery query = hy_query_create (dnf_context_get_sack (dnfctx));
hy_query_filter (query, HY_PKG_REPONAME, HY_EQ, oirpm_repoid);
hy_query_filter (query, HY_PKG_NAME, HY_EQ, oirpm_name);
if (opt_oirpm_version)
hy_query_filter (query, HY_PKG_VERSION, HY_EQ, opt_oirpm_version);
g_autoptr(GPtrArray) pkglist = hy_query_run (query);
if (pkglist->len == 0)
return glnx_throw (error, "Failed to find jigdo OIRPM package '%s'", oirpm_name);
g_ptr_array_sort (pkglist, compare_pkgs_reverse);
if (pkglist->len > 1)
{
g_print ("%u oirpm matches\n", pkglist->len);
}
g_ptr_array_set_size (pkglist, 1);
oirpm_pkg = g_object_ref (pkglist->pdata[0]);
/* Iterate over provides directly to provide a nicer error on mismatch */
gboolean found_vprovide = FALSE;
g_autoptr(DnfReldepList) provides = dnf_package_get_provides (oirpm_pkg);
const gint n_provides = dnf_reldep_list_count (provides);
for (int i = 0; i < n_provides; i++)
{
DnfReldep *provide = dnf_reldep_list_index (provides, i);
const char *provide_str = dnf_reldep_to_string (provide);
if (g_str_equal (provide_str, RPMOSTREE_JIGDO_PROVIDE_V3))
{
found_vprovide = TRUE;
}
else if (g_str_has_prefix (provide_str, RPMOSTREE_JIGDO_PROVIDE_COMMIT))
{
const char *rest = provide_str + strlen (RPMOSTREE_JIGDO_PROVIDE_COMMIT);
if (*rest != '(')
return glnx_throw (error, "Invalid %s", provide_str);
rest++;
const char *closeparen = strchr (rest, ')');
if (!closeparen)
return glnx_throw (error, "Invalid %s", provide_str);
provided_commit = g_strndup (rest, closeparen - rest);
if (strlen (provided_commit) != OSTREE_SHA256_STRING_LEN)
return glnx_throw (error, "Invalid %s", provide_str);
}
}
if (!found_vprovide)
return glnx_throw (error, "Package '%s' does not have Provides: %s",
dnf_package_get_nevra (oirpm_pkg), RPMOSTREE_JIGDO_PROVIDE_V3);
if (!provided_commit)
return glnx_throw (error, "Package '%s' does not have Provides: %s",
dnf_package_get_nevra (oirpm_pkg), RPMOSTREE_JIGDO_PROVIDE_COMMIT);
}
g_print ("oirpm: %s (%s) commit=%s\n", dnf_package_get_nevra (oirpm_pkg),
dnf_package_get_reponame (oirpm_pkg), provided_commit);

View File

@ -33,6 +33,7 @@
#include <librepo/librepo.h>
#include "rpmostree-core.h"
#include "rpmostree-jigdo-core.h"
#include "rpmostree-postprocess.h"
#include "rpmostree-rpm-util.h"
#include "rpmostree-passwd-util.h"
@ -51,6 +52,15 @@
static OstreeRepo * get_pkgcache_repo (RpmOstreeContext *self);
static int
compare_pkgs (gconstpointer ap,
gconstpointer bp)
{
DnfPackage **a = (gpointer)ap;
DnfPackage **b = (gpointer)bp;
return dnf_package_cmp (*a, *b);
}
/***********************************************************
* RpmOstreeTreespec *
***********************************************************
@ -170,6 +180,12 @@ rpmostree_treespec_new_from_keyfile (GKeyFile *keyfile,
g_variant_builder_add (&builder, "{sv}", "ref", g_variant_new_string (ref));
}
/* See if we're using jigdo */
{ g_autofree char *jigdo = g_key_file_get_string (keyfile, "tree", "jigdo", NULL);
if (jigdo)
g_variant_builder_add (&builder, "{sv}", "jigdo", g_variant_new_string (jigdo));
}
add_canonicalized_string_array (&builder, "packages", NULL, keyfile);
add_canonicalized_string_array (&builder, "cached-packages", NULL, keyfile);
add_canonicalized_string_array (&builder, "removed-base-packages", NULL, keyfile);
@ -243,6 +259,14 @@ struct _RpmOstreeContext {
RpmOstreeTreespec *spec;
gboolean empty;
/* jigdo-mode data */
const char *jigdo_spec; /* The jigdo spec like: repoid:package */
const char *jigdo_version; /* Optional */
gboolean jigdo_pure; /* There is only jigdo */
DnfPackage *jigdo_pkg;
char *jigdo_checksum;
gboolean pkgcache_only;
DnfContext *dnfctx;
OstreeRepo *ostreerepo;
@ -281,6 +305,9 @@ rpmostree_context_finalize (GObject *object)
g_clear_object (&rctx->spec);
g_clear_object (&rctx->dnfctx);
g_clear_object (&rctx->jigdo_pkg);
g_free (rctx->jigdo_checksum);
g_clear_object (&rctx->pkgcache_repo);
g_clear_object (&rctx->ostreerepo);
g_clear_pointer (&rctx->devino_cache, (GDestroyNotify)ostree_repo_devino_cache_unref);
@ -687,6 +714,11 @@ rpmostree_context_setup (RpmOstreeContext *self,
return glnx_throw (error, "No enabled repositories");
}
/* Keep a handy pointer to the jigdo source if specified, since it influences
* a lot of things here.
*/
g_variant_dict_lookup (self->spec->dict, "jigdo", "&s", &self->jigdo_spec);
/* Ensure that each repo that's enabled is marked as required; this should be
* the default, but we make sure. This is a bit of a messy topic, but for
* rpm-ostree we're being more strict about requiring repos.
@ -1699,6 +1731,79 @@ add_remaining_pkgcache_pkgs (RpmOstreeContext *self,
return TRUE;
}
static gboolean
setup_jigdo_state (RpmOstreeContext *self,
GError **error)
{
g_assert (self->jigdo_spec);
g_assert (!self->jigdo_pkg);
g_assert (!self->jigdo_checksum);
g_autofree char *jigdo_repoid = NULL;
g_autofree char *jigdo_name = NULL;
{ const char *colon = strchr (self->jigdo_spec, ':');
if (!colon)
return glnx_throw (error, "Invalid jigdo spec '%s', expected repoid:name", self->jigdo_spec);
jigdo_repoid = g_strndup (self->jigdo_spec, colon - self->jigdo_spec);
jigdo_name = g_strdup (colon + 1);
}
const char *jigdo_version = NULL;
g_variant_dict_lookup (self->spec->dict, "jigdo-version", "&s", &jigdo_version);
hy_autoquery HyQuery query = hy_query_create (dnf_context_get_sack (self->dnfctx));
hy_query_filter (query, HY_PKG_REPONAME, HY_EQ, jigdo_repoid);
hy_query_filter (query, HY_PKG_NAME, HY_EQ, jigdo_name);
if (jigdo_version)
hy_query_filter (query, HY_PKG_VERSION, HY_EQ, jigdo_version);
g_autoptr(GPtrArray) pkglist = hy_query_run (query);
if (pkglist->len == 0)
return glnx_throw (error, "Failed to find jigdo package '%s'", self->jigdo_spec);
g_ptr_array_sort (pkglist, compare_pkgs);
/* We use the last package in the array which should be newest */
self->jigdo_pkg = g_object_ref (pkglist->pdata[pkglist->len-1]);
/* Iterate over provides directly to provide a nicer error on mismatch */
gboolean found_vprovide = FALSE;
g_autoptr(DnfReldepList) provides = dnf_package_get_provides (self->jigdo_pkg);
const gint n_provides = dnf_reldep_list_count (provides);
for (int i = 0; i < n_provides; i++)
{
DnfReldep *provide = dnf_reldep_list_index (provides, i);
const char *provide_str = dnf_reldep_to_string (provide);
if (g_str_equal (provide_str, RPMOSTREE_JIGDO_PROVIDE_V3))
{
found_vprovide = TRUE;
}
else if (g_str_has_prefix (provide_str, RPMOSTREE_JIGDO_PROVIDE_COMMIT))
{
const char *rest = provide_str + strlen (RPMOSTREE_JIGDO_PROVIDE_COMMIT);
if (*rest != '(')
return glnx_throw (error, "Invalid %s", provide_str);
rest++;
const char *closeparen = strchr (rest, ')');
if (!closeparen)
return glnx_throw (error, "Invalid %s", provide_str);
self->jigdo_checksum = g_strndup (rest, closeparen - rest);
if (strlen (self->jigdo_checksum) != OSTREE_SHA256_STRING_LEN)
return glnx_throw (error, "Invalid %s", provide_str);
}
}
if (!found_vprovide)
return glnx_throw (error, "Package '%s' does not have Provides: %s",
dnf_package_get_nevra (self->jigdo_pkg), RPMOSTREE_JIGDO_PROVIDE_V3);
if (!self->jigdo_checksum)
return glnx_throw (error, "Package '%s' does not have Provides: %s",
dnf_package_get_nevra (self->jigdo_pkg), RPMOSTREE_JIGDO_PROVIDE_COMMIT);
return TRUE;
}
/* Check for/download new rpm-md, then depsolve */
gboolean
rpmostree_context_prepare (RpmOstreeContext *self,
@ -1731,13 +1836,20 @@ rpmostree_context_prepare (RpmOstreeContext *self,
return FALSE;
}
HyGoal goal = dnf_context_get_goal (dnfctx);
if (self->jigdo_pure)
{
g_assert_cmpint (g_strv_length (pkgnames), ==, 0);
g_assert_cmpint (g_strv_length (cached_pkgnames), ==, 0);
g_assert_cmpint (g_strv_length (cached_replace_pkgs), ==, 0);
g_assert_cmpint (g_strv_length (removed_base_pkgnames), ==, 0);
}
/* Handle packages to remove */
g_autoptr(GPtrArray) removed_pkgnames = g_ptr_array_new ();
for (char **it = removed_base_pkgnames; it && *it; it++)
{
const char *pkgname = *it;
g_assert (!self->jigdo_pure);
if (!dnf_context_remove (dnfctx, pkgname, error))
return FALSE;
@ -1756,6 +1868,7 @@ rpmostree_context_prepare (RpmOstreeContext *self,
if (!rpmostree_decompose_sha256_nevra (&nevra, &sha256, error))
return FALSE;
g_assert (!self->jigdo_pure);
if (!install_pkg_from_cache (self, nevra, sha256, cancellable, error))
return FALSE;
@ -1771,6 +1884,7 @@ rpmostree_context_prepare (RpmOstreeContext *self,
if (!rpmostree_decompose_sha256_nevra (&nevra, &sha256, error))
return FALSE;
g_assert (!self->jigdo_pure);
if (!install_pkg_from_cache (self, nevra, sha256, cancellable, error))
return FALSE;
@ -1791,33 +1905,59 @@ rpmostree_context_prepare (RpmOstreeContext *self,
for (char **it = pkgnames; it && *it; it++)
{
const char *pkgname = *it;
g_assert (!self->jigdo_pure);
if (!dnf_context_install (dnfctx, pkgname, error))
return FALSE;
}
rpmostree_output_task_begin ("Resolving dependencies");
/* XXX: consider a --allow-uninstall switch? */
if (!dnf_goal_depsolve (goal, DNF_INSTALL | DNF_ALLOW_UNINSTALL, error) ||
!check_goal_solution (self, removed_pkgnames, replaced_nevras, error))
if (self->jigdo_spec)
{
rpmostree_output_task_end ("failed");
return FALSE;
}
g_autoptr(GPtrArray) packages = dnf_goal_get_packages (dnf_context_get_goal (dnfctx),
DNF_PACKAGE_INFO_INSTALL,
DNF_PACKAGE_INFO_UPDATE,
DNF_PACKAGE_INFO_DOWNGRADE, -1);
if (!sort_packages (self, packages, cancellable, error))
{
rpmostree_output_task_end ("failed");
return FALSE;
if (!setup_jigdo_state (self, error))
return FALSE;
}
if (!self->jigdo_pure)
{
HyGoal goal = dnf_context_get_goal (dnfctx);
rpmostree_output_task_begin ("Resolving dependencies");
/* XXX: consider a --allow-uninstall switch? */
if (!dnf_goal_depsolve (goal, DNF_INSTALL | DNF_ALLOW_UNINSTALL, error) ||
!check_goal_solution (self, removed_pkgnames, replaced_nevras, error))
{
rpmostree_output_task_end ("failed");
return FALSE;
}
g_autoptr(GPtrArray) packages = dnf_goal_get_packages (dnf_context_get_goal (dnfctx),
DNF_PACKAGE_INFO_INSTALL,
DNF_PACKAGE_INFO_UPDATE,
DNF_PACKAGE_INFO_DOWNGRADE, -1);
if (!sort_packages (self, packages, cancellable, error))
{
rpmostree_output_task_end ("failed");
return FALSE;
}
rpmostree_output_task_end ("done");
}
rpmostree_output_task_end ("done");
return TRUE;
}
/* Call this to ensure we don't do any "package stuff" like
* depsolving - we're in "pure jigdo" mode. If specified
* this obviously means there are no layered packages for
* example.
*/
gboolean
rpmostree_context_prepare_jigdo (RpmOstreeContext *self,
GCancellable *cancellable,
GError **error)
{
self->jigdo_pure = TRUE;
return rpmostree_context_prepare (self, cancellable, error);
}
/* Rather than doing a depsolve, directly set which packages
* are required. Will be used by jigdo.
*/
@ -1843,15 +1983,6 @@ rpmostree_context_get_packages_to_import (RpmOstreeContext *self)
return g_ptr_array_ref (self->pkgs_to_import);
}
static int
compare_pkgs (gconstpointer ap,
gconstpointer bp)
{
DnfPackage **a = (gpointer)ap;
DnfPackage **b = (gpointer)bp;
return dnf_package_cmp (*a, *b);
}
/* XXX: push this into libdnf */
static const char*
convert_dnf_action_to_string (DnfStateAction action)
@ -2033,6 +2164,23 @@ rpmostree_context_download (RpmOstreeContext *self,
return TRUE;
}
/* Returns: (transfer none): The jigdo package */
DnfPackage *
rpmostree_context_get_jigdo_pkg (RpmOstreeContext *self)
{
g_assert (self->jigdo_spec);
return self->jigdo_pkg;
}
/* Returns: (transfer none): The jigdo checksum */
const char *
rpmostree_context_get_jigdo_checksum (RpmOstreeContext *self)
{
g_assert (self->jigdo_spec);
return self->jigdo_checksum;
}
static inline void
dnf_state_assert_done (DnfState *dnfstate)
{
@ -3023,6 +3171,8 @@ run_all_transfiletriggers (RpmOstreeContext *self,
GCancellable *cancellable,
GError **error)
{
g_assert (!self->jigdo_pure);
/* Triggers from base packages, but only if we already have an rpmdb,
* otherwise librpm will whine on our stderr.
*/

View File

@ -132,6 +132,10 @@ gboolean rpmostree_context_download_metadata (RpmOstreeContext *context,
gboolean rpmostree_context_prepare (RpmOstreeContext *self,
GCancellable *cancellable,
GError **error);
/* Like above, but used for "pure jigdo" cases */
gboolean rpmostree_context_prepare_jigdo (RpmOstreeContext *self,
GCancellable *cancellable,
GError **error);
/* Alternative to _prepare() for non-depsolve cases like jigdo */
gboolean rpmostree_context_set_packages (RpmOstreeContext *self,
@ -151,6 +155,9 @@ rpmostree_context_consume_package (RpmOstreeContext *self,
int *out_fd,
GError **error);
DnfPackage *rpmostree_context_get_jigdo_pkg (RpmOstreeContext *self);
const char *rpmostree_context_get_jigdo_checksum (RpmOstreeContext *self);
gboolean rpmostree_context_import (RpmOstreeContext *self,
GCancellable *cancellable,
GError **error);