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; 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 static int
compare_pkgs (gconstpointer ap, compare_pkgs (gconstpointer ap,
gconstpointer bp) gconstpointer bp)
@ -161,23 +152,15 @@ compare_pkgs (gconstpointer ap,
static gboolean static gboolean
impl_jigdo2commit (RpmOstreeJigdo2CommitContext *self, impl_jigdo2commit (RpmOstreeJigdo2CommitContext *self,
const char *repoid_and_oirpm_name, const char *jigdo_id,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) 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_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) if (opt_releasever)
g_key_file_set_string (tsk, "tree", "releasever", opt_releasever); g_key_file_set_string (tsk, "tree", "releasever", opt_releasever);
if (opt_enable_rpmmdrepo) if (opt_enable_rpmmdrepo)
@ -188,67 +171,16 @@ impl_jigdo2commit (RpmOstreeJigdo2CommitContext *self,
if (!treespec) if (!treespec)
return FALSE; 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)) if (!rpmostree_context_setup (self->ctx, NULL, NULL, treespec, cancellable, error))
return FALSE; return FALSE;
if (!rpmostree_context_download_metadata (self->ctx, cancellable, error)) if (!rpmostree_context_prepare_jigdo (self->ctx, cancellable, error))
return FALSE; 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); 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), g_print ("oirpm: %s (%s) commit=%s\n", dnf_package_get_nevra (oirpm_pkg),
dnf_package_get_reponame (oirpm_pkg), provided_commit); dnf_package_get_reponame (oirpm_pkg), provided_commit);

View File

