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:
parent
879c5afefc
commit
1793480155
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user