From b881f33ba776610d127b8f44e4a5429c458ddfc7 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 17 Jan 2018 10:33:46 -0500 Subject: [PATCH] Add support for `rebase rojig://` This is an initial drop of support for: `rpm-ostree rebase rojig://fahc:fedora-atomic-host`. We also then support `rpm-ostree upgrade` from that. There's a lot that could be improved here; the test coverage is relatively minimal. A blocking issue there is having a realistic jigdo setup, and that's going to require changing how we do testing. For now, this means that if we want to e.g. change the format we'll have to temporarily disable this test, get the format change in, update FAHC, then re-enable the test. Closes: #1166 Approved by: jlebon --- src/app/rpmostree-builtin-rebase.c | 8 + src/daemon/rpmostree-sysroot-core.c | 12 +- src/daemon/rpmostree-sysroot-upgrader.c | 136 +++++++++++----- src/daemon/rpmostreed-deployment-utils.c | 69 ++++---- src/daemon/rpmostreed-os.c | 15 +- src/daemon/rpmostreed-transaction-types.c | 32 +++- src/daemon/rpmostreed-utils.c | 3 +- src/libpriv/rpmostree-origin.c | 184 ++++++++++++++++------ src/libpriv/rpmostree-origin.h | 13 ++ tests/check/test-basic.sh | 4 - tests/vmcheck/test-jigdo-client.sh | 44 ++++++ 11 files changed, 374 insertions(+), 146 deletions(-) create mode 100755 tests/vmcheck/test-jigdo-client.sh diff --git a/src/app/rpmostree-builtin-rebase.c b/src/app/rpmostree-builtin-rebase.c index 05acf527..0f831a43 100644 --- a/src/app/rpmostree-builtin-rebase.c +++ b/src/app/rpmostree-builtin-rebase.c @@ -38,6 +38,7 @@ static char * opt_branch; static char * opt_remote; static gboolean opt_cache_only; static gboolean opt_download_only; +static gboolean opt_experimental; static GOptionEntry option_entries[] = { { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Operate on provided OSNAME", "OSNAME" }, @@ -47,6 +48,7 @@ static GOptionEntry option_entries[] = { { "skip-purge", 0, 0, G_OPTION_ARG_NONE, &opt_skip_purge, "Keep previous refspec after rebase", NULL }, { "cache-only", 'C', 0, G_OPTION_ARG_NONE, &opt_cache_only, "Do not download latest ostree and RPM data", NULL }, { "download-only", 0, 0, G_OPTION_ARG_NONE, &opt_download_only, "Just download latest ostree and RPM data, don't deploy", NULL }, + { "experimental", 0, 0, G_OPTION_ARG_NONE, &opt_experimental, "Enable experimental features", NULL }, { NULL } }; @@ -121,6 +123,12 @@ rpmostree_builtin_rebase (int argc, new_provided_refspec = opt_branch; } + RpmOstreeRefspecType refspectype; + if (!rpmostree_refspec_classify (new_provided_refspec, &refspectype, NULL, error)) + return FALSE; + if (!opt_experimental && refspectype == RPMOSTREE_REFSPEC_TYPE_ROJIG) + return glnx_throw (error, "rojig:// refspec requires --experimental"); + g_autoptr(GVariant) previous_deployment = rpmostree_os_dup_default_deployment (os_proxy); g_autoptr(GVariant) options = rpmostree_get_options_variant (opt_reboot, diff --git a/src/daemon/rpmostree-sysroot-core.c b/src/daemon/rpmostree-sysroot-core.c index 43a7c998..df8fab99 100644 --- a/src/daemon/rpmostree-sysroot-core.c +++ b/src/daemon/rpmostree-sysroot-core.c @@ -190,7 +190,15 @@ clean_pkgcache_orphans (OstreeSysroot *sysroot, NULL, NULL, error)) return FALSE; - if (is_layered) + g_autoptr(RpmOstreeOrigin) origin = rpmostree_origin_parse_deployment (deployment, error); + if (!origin) + return FALSE; + + RpmOstreeRefspecType refspectype; + rpmostree_origin_classify_refspec (origin, &refspectype, NULL); + + /* In rojig mode, we need to also reference all packages */ + if (is_layered || refspectype == RPMOSTREE_REFSPEC_TYPE_ROJIG) { g_autofree char *deployment_dirpath = ostree_sysroot_get_deployment_dirpath (sysroot, deployment); @@ -209,8 +217,6 @@ clean_pkgcache_orphans (OstreeSysroot *sysroot, } /* also add any inactive local replacements */ - g_autoptr(RpmOstreeOrigin) origin = - rpmostree_origin_parse_deployment (deployment, error); GHashTable *local_replace = rpmostree_origin_get_overrides_local_replace (origin); GLNX_HASH_TABLE_FOREACH (local_replace, const char*, nevra) { diff --git a/src/daemon/rpmostree-sysroot-upgrader.c b/src/daemon/rpmostree-sysroot-upgrader.c index 55ad1fa7..b6b62690 100644 --- a/src/daemon/rpmostree-sysroot-upgrader.c +++ b/src/daemon/rpmostree-sysroot-upgrader.c @@ -44,7 +44,7 @@ * The #RpmOstreeSysrootUpgrader class models a `baserefspec` OSTree branch * in an origin file, along with a set of layered RPM packages. * - * It also supports the plain-ostree "refspec" model. + * It also supports the plain-ostree "refspec" model, as well as rojig://. */ typedef struct { GObjectClass parent_class; @@ -374,13 +374,6 @@ rpmostree_sysroot_upgrader_pull_base (RpmOstreeSysrootUpgrader *self, GCancellable *cancellable, GError **error) { - const char *refspec = rpmostree_origin_get_refspec (self->origin); - - g_autofree char *origin_remote = NULL; - g_autofree char *origin_ref = NULL; - if (!ostree_parse_refspec (refspec, &origin_remote, &origin_ref, error)) - return FALSE; - const gboolean allow_older = (self->flags & RPMOSTREE_SYSROOT_UPGRADER_FLAGS_ALLOW_OLDER) > 0; const gboolean synthetic = @@ -388,44 +381,101 @@ rpmostree_sysroot_upgrader_pull_base (RpmOstreeSysrootUpgrader *self, const char *override_commit = rpmostree_origin_get_override_commit (self->origin); - g_assert (self->origin_merge_deployment); - if (origin_remote && !synthetic) - { - g_autoptr(GVariantBuilder) optbuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); - if (dir_to_pull && *dir_to_pull) - g_variant_builder_add (optbuilder, "{s@v}", "subdir", - g_variant_new_variant (g_variant_new_string (dir_to_pull))); - g_variant_builder_add (optbuilder, "{s@v}", "flags", - g_variant_new_variant (g_variant_new_int32 (flags))); - /* Add the timestamp check, unless disabled. The option was added in - * libostree v2017.11 */ - if (!allow_older) - g_variant_builder_add (optbuilder, "{s@v}", "timestamp-check", - g_variant_new_variant (g_variant_new_boolean (TRUE))); - g_variant_builder_add (optbuilder, "{s@v}", "refs", - g_variant_new_variant (g_variant_new_strv ( - (const char *const *)&origin_ref, 1))); - if (override_commit) - g_variant_builder_add (optbuilder, "{s@v}", "override-commit-ids", - g_variant_new_variant (g_variant_new_strv ( - (const char *const *)&override_commit, 1))); - - g_autoptr(GVariant) opts = g_variant_ref_sink (g_variant_builder_end (optbuilder)); - if (!ostree_repo_pull_with_options (self->repo, origin_remote, opts, progress, - cancellable, error)) - return FALSE; - - if (progress) - ostree_async_progress_finish (progress); - } + RpmOstreeRefspecType refspec_type; + const char *refspec; + rpmostree_origin_classify_refspec (self->origin, &refspec_type, &refspec); g_autofree char *new_base_rev = NULL; - if (override_commit) - new_base_rev = g_strdup (override_commit); - else + + switch (refspec_type) { - if (!ostree_repo_resolve_rev (self->repo, refspec, FALSE, &new_base_rev, error)) - return FALSE; + case RPMOSTREE_REFSPEC_TYPE_OSTREE: + { + g_autofree char *origin_remote = NULL; + g_autofree char *origin_ref = NULL; + if (!ostree_parse_refspec (refspec, &origin_remote, &origin_ref, error)) + return FALSE; + + g_assert (self->origin_merge_deployment); + if (origin_remote && !synthetic) + { + g_autoptr(GVariantBuilder) optbuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + if (dir_to_pull && *dir_to_pull) + g_variant_builder_add (optbuilder, "{s@v}", "subdir", + g_variant_new_variant (g_variant_new_string (dir_to_pull))); + g_variant_builder_add (optbuilder, "{s@v}", "flags", + g_variant_new_variant (g_variant_new_int32 (flags))); + /* Add the timestamp check, unless disabled. The option was added in + * libostree v2017.11 */ + if (!allow_older) + g_variant_builder_add (optbuilder, "{s@v}", "timestamp-check", + g_variant_new_variant (g_variant_new_boolean (TRUE))); + g_variant_builder_add (optbuilder, "{s@v}", "refs", + g_variant_new_variant (g_variant_new_strv ( + (const char *const *)&origin_ref, 1))); + if (override_commit) + g_variant_builder_add (optbuilder, "{s@v}", "override-commit-ids", + g_variant_new_variant (g_variant_new_strv ( + (const char *const *)&override_commit, 1))); + + g_autoptr(GVariant) opts = g_variant_ref_sink (g_variant_builder_end (optbuilder)); + if (!ostree_repo_pull_with_options (self->repo, origin_remote, opts, progress, + cancellable, error)) + return FALSE; + + if (progress) + ostree_async_progress_finish (progress); + } + + if (override_commit) + new_base_rev = g_strdup (override_commit); + else + { + if (!ostree_repo_resolve_rev (self->repo, refspec, FALSE, &new_base_rev, error)) + return FALSE; + } + } + break; + case RPMOSTREE_REFSPEC_TYPE_ROJIG: + { + // Not implemented yet, though we could do a query for the provides + g_assert (!override_commit); + + g_autoptr(GKeyFile) tsk = g_key_file_new (); + g_key_file_set_string (tsk, "tree", "jigdo", refspec); + const char *jigdo_version = rpmostree_origin_get_jigdo_version (self->origin); + if (jigdo_version) + g_key_file_set_string (tsk, "tree", "jigdo-version", jigdo_version); + + g_autoptr(RpmOstreeTreespec) treespec = rpmostree_treespec_new_from_keyfile (tsk, error); + if (!treespec) + return FALSE; + + /* This context is currently different from one that may be created later + * for e.g. package layering. I can't think why we couldn't unify them, + * but for now it seems a lot simpler to keep the symmetry that + * rpm-ostree jigdo == ostree pull. + */ + g_autoptr(RpmOstreeContext) ctx = + rpmostree_context_new_system (self->repo, cancellable, error); + if (!ctx) + return FALSE; + + /* We use / as a source root mostly so we get $releasever from it so + * things work out of the box. That said this is kind of wrong and we'll + * really need a way for users to configure a different releasever when + * e.g. rebasing across majors. + */ + if (!rpmostree_context_setup (ctx, NULL, "/", treespec, cancellable, error)) + return FALSE; + /* We're also "pure" rpm-ostree jigdo - this adds assertions that we don't depsolve for example */ + if (!rpmostree_context_prepare_jigdo (ctx, cancellable, error)) + return FALSE; + new_base_rev = g_strdup (rpmostree_context_get_jigdo_checksum (ctx)); + gboolean jigdo_changed; /* Currently unused */ + if (!rpmostree_context_execute_jigdo (ctx, &jigdo_changed, cancellable, error)) + return FALSE; + } } gboolean changed = !g_str_equal (new_base_rev, self->base_revision); diff --git a/src/daemon/rpmostreed-deployment-utils.c b/src/daemon/rpmostreed-deployment-utils.c index f7f509ca..38b438f9 100644 --- a/src/daemon/rpmostreed-deployment-utils.c +++ b/src/daemon/rpmostreed-deployment-utils.c @@ -24,6 +24,7 @@ #include "rpmostree-types.h" #include "rpmostreed-deployment-utils.h" #include "rpmostree-origin.h" +#include "rpmostree-core.h" #include "rpmostree-util.h" #include "rpmostree-rpm-util.h" #include "rpmostree-sysroot-core.h" @@ -245,7 +246,8 @@ rpmostreed_deployment_generate_variant (OstreeSysroot *sysroot, if (!origin) return NULL; - const char *refspec = rpmostree_origin_get_refspec (origin); + RpmOstreeRefspecType refspec_type; + g_autofree char *refspec = rpmostree_origin_get_full_refspec (origin, &refspec_type); GVariantDict dict; g_variant_dict_init (&dict, NULL); @@ -295,31 +297,32 @@ rpmostreed_deployment_generate_variant (OstreeSysroot *sysroot, { g_autoptr(GVariant) base_meta = g_variant_get_child_value (commit, 0); g_variant_dict_insert (&dict, "base-commit-meta", "@a{sv}", base_meta); } + variant_add_commit_details (&dict, NULL, commit); gboolean gpg_enabled = FALSE; g_autoptr(GVariant) sigs = NULL; - if (!rpmostreed_deployment_gpg_results (repo, refspec, base_checksum, &sigs, &gpg_enabled, error)) - return NULL; - variant_add_commit_details (&dict, NULL, commit); - - g_autofree char *pending_base_commitrev = NULL; - if (!ostree_repo_resolve_rev (repo, refspec, TRUE, - &pending_base_commitrev, error)) - return NULL; - - if (pending_base_commitrev && strcmp (pending_base_commitrev, base_checksum) != 0) + if (refspec_type == RPMOSTREE_REFSPEC_TYPE_OSTREE) { - g_autoptr(GVariant) pending_base_commit = NULL; - - if (!ostree_repo_load_variant (repo, - OSTREE_OBJECT_TYPE_COMMIT, - pending_base_commitrev, - &pending_base_commit, - error)) + if (!rpmostreed_deployment_gpg_results (repo, refspec, base_checksum, &sigs, &gpg_enabled, error)) return NULL; - g_variant_dict_insert (&dict, "pending-base-checksum", "s", pending_base_commitrev); - variant_add_commit_details (&dict, "pending-base-", pending_base_commit); + g_autofree char *pending_base_commitrev = NULL; + if (!ostree_repo_resolve_rev (repo, refspec, TRUE, + &pending_base_commitrev, error)) + return NULL; + + if (pending_base_commitrev && !g_str_equal (pending_base_commitrev, base_checksum)) + { + g_autoptr(GVariant) pending_base_commit = NULL; + + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + pending_base_commitrev, &pending_base_commit, + error)) + return NULL; + + g_variant_dict_insert (&dict, "pending-base-checksum", "s", pending_base_commitrev); + variant_add_commit_details (&dict, "pending-base-", pending_base_commit); + } } g_autofree char *live_inprogress = NULL; @@ -333,7 +336,8 @@ rpmostreed_deployment_generate_variant (OstreeSysroot *sysroot, if (live_replaced) g_variant_dict_insert (&dict, "live-replaced", "s", live_replaced); - g_variant_dict_insert (&dict, "origin", "s", refspec); + if (refspec) + g_variant_dict_insert (&dict, "origin", "s", refspec); variant_add_from_hash_table (&dict, "requested-packages", rpmostree_origin_get_packages (origin)); @@ -380,13 +384,16 @@ add_all_commit_details_to_vardict (OstreeDeployment *deployment, const gchar *osname = ostree_deployment_get_osname (deployment); g_autofree gchar *refspec_owned = NULL; + gboolean refspec_is_ostree = FALSE; if (!refspec) { g_autoptr(RpmOstreeOrigin) origin = rpmostree_origin_parse_deployment (deployment, error); if (!origin) return FALSE; - refspec = refspec_owned = g_strdup (rpmostree_origin_get_refspec (origin)); + RpmOstreeRefspecType refspec_type; + refspec = refspec_owned = rpmostree_origin_get_full_refspec (origin, &refspec_type); + refspec_is_ostree = (refspec_type == RPMOSTREE_REFSPEC_TYPE_OSTREE); } g_assert (refspec); @@ -395,8 +402,11 @@ add_all_commit_details_to_vardict (OstreeDeployment *deployment, g_autofree gchar *checksum_owned = NULL; if (!checksum) { - if (!ostree_repo_resolve_rev (repo, refspec, TRUE, &checksum_owned, error)) - return FALSE; + if (refspec_is_ostree) + { + if (!ostree_repo_resolve_rev (repo, refspec, TRUE, &checksum_owned, error)) + return FALSE; + } /* in that case, use deployment csum */ checksum = checksum_owned ?: ostree_deployment_get_csum (deployment); @@ -411,11 +421,14 @@ add_all_commit_details_to_vardict (OstreeDeployment *deployment, commit = commit_owned; } - gboolean gpg_enabled; + gboolean gpg_enabled = FALSE; g_autoptr(GVariant) sigs = NULL; - if (!rpmostreed_deployment_gpg_results (repo, refspec, checksum, - &sigs, &gpg_enabled, error)) - return FALSE; + if (refspec_is_ostree) + { + if (!rpmostreed_deployment_gpg_results (repo, refspec, checksum, + &sigs, &gpg_enabled, error)) + return FALSE; + } if (osname != NULL) g_variant_dict_insert (dict, "osname", "s", osname); diff --git a/src/daemon/rpmostreed-os.c b/src/daemon/rpmostreed-os.c index f32d3df4..7785eee2 100644 --- a/src/daemon/rpmostreed-os.c +++ b/src/daemon/rpmostreed-os.c @@ -686,18 +686,9 @@ start_deployment_txn (GDBusMethodInvocation *invocation, g_autofree char *canon_refspec = NULL; if (refspec) { - RpmOstreeRefspecType refspectype; - const char *refspecdata; - if (!rpmostree_refspec_classify (refspec, &refspectype, &refspecdata, error)) - return NULL; - switch (refspectype) - { - case RPMOSTREE_REFSPEC_TYPE_OSTREE: - break; - case RPMOSTREE_REFSPEC_TYPE_ROJIG: - return glnx_null_throw (error, "Unsupported refspec: %s", refspec); - } - canon_refspec = rpmostree_refspec_to_string (refspectype, refspecdata); + canon_refspec = rpmostree_refspec_canonicalize (refspec, error); + if (!canon_refspec) + return FALSE; } default_flags = deploy_flags_from_options (options, default_flags); diff --git a/src/daemon/rpmostreed-transaction-types.c b/src/daemon/rpmostreed-transaction-types.c index 2cbf6a0b..e8e070b0 100644 --- a/src/daemon/rpmostreed-transaction-types.c +++ b/src/daemon/rpmostreed-transaction-types.c @@ -48,8 +48,35 @@ change_origin_refspec (OstreeSysroot *sysroot, const char *refspecdata; if (!rpmostree_refspec_classify (src_refspec, &refspectype, &refspecdata, error)) return FALSE; - /* Should have been canonicalized earlier */ - g_assert_cmpint (refspectype, ==, RPMOSTREE_REFSPEC_TYPE_OSTREE); + + RpmOstreeRefspecType current_refspectype; + const char *current_refspecdata; + rpmostree_origin_classify_refspec (origin, ¤t_refspectype, ¤t_refspecdata); + + /* This function ideally would be split into ostree/rojig handling + * and we'd also do "partial" support for rojig so one could do e.g. + * `rpm-ostree rebase fedora-atomic-workstation` instead of + * `rpm-ostree rebase updates:fedora-atomic-workstation` etc. + */ + switch (refspectype) + { + case RPMOSTREE_REFSPEC_TYPE_ROJIG: + { + if (!rpmostree_origin_set_rebase (origin, src_refspec, error)) + return FALSE; + + if (current_refspectype == RPMOSTREE_REFSPEC_TYPE_ROJIG + && strcmp (current_refspecdata, refspecdata) == 0) + return glnx_throw (error, "Old and new refs are equal: %s", src_refspec); + + if (out_old_refspec != NULL) + *out_old_refspec = g_strdup (current_refspecdata); + *out_new_refspec = g_strdup (src_refspec); + return TRUE; + } + case RPMOSTREE_REFSPEC_TYPE_OSTREE: + break; + } /* Now here we "peel" it since the rest of the code assumes libostree */ const char *refspec = refspecdata; @@ -57,6 +84,7 @@ change_origin_refspec (OstreeSysroot *sysroot, g_autofree gchar *current_refspec = g_strdup (rpmostree_origin_get_refspec (origin)); g_autofree gchar *new_refspec = NULL; + if (!rpmostreed_refspec_parse_partial (refspec, current_refspec, &new_refspec, diff --git a/src/daemon/rpmostreed-utils.c b/src/daemon/rpmostreed-utils.c index ace67cb6..934b7085 100644 --- a/src/daemon/rpmostreed-utils.c +++ b/src/daemon/rpmostreed-utils.c @@ -136,10 +136,9 @@ rpmostreed_refspec_parse_partial (const gchar *new_provided_refspec, gchar **out_refspec, GError **error) { - g_autofree gchar *ref = NULL; g_autofree gchar *remote = NULL; - gboolean infer_remote = TRUE;; + gboolean infer_remote = TRUE; /* Allow just switching remotes */ if (g_str_has_suffix (new_provided_refspec, ":")) diff --git a/src/libpriv/rpmostree-origin.c b/src/libpriv/rpmostree-origin.c index df229ce6..764df615 100644 --- a/src/libpriv/rpmostree-origin.c +++ b/src/libpriv/rpmostree-origin.c @@ -24,6 +24,7 @@ #include "libglnx.h" #include "rpmostree-origin.h" +#include "rpmostree-core.h" #include "rpmostree-util.h" struct RpmOstreeOrigin { @@ -32,8 +33,14 @@ struct RpmOstreeOrigin { /* this is the single source of truth */ GKeyFile *kf; + /* An origin can have either a refspec or a jigdospec */ + RpmOstreeRefspecType refspec_type; char *cached_refspec; + + /* Version data that goes along with the refspec */ char *cached_override_commit; + char *cached_jigdo_version; + char *cached_unconfigured_state; char **cached_initramfs_args; GHashTable *cached_packages; /* set of reldeps */ @@ -107,32 +114,50 @@ rpmostree_origin_parse_keyfile (GKeyFile *origin, ret->cached_unconfigured_state = g_key_file_get_string (ret->kf, "origin", "unconfigured-state", NULL); - ret->cached_refspec = g_key_file_get_string (ret->kf, "origin", "refspec", NULL); - if (!ret->cached_refspec) + g_autofree char *refspec = g_key_file_get_string (ret->kf, "origin", "refspec", NULL); + g_autofree char *jigdo_spec = g_key_file_get_string (ret->kf, "origin", "rojig", NULL); + if (!refspec) { - ret->cached_refspec = g_key_file_get_string (ret->kf, "origin", "baserefspec", NULL); - if (!ret->cached_refspec) - return glnx_null_throw (error, "No origin/refspec or origin/baserefspec in current deployment origin; cannot handle via rpm-ostree"); - - if (!parse_packages_strv (ret->kf, "packages", "requested", FALSE, - ret->cached_packages, error)) - return FALSE; - - if (!parse_packages_strv (ret->kf, "packages", "requested-local", TRUE, - ret->cached_local_packages, error)) - return FALSE; - - if (!parse_packages_strv (ret->kf, "overrides", "remove", FALSE, - ret->cached_overrides_remove, error)) - return FALSE; - - if (!parse_packages_strv (ret->kf, "overrides", "replace-local", TRUE, - ret->cached_overrides_local_replace, error)) - return FALSE; + refspec = g_key_file_get_string (ret->kf, "origin", "baserefspec", NULL); + if (!refspec && !jigdo_spec) + return glnx_null_throw (error, "No origin/refspec, origin/rojig, or origin/baserefspec in current deployment origin; cannot handle via rpm-ostree"); + } + if (refspec && jigdo_spec) + return glnx_null_throw (error, "Duplicate origin/refspec and origin/rojig in deployment origin"); + else if (refspec) + { + ret->refspec_type = RPMOSTREE_REFSPEC_TYPE_OSTREE; + /* Note the lack of a prefix here so that code that just calls + * rpmostree_origin_get_refspec() in the ostree:// case + * sees it without the prefix for compatibility. + */ + ret->cached_refspec = g_steal_pointer (&refspec); + ret->cached_override_commit = + g_key_file_get_string (ret->kf, "origin", "override-commit", NULL); + } + else + { + g_assert (jigdo_spec); + ret->refspec_type = RPMOSTREE_REFSPEC_TYPE_ROJIG; + ret->cached_refspec = g_steal_pointer (&jigdo_spec); + ret->cached_jigdo_version = g_key_file_get_string (ret->kf, "origin", "jigdo-version", NULL); } - ret->cached_override_commit = - g_key_file_get_string (ret->kf, "origin", "override-commit", NULL); + if (!parse_packages_strv (ret->kf, "packages", "requested", FALSE, + ret->cached_packages, error)) + return FALSE; + + if (!parse_packages_strv (ret->kf, "packages", "requested-local", TRUE, + ret->cached_local_packages, error)) + return FALSE; + + if (!parse_packages_strv (ret->kf, "overrides", "remove", FALSE, + ret->cached_overrides_remove, error)) + return FALSE; + + if (!parse_packages_strv (ret->kf, "overrides", "replace-local", TRUE, + ret->cached_overrides_local_replace, error)) + return FALSE; ret->cached_initramfs_args = g_key_file_get_string_list (ret->kf, "rpmostree", "initramfs-args", NULL, NULL); @@ -143,7 +168,10 @@ rpmostree_origin_parse_keyfile (GKeyFile *origin, RpmOstreeOrigin * rpmostree_origin_dup (RpmOstreeOrigin *origin) { - return rpmostree_origin_parse_keyfile (origin->kf, NULL); + g_autoptr(GError) local_error = NULL; + RpmOstreeOrigin *ret = rpmostree_origin_parse_keyfile (origin->kf, &local_error); + g_assert_no_error (local_error); + return ret; } const char * @@ -152,6 +180,40 @@ rpmostree_origin_get_refspec (RpmOstreeOrigin *origin) return origin->cached_refspec; } +/* For rojig:// refspecs, includes the prefix. */ +char * +rpmostree_origin_get_full_refspec (RpmOstreeOrigin *origin, + RpmOstreeRefspecType *out_refspectype) +{ + if (out_refspectype) + *out_refspectype = origin->refspec_type; + switch (origin->refspec_type) + { + case RPMOSTREE_REFSPEC_TYPE_OSTREE: + return g_strdup (origin->cached_refspec); + case RPMOSTREE_REFSPEC_TYPE_ROJIG: + return g_strconcat (RPMOSTREE_REFSPEC_ROJIG_PREFIX, origin->cached_refspec, NULL); + } + g_assert_not_reached (); + return NULL; +} + +void +rpmostree_origin_classify_refspec (RpmOstreeOrigin *origin, + RpmOstreeRefspecType *out_type, + const char **out_refspecdata) +{ + *out_type = origin->refspec_type; + if (out_refspecdata) + *out_refspecdata = origin->cached_refspec; +} + +const char * +rpmostree_origin_get_jigdo_version (RpmOstreeOrigin *origin) +{ + return origin->cached_jigdo_version; +} + GHashTable * rpmostree_origin_get_packages (RpmOstreeOrigin *origin) { @@ -256,6 +318,7 @@ rpmostree_origin_unref (RpmOstreeOrigin *origin) return; g_key_file_unref (origin->kf); g_free (origin->cached_refspec); + g_free (origin->cached_jigdo_version); g_free (origin->cached_unconfigured_state); g_strfreev (origin->cached_initramfs_args); g_clear_pointer (&origin->cached_packages, g_hash_table_unref); @@ -325,38 +388,44 @@ rpmostree_origin_set_override_commit (RpmOstreeOrigin *origin, origin->cached_override_commit = g_strdup (checksum); } -/* updates an origin's refspec without migrating format */ -static gboolean -origin_set_refspec (GKeyFile *origin, - const char *new_refspec, - GError **error) -{ - if (g_key_file_has_key (origin, "origin", "baserefspec", error)) - { - g_key_file_set_value (origin, "origin", "baserefspec", new_refspec); - return TRUE; - } - - if (error && *error) - return FALSE; - - g_key_file_set_value (origin, "origin", "refspec", new_refspec); - return TRUE; -} - gboolean rpmostree_origin_set_rebase (RpmOstreeOrigin *origin, const char *new_refspec, GError **error) { - if (!origin_set_refspec (origin->kf, new_refspec, error)) - return FALSE; - - /* we don't want to carry any commit overrides during a rebase */ + /* We don't want to carry any commit overrides or version pinning during a + * rebase by default. + */ rpmostree_origin_set_override_commit (origin, NULL, NULL); + g_key_file_remove_key (origin->kf, "origin", "jigdo-version", NULL); + /* See related code in rpmostree_origin_parse_keyfile() */ + const char *refspecdata; + if (!rpmostree_refspec_classify (new_refspec, &origin->refspec_type, &refspecdata, error)) + return FALSE; g_free (origin->cached_refspec); - origin->cached_refspec = g_strdup (new_refspec); + origin->cached_refspec = g_strdup (refspecdata); + switch (origin->refspec_type) + { + case RPMOSTREE_REFSPEC_TYPE_OSTREE: + { + g_key_file_remove_key (origin->kf, "origin", "rojig", NULL); + const char *refspec_key = + g_key_file_has_key (origin->kf, "origin", "baserefspec", NULL) ? + "baserefspec" : "refspec"; + g_key_file_set_string (origin->kf, "origin", refspec_key, origin->cached_refspec); + } + break; + case RPMOSTREE_REFSPEC_TYPE_ROJIG: + { + origin->cached_refspec = g_strdup (refspecdata); + g_key_file_remove_key (origin->kf, "origin", "refspec", NULL); + g_key_file_remove_key (origin->kf, "origin", "baserefspec", NULL); + /* Peeled */ + g_key_file_set_string (origin->kf, "origin", "rojig", origin->cached_refspec); + } + break; + } return TRUE; } @@ -425,10 +494,21 @@ update_keyfile_pkgs_from_cache (RpmOstreeOrigin *origin, if (g_hash_table_size (pkgs) > 0) { - /* migrate to baserefspec model */ - g_key_file_set_value (origin->kf, "origin", "baserefspec", - origin->cached_refspec); - g_key_file_remove_key (origin->kf, "origin", "refspec", NULL); + switch (origin->refspec_type) + { + case RPMOSTREE_REFSPEC_TYPE_OSTREE: + { + g_key_file_set_value (origin->kf, "origin", "baserefspec", + origin->cached_refspec); + g_key_file_remove_key (origin->kf, "origin", "refspec", NULL); + break; + } + case RPMOSTREE_REFSPEC_TYPE_ROJIG: + /* Nothing to switch, since libostree already doesn't know how to + * handle rojig. + */ + break; + } } } diff --git a/src/libpriv/rpmostree-origin.h b/src/libpriv/rpmostree-origin.h index b18150fa..c09e3359 100644 --- a/src/libpriv/rpmostree-origin.h +++ b/src/libpriv/rpmostree-origin.h @@ -21,6 +21,7 @@ #pragma once #include +#include "rpmostree-core.h" typedef struct RpmOstreeOrigin RpmOstreeOrigin; RpmOstreeOrigin *rpmostree_origin_ref (RpmOstreeOrigin *origin); @@ -54,6 +55,18 @@ rpmostree_origin_dup (RpmOstreeOrigin *origin); const char * rpmostree_origin_get_refspec (RpmOstreeOrigin *origin); +void +rpmostree_origin_classify_refspec (RpmOstreeOrigin *origin, + RpmOstreeRefspecType *out_type, + const char **out_refspecdata); + +char * +rpmostree_origin_get_full_refspec (RpmOstreeOrigin *origin, + RpmOstreeRefspecType *out_refspectype); + +const char * +rpmostree_origin_get_jigdo_version (RpmOstreeOrigin *origin); + GHashTable * rpmostree_origin_get_packages (RpmOstreeOrigin *origin); diff --git a/tests/check/test-basic.sh b/tests/check/test-basic.sh index 01fa57b7..77f25e11 100755 --- a/tests/check/test-basic.sh +++ b/tests/check/test-basic.sh @@ -180,10 +180,6 @@ echo "ok rebase new syntax" rpm-ostree rebase --skip-purge --os=testos ostree://testos:testos/buildmaster/x86_64-runtime assert_status_jq '.deployments[0].origin == "testos:testos/buildmaster/x86_64-runtime"' -if rpm-ostree rebase --skip-purge --os=testos rojig://testos:testos/buildmaster/x86_64-runtime 2>err.txt; then - fatal "rebase rojig worked?" -fi -assert_file_has_content_literal err.txt 'error: Unsupported refspec: rojig://' echo "ok rebase refspec syntax" rpm-ostree rebase --os=testos :another-branch diff --git a/tests/vmcheck/test-jigdo-client.sh b/tests/vmcheck/test-jigdo-client.sh new file mode 100755 index 00000000..5732d6f1 --- /dev/null +++ b/tests/vmcheck/test-jigdo-client.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# +# Copyright (C) 2018 Red Hat, Inc. +# +# This library 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 License, 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. + +set -euo pipefail + +. ${commondir}/libtest.sh +. ${commondir}/libvm.sh + +set -x + +# Test rebasing to https://pagure.io/fedora-atomic-host-continuous +# in rojig:// mode. + +vm_cmd 'cat >/etc/yum.repos.d/fahc.repo' <err.txt; then + fatal "Did rojig rebase without --experimental" +fi +assert_file_has_content_literal err.txt 'rojig:// refspec requires --experimental' +vm_rpmostree rebase --experimental rojig://fahc:fedora-atomic-host +vm_assert_status_jq '.deployments[0].origin|startswith("rojig://fahc:fedora-atomic-host")' +vm_cmd ostree refs > refs.txt +assert_file_has_content refs.txt '^rpmostree/pkg/kernel-core/' +echo "ok jigdo client"