@ -33,6 +33,7 @@
#include <librepo/librepo.h> #include <librepo/librepo.h>
#include "rpmostree-core.h" #include "rpmostree-core.h"
#include "rpmostree-jigdo-core.h"
#include "rpmostree-postprocess.h" #include "rpmostree-postprocess.h"
#include "rpmostree-rpm-util.h" #include "rpmostree-rpm-util.h"
#include "rpmostree-passwd-util.h" #include "rpmostree-passwd-util.h"
@ -51,6 +52,15 @@
static OstreeRepo * get_pkgcache_repo (RpmOstreeContext *self); 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 * * RpmOstreeTreespec *
*********************************************************** ***********************************************************
@ -170,6 +180,12 @@ rpmostree_treespec_new_from_keyfile (GKeyFile *keyfile,
g_variant_builder_add (&builder, "{sv}", "ref", g_variant_new_string (ref)); 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, "packages", NULL, keyfile);
add_canonicalized_string_array (&builder, "cached-packages", NULL, keyfile); add_canonicalized_string_array (&builder, "cached-packages", NULL, keyfile);
add_canonicalized_string_array (&builder, "removed-base-packages", NULL, keyfile); add_canonicalized_string_array (&builder, "removed-base-packages", NULL, keyfile);
@ -243,6 +259,14 @@ struct _RpmOstreeContext {
RpmOstreeTreespec *spec; RpmOstreeTreespec *spec;
gboolean empty; 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; gboolean pkgcache_only;
DnfContext *dnfctx; DnfContext *dnfctx;
OstreeRepo *ostreerepo; OstreeRepo *ostreerepo;
@ -281,6 +305,9 @@ rpmostree_context_finalize (GObject *object)
g_clear_object (&rctx->spec); g_clear_object (&rctx->spec);
g_clear_object (&rctx->dnfctx); 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->pkgcache_repo);
g_clear_object (&rctx->ostreerepo); g_clear_object (&rctx->ostreerepo);
g_clear_pointer (&rctx->devino_cache, (GDestroyNotify)ostree_repo_devino_cache_unref); 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"); 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 /* 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 * 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. * rpm-ostree we're being more strict about requiring repos.
@ -1699,6 +1731,79 @@ add_remaining_pkgcache_pkgs (RpmOstreeContext *self,
return TRUE; 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 */ /* Check for/download new rpm-md, then depsolve */
gboolean gboolean
rpmostree_context_prepare (RpmOstreeContext *self, rpmostree_context_prepare (RpmOstreeContext *self,
@ -1731,13 +1836,20 @@ rpmostree_context_prepare (RpmOstreeContext *self,
return FALSE; 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 */ /* Handle packages to remove */
g_autoptr(GPtrArray) removed_pkgnames = g_ptr_array_new (); g_autoptr(GPtrArray) removed_pkgnames = g_ptr_array_new ();
for (char **it = removed_base_pkgnames; it && *it; it++) for (char **it = removed_base_pkgnames; it && *it; it++)
{ {
const char *pkgname = *it; const char *pkgname = *it;
g_assert (!self->jigdo_pure);
if (!dnf_context_remove (dnfctx, pkgname, error)) if (!dnf_context_remove (dnfctx, pkgname, error))
return FALSE; return FALSE;
@ -1756,6 +1868,7 @@ rpmostree_context_prepare (RpmOstreeContext *self,
if (!rpmostree_decompose_sha256_nevra (&nevra, &sha256, error)) if (!rpmostree_decompose_sha256_nevra (&nevra, &sha256, error))
return FALSE; return FALSE;
g_assert (!self->jigdo_pure);
if (!install_pkg_from_cache (self, nevra, sha256, cancellable, error)) if (!install_pkg_from_cache (self, nevra, sha256, cancellable, error))
return FALSE; return FALSE;
@ -1771,6 +1884,7 @@ rpmostree_context_prepare (RpmOstreeContext *self,
if (!rpmostree_decompose_sha256_nevra (&nevra, &sha256, error)) if (!rpmostree_decompose_sha256_nevra (&nevra, &sha256, error))
return FALSE; return FALSE;
g_assert (!self->jigdo_pure);
if (!install_pkg_from_cache (self, nevra, sha256, cancellable, error)) if (!install_pkg_from_cache (self, nevra, sha256, cancellable, error))
return FALSE; return FALSE;
@ -1791,10 +1905,21 @@ rpmostree_context_prepare (RpmOstreeContext *self,
for (char **it = pkgnames; it && *it; it++) for (char **it = pkgnames; it && *it; it++)
{ {
const char *pkgname = *it; const char *pkgname = *it;
g_assert (!self->jigdo_pure);
if (!dnf_context_install (dnfctx, pkgname, error)) if (!dnf_context_install (dnfctx, pkgname, error))
return FALSE; return FALSE;
} }
if (self->jigdo_spec)
{
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"); rpmostree_output_task_begin ("Resolving dependencies");
/* XXX: consider a --allow-uninstall switch? */ /* XXX: consider a --allow-uninstall switch? */
@ -1813,11 +1938,26 @@ rpmostree_context_prepare (RpmOstreeContext *self,
rpmostree_output_task_end ("failed"); rpmostree_output_task_end ("failed");
return FALSE; return FALSE;
} }
rpmostree_output_task_end ("done"); rpmostree_output_task_end ("done");
}
return TRUE; 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 /* Rather than doing a depsolve, directly set which packages
* are required. Will be used by jigdo. * 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); 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 */ /* XXX: push this into libdnf */
static const char* static const char*
convert_dnf_action_to_string (DnfStateAction action) convert_dnf_action_to_string (DnfStateAction action)
@ -2033,6 +2164,23 @@ rpmostree_context_download (RpmOstreeContext *self,
return TRUE; 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 static inline void
dnf_state_assert_done (DnfState *dnfstate) dnf_state_assert_done (DnfState *dnfstate)
{ {
@ -3023,6 +3171,8 @@ run_all_transfiletriggers (RpmOstreeContext *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
g_assert (!self->jigdo_pure);
/* Triggers from base packages, but only if we already have an rpmdb, /* Triggers from base packages, but only if we already have an rpmdb,
* otherwise librpm will whine on our stderr. * 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, gboolean rpmostree_context_prepare (RpmOstreeContext *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); 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 */ /* Alternative to _prepare() for non-depsolve cases like jigdo */
gboolean rpmostree_context_set_packages (RpmOstreeContext *self, gboolean rpmostree_context_set_packages (RpmOstreeContext *self,
@ -151,6 +155,9 @@ rpmostree_context_consume_package (RpmOstreeContext *self,
int *out_fd, int *out_fd,
GError **error); 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, gboolean rpmostree_context_import (RpmOstreeContext *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);