From d9c4031e7ad7bbcabdfa245669de2e12025acda0 Mon Sep 17 00:00:00 2001 From: Evan Goode Date: Mon, 10 Mar 2025 16:01:56 -0400 Subject: [PATCH] Support releasever_{major,minor}, shell-style substitution Resolves: RHEL-74025 --- ...-to-releasever_major-and-releasever_.patch | 156 ++++++++++++++++++ ...easever_major-releasever_minor-from-.patch | 147 +++++++++++++++++ ...ever_-major-minor-from-context-inste.patch | 121 ++++++++++++++ ...rt-shell-style-variable-substitution.patch | 60 +++++++ ...est-shell-style-variable-expressions.patch | 80 +++++++++ libdnf.spec | 10 +- 6 files changed, 573 insertions(+), 1 deletion(-) create mode 100644 0009-Split-releasever-to-releasever_major-and-releasever_.patch create mode 100644 0010-C-API-Detect-releasever_major-releasever_minor-from-.patch create mode 100644 0011-C-API-Use-releasever_-major-minor-from-context-inste.patch create mode 100644 0012-C-API-support-shell-style-variable-substitution.patch create mode 100644 0013-C-API-test-shell-style-variable-expressions.patch diff --git a/0009-Split-releasever-to-releasever_major-and-releasever_.patch b/0009-Split-releasever-to-releasever_major-and-releasever_.patch new file mode 100644 index 0000000..2b6cd1b --- /dev/null +++ b/0009-Split-releasever-to-releasever_major-and-releasever_.patch @@ -0,0 +1,156 @@ +From 9701b99ef3b3019dcef1bd929ffc758ceeb4aae3 Mon Sep 17 00:00:00 2001 +From: Diego Herrera +Date: Thu, 16 Jan 2025 18:29:40 -0300 +Subject: [PATCH 1/5] Split $releasever to $releasever_major and + $releasever_minor in c api + +--- + libdnf/dnf-repo.cpp | 6 ++++- + libdnf/dnf-utils.cpp | 44 ++++++++++++++++++++++++++++++++++++ + libdnf/dnf-utils.h | 3 +++ + tests/libdnf/dnf-self-test.c | 27 ++++++++++++++++++++++ + 4 files changed, 79 insertions(+), 1 deletion(-) + +diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp +index ca3d1920..49da175f 100644 +--- a/libdnf/dnf-repo.cpp ++++ b/libdnf/dnf-repo.cpp +@@ -1194,6 +1194,8 @@ dnf_repo_setup(DnfRepo *repo, GError **error) try + DnfRepoEnabled enabled = DNF_REPO_ENABLED_NONE; + g_autofree gchar *basearch = NULL; + g_autofree gchar *release = NULL; ++ g_autofree gchar *major = NULL; ++ g_autofree gchar *minor = NULL; + + basearch = g_key_file_get_string(priv->keyfile, "general", "arch", NULL); + if (basearch == NULL) +@@ -1221,9 +1223,11 @@ dnf_repo_setup(DnfRepo *repo, GError **error) try + return FALSE; + if (!lr_handle_setopt(priv->repo_handle, error, LRO_INTERRUPTIBLE, 0L)) + return FALSE; ++ dnf_split_releasever(release, &major, &minor); + priv->urlvars = lr_urlvars_set(priv->urlvars, "releasever", release); ++ priv->urlvars = lr_urlvars_set(priv->urlvars, "releasever_major", major); ++ priv->urlvars = lr_urlvars_set(priv->urlvars, "releasever_minor", minor); + priv->urlvars = lr_urlvars_set(priv->urlvars, "basearch", basearch); +- + /* Call libdnf::dnf_context_load_vars(priv->context); only when values not in cache. + * But what about if variables on disk change during long running programs (PackageKit daemon)? + * if (!libdnf::dnf_context_get_vars_cached(priv->context)) +diff --git a/libdnf/dnf-utils.cpp b/libdnf/dnf-utils.cpp +index 874282cf..43c84b82 100644 +--- a/libdnf/dnf-utils.cpp ++++ b/libdnf/dnf-utils.cpp +@@ -84,6 +84,50 @@ dnf_realpath(const gchar *path) + return real; + } + ++/** ++ * dnf_split_releasever: ++ * @releasever: A releasever string ++ * @releasever_major: Output string, or %NULL ++ * @releasever_minor: Output string, or %NULL ++ * ++ * Splits a releasever string into mayor and minor ++ * using the same logic as DNF 5 and as splitReleaseverTo in libzypp. ++ **/ ++void ++dnf_split_releasever(const gchar *releasever, ++ gchar **releasever_major, ++ gchar **releasever_minor) ++{ ++ g_autofree gchar** result = NULL; ++ ++ // Uses the same logic as DNF 5 and as splitReleaseverTo in libzypp ++ result = g_strsplit(releasever, ".", 2); ++ ++ if(result[0] == NULL) { ++ if(releasever_major != NULL) ++ *releasever_major = g_strdup(""); ++ if(releasever_minor != NULL) ++ *releasever_minor = g_strdup(""); ++ return; ++ } ++ else { ++ if(releasever_major != NULL) ++ *releasever_major = result[0]; ++ else ++ g_free(result[0]); ++ } ++ ++ if(result[1] == NULL) { ++ if(releasever_minor != NULL) ++ *releasever_minor = g_strdup(""); ++ } else { ++ if(releasever_minor != NULL) ++ *releasever_minor = result[1]; ++ else ++ g_free(result[1]); ++ } ++} ++ + /** + * dnf_remove_recursive: + * @directory: A directory path +diff --git a/libdnf/dnf-utils.h b/libdnf/dnf-utils.h +index 6b711918..c10dd53f 100644 +--- a/libdnf/dnf-utils.h ++++ b/libdnf/dnf-utils.h +@@ -53,6 +53,9 @@ extern "C" { + #endif + + gchar *dnf_realpath (const gchar *path); ++void dnf_split_releasever (const gchar *releasever, ++ gchar **releasever_major, ++ gchar **releasever_minor); + gboolean dnf_remove_recursive (const gchar *directory, + GError **error); + gboolean dnf_ensure_file_unlinked (const gchar *src_path, +diff --git a/tests/libdnf/dnf-self-test.c b/tests/libdnf/dnf-self-test.c +index e0fbe657..2fe792e9 100644 +--- a/tests/libdnf/dnf-self-test.c ++++ b/tests/libdnf/dnf-self-test.c +@@ -189,6 +189,32 @@ dnf_lock_threads_func(void) + g_object_unref(lock); + } + ++static void ++dnf_split_releasever_func(void) ++{ ++ gchar *major, *minor; ++ dnf_split_releasever("1.23.45", &major, &minor); ++ g_assert_cmpstr(major, ==, "1"); ++ g_assert_cmpstr(minor, ==, "23.45"); ++ g_free(major); ++ g_free(minor); ++ dnf_split_releasever("6.789", &major, &minor); ++ g_assert_cmpstr(major, ==, "6"); ++ g_assert_cmpstr(minor, ==, "789"); ++ g_free(major); ++ g_free(minor); ++ dnf_split_releasever("10", &major, &minor); ++ g_assert_cmpstr(major, ==, "10"); ++ g_assert_cmpstr(minor, ==, ""); ++ g_free(major); ++ g_free(minor); ++ dnf_split_releasever("", &major, &minor); ++ g_assert_cmpstr(major, ==, ""); ++ g_assert_cmpstr(minor, ==, ""); ++ g_free(major); ++ g_free(minor); ++} ++ + static void + ch_test_repo_func(void) + { +@@ -1240,6 +1266,7 @@ main(int argc, char **argv) + g_test_add_func("/libdnf/context{cache-clean-check}", dnf_context_cache_clean_check_func); + g_test_add_func("/libdnf/lock", dnf_lock_func); + g_test_add_func("/libdnf/lock[threads]", dnf_lock_threads_func); ++ g_test_add_func("/libdnf/split_releasever", dnf_split_releasever_func); + g_test_add_func("/libdnf/repo", ch_test_repo_func); + g_test_add_func("/libdnf/repo_empty_keyfile", dnf_repo_setup_with_empty_keyfile); + g_test_add_func("/libdnf/state", dnf_state_func); +-- +2.48.1 + diff --git a/0010-C-API-Detect-releasever_major-releasever_minor-from-.patch b/0010-C-API-Detect-releasever_major-releasever_minor-from-.patch new file mode 100644 index 0000000..9e60b19 --- /dev/null +++ b/0010-C-API-Detect-releasever_major-releasever_minor-from-.patch @@ -0,0 +1,147 @@ +From 86120acbadab9347d53e93876906b0acdba92666 Mon Sep 17 00:00:00 2001 +From: Evan Goode +Date: Mon, 3 Feb 2025 20:31:12 +0000 +Subject: [PATCH 2/5] C API: Detect releasever_major, releasever_minor from + provides + +releasever_major and releasever_minor can now be overridden by virtual +provides on the system-release package (any of `DISTROVERPKG`). The +detection of releasever is unchanged. releasever_major and +releasever_minor are specified by the versions of the +`system-release-major` and `system-release-minor` provides, +respectively. + +Introduces dnf_context_set_release_ver_major and +dnf_context_set_release_ver_minor. +--- + libdnf/dnf-context.cpp | 65 ++++++++++++++++++++++++++++++++++++++++-- + libdnf/dnf-context.h | 4 +++ + 2 files changed, 66 insertions(+), 3 deletions(-) + +diff --git a/libdnf/dnf-context.cpp b/libdnf/dnf-context.cpp +index 1ec782d0..44d26ad1 100644 +--- a/libdnf/dnf-context.cpp ++++ b/libdnf/dnf-context.cpp +@@ -85,6 +85,8 @@ + #define MAX_NATIVE_ARCHES 12 + + #define RELEASEVER_PROV "system-release(releasever)" ++#define RELEASEVER_MAJOR_PROV "system-release(releasever_major)" ++#define RELEASEVER_MINOR_PROV "system-release(releasever_minor)" + + /* data taken from https://github.com/rpm-software-management/dnf/blob/master/dnf/arch.py */ + static const struct { +@@ -142,6 +144,8 @@ typedef struct + gchar **installonlypkgs; + gchar *base_arch; + gchar *release_ver; ++ gchar *release_ver_major; ++ gchar *release_ver_minor; + gchar *platform_module; + gchar *cache_dir; + gchar *solv_dir; +@@ -1271,7 +1275,9 @@ dnf_context_set_vars_dir(DnfContext *context, const gchar * const *vars_dir) + * @context: a #DnfContext instance. + * @release_ver: the release version, e.g. "20" + * +- * Sets the release version. ++ * Sets the release version. Sets the major and minor release version by splitting `release_ver` on ++ * the first ".". The derived major and minor versions can later be overridden by calling ++ *`dnf_context_set_release_ver_major` and `dnf_context_set_release_ver_minor`, respectively. + * + * Since: 0.1.0 + **/ +@@ -1281,6 +1287,46 @@ dnf_context_set_release_ver(DnfContext *context, const gchar *release_ver) + DnfContextPrivate *priv = GET_PRIVATE(context); + g_free(priv->release_ver); + priv->release_ver = g_strdup(release_ver); ++ ++ g_free(priv->release_ver_major); ++ g_free(priv->release_ver_minor); ++ dnf_split_releasever(release_ver, &priv->release_ver_major, &priv->release_ver_minor); ++} ++ ++/** ++ * dnf_context_set_release_ver_major: ++ * @context: a #DnfContext instance. ++ * @release_ver_major: the release major version, e.g. "10" ++ * ++ * Sets the release major version, which is usually derived by splitting releasever on the first ++ * ".". This setter does not update the value of $releasever. ++ * ++ * Since: 0.74.0 ++ **/ ++void ++dnf_context_set_release_ver_major(DnfContext *context, const gchar *release_ver_major) ++{ ++ DnfContextPrivate *priv = GET_PRIVATE(context); ++ g_free(priv->release_ver_major); ++ priv->release_ver_major = g_strdup(release_ver_major); ++} ++ ++/** ++ * dnf_context_set_release_ver_minor: ++ * @context: a #DnfContext instance. ++ * @release_ver_minor: the release minor version, e.g. "1" ++ * ++ * Sets the release minor version, which is usually derived by splitting releasever on the first ++ * ".". This setter does not update the value of $releasever. ++ * ++ * Since: 0.74.0 ++ **/ ++void ++dnf_context_set_release_ver_minor(DnfContext *context, const gchar *release_ver_minor) ++{ ++ DnfContextPrivate *priv = GET_PRIVATE(context); ++ g_free(priv->release_ver_minor); ++ priv->release_ver_minor = g_strdup(release_ver_minor); + } + + /** +@@ -1660,13 +1706,26 @@ dnf_context_set_os_release(DnfContext *context, GError **error) try + Header hdr; + while ((hdr = rpmdbNextIterator (mi)) != NULL) { + const char *v = headerGetString (hdr, RPMTAG_VERSION); ++ const char *v_major = nullptr; ++ const char *v_minor = nullptr; + rpmds ds = rpmdsNew (hdr, RPMTAG_PROVIDENAME, 0); + while (rpmdsNext (ds) >= 0) { +- if (strcmp (rpmdsN (ds), RELEASEVER_PROV) == 0 && rpmdsFlags (ds) == RPMSENSE_EQUAL) ++ if (strcmp (rpmdsN (ds), RELEASEVER_PROV) == 0 && rpmdsFlags (ds) == RPMSENSE_EQUAL) { + v = rpmdsEVR (ds); ++ } else if (strcmp (rpmdsN (ds), RELEASEVER_MAJOR_PROV) == 0 && rpmdsFlags (ds) == RPMSENSE_EQUAL) { ++ v_major = rpmdsEVR(ds); ++ } else if (strcmp (rpmdsN (ds), RELEASEVER_MINOR_PROV) == 0 && rpmdsFlags (ds) == RPMSENSE_EQUAL) { ++ v_minor = rpmdsEVR(ds); ++ } + } + found_in_rpmdb = TRUE; +- dnf_context_set_release_ver (context, v); ++ dnf_context_set_release_ver(context, v); ++ if (v_major != nullptr) { ++ dnf_context_set_release_ver_major(context, v_major); ++ } ++ if (v_minor != nullptr) { ++ dnf_context_set_release_ver_minor(context, v_minor); ++ } + rpmdsFree (ds); + break; + } +diff --git a/libdnf/dnf-context.h b/libdnf/dnf-context.h +index cb00a29b..4d8481b2 100644 +--- a/libdnf/dnf-context.h ++++ b/libdnf/dnf-context.h +@@ -164,6 +164,10 @@ void dnf_context_set_vars_dir (DnfContext *context + const gchar * const *vars_dir); + void dnf_context_set_release_ver (DnfContext *context, + const gchar *release_ver); ++void dnf_context_set_release_ver_major (DnfContext *context, ++ const gchar *release_ver_major); ++void dnf_context_set_release_ver_minor (DnfContext *context, ++ const gchar *release_ver_minor); + void dnf_context_set_platform_module (DnfContext *context, + const gchar *platform_module); + void dnf_context_set_cache_dir (DnfContext *context, +-- +2.48.1 + diff --git a/0011-C-API-Use-releasever_-major-minor-from-context-inste.patch b/0011-C-API-Use-releasever_-major-minor-from-context-inste.patch new file mode 100644 index 0000000..95ad01c --- /dev/null +++ b/0011-C-API-Use-releasever_-major-minor-from-context-inste.patch @@ -0,0 +1,121 @@ +From e3f6174b5ec97fded9d8f91b3186813ae89b51b7 Mon Sep 17 00:00:00 2001 +From: Evan Goode +Date: Mon, 3 Feb 2025 16:06:35 -0500 +Subject: [PATCH 3/5] C API: Use releasever_{major,minor} from context instead + of always splitting + +Introduces dnf_context_get_release_ver_major and +dnf_context_get_release_ver_minor. +--- + libdnf/dnf-context.cpp | 36 ++++++++++++++++++++++++++++++++++++ + libdnf/dnf-context.h | 2 ++ + libdnf/dnf-repo.cpp | 17 +++++++++++------ + 3 files changed, 49 insertions(+), 6 deletions(-) + +diff --git a/libdnf/dnf-context.cpp b/libdnf/dnf-context.cpp +index 44d26ad1..9db4278c 100644 +--- a/libdnf/dnf-context.cpp ++++ b/libdnf/dnf-context.cpp +@@ -620,6 +620,42 @@ dnf_context_get_release_ver(DnfContext *context) + return priv->release_ver; + } + ++/** ++ * dnf_context_get_release_ver_major: ++ * @context: a #DnfContext instance. ++ * ++ * Gets the release major version. Usually derived by taking the substring of releasever before the ++ * first ".", but can be overridden by the distribution. ++ * ++ * Returns: the release major version, e.g. "10" ++ * ++ * Since: 0.74.0 ++ **/ ++const gchar * ++dnf_context_get_release_ver_major(DnfContext *context) ++{ ++ DnfContextPrivate *priv = GET_PRIVATE(context); ++ return priv->release_ver_major; ++} ++ ++/** ++ * dnf_context_get_release_ver_minor: ++ * @context: a #DnfContext instance. ++ * ++ * Gets the release minor version. Usually derived by taking the substring of releasever after the ++ * first ".", but can be overridden by the distribution. ++ * ++ * Returns: the release minor version, e.g. "1" ++ * ++ * Since: 0.74.0 ++ **/ ++const gchar * ++dnf_context_get_release_ver_minor(DnfContext *context) ++{ ++ DnfContextPrivate *priv = GET_PRIVATE(context); ++ return priv->release_ver_minor; ++} ++ + /** + * dnf_context_get_platform_module: + * @context: a #DnfContext instance. +diff --git a/libdnf/dnf-context.h b/libdnf/dnf-context.h +index 4d8481b2..8e1c948e 100644 +--- a/libdnf/dnf-context.h ++++ b/libdnf/dnf-context.h +@@ -120,6 +120,8 @@ const gchar *dnf_context_get_base_arch (DnfContext *context + const gchar *dnf_context_get_os_info (DnfContext *context); + const gchar *dnf_context_get_arch_info (DnfContext *context); + const gchar *dnf_context_get_release_ver (DnfContext *context); ++const gchar *dnf_context_get_release_ver_major (DnfContext *context); ++const gchar *dnf_context_get_release_ver_minor (DnfContext *context); + const gchar *dnf_context_get_platform_module (DnfContext *context); + const gchar *dnf_context_get_cache_dir (DnfContext *context); + const gchar *dnf_context_get_arch (DnfContext *context); +diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp +index 49da175f..b5009758 100644 +--- a/libdnf/dnf-repo.cpp ++++ b/libdnf/dnf-repo.cpp +@@ -1194,8 +1194,8 @@ dnf_repo_setup(DnfRepo *repo, GError **error) try + DnfRepoEnabled enabled = DNF_REPO_ENABLED_NONE; + g_autofree gchar *basearch = NULL; + g_autofree gchar *release = NULL; +- g_autofree gchar *major = NULL; +- g_autofree gchar *minor = NULL; ++ g_autofree gchar *release_major = NULL; ++ g_autofree gchar *release_minor = NULL; + + basearch = g_key_file_get_string(priv->keyfile, "general", "arch", NULL); + if (basearch == NULL) +@@ -1208,8 +1208,14 @@ dnf_repo_setup(DnfRepo *repo, GError **error) try + return FALSE; + } + release = g_key_file_get_string(priv->keyfile, "general", "version", NULL); +- if (release == NULL) ++ if (release == NULL) { + release = g_strdup(dnf_context_get_release_ver(priv->context)); ++ release_major = g_strdup(dnf_context_get_release_ver_major(priv->context)); ++ release_minor = g_strdup(dnf_context_get_release_ver_minor(priv->context)); ++ } else { ++ dnf_split_releasever(release, &release_major, &release_minor); ++ } ++ + if (release == NULL) { + g_set_error_literal(error, + DNF_ERROR, +@@ -1223,10 +1229,9 @@ dnf_repo_setup(DnfRepo *repo, GError **error) try + return FALSE; + if (!lr_handle_setopt(priv->repo_handle, error, LRO_INTERRUPTIBLE, 0L)) + return FALSE; +- dnf_split_releasever(release, &major, &minor); + priv->urlvars = lr_urlvars_set(priv->urlvars, "releasever", release); +- priv->urlvars = lr_urlvars_set(priv->urlvars, "releasever_major", major); +- priv->urlvars = lr_urlvars_set(priv->urlvars, "releasever_minor", minor); ++ priv->urlvars = lr_urlvars_set(priv->urlvars, "releasever_major", release_major); ++ priv->urlvars = lr_urlvars_set(priv->urlvars, "releasever_minor", release_minor); + priv->urlvars = lr_urlvars_set(priv->urlvars, "basearch", basearch); + /* Call libdnf::dnf_context_load_vars(priv->context); only when values not in cache. + * But what about if variables on disk change during long running programs (PackageKit daemon)? +-- +2.48.1 + diff --git a/0012-C-API-support-shell-style-variable-substitution.patch b/0012-C-API-support-shell-style-variable-substitution.patch new file mode 100644 index 0000000..d9b687a --- /dev/null +++ b/0012-C-API-support-shell-style-variable-substitution.patch @@ -0,0 +1,60 @@ +From f829c16b0677d143ea0ea40a8364b397168292dc Mon Sep 17 00:00:00 2001 +From: Evan Goode +Date: Fri, 7 Feb 2025 18:02:20 +0000 +Subject: [PATCH 4/5] C API: support shell-style variable substitution + +Rework `dnf_repo_substitute` to call the C++ API's +ConfigParser::substitute instead of librepo's lr_url_substitute. + +Resolves https://github.com/rpm-software-management/libdnf/issues/1690 +--- + libdnf/dnf-repo.cpp | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp +index b5009758..7b4f83bb 100644 +--- a/libdnf/dnf-repo.cpp ++++ b/libdnf/dnf-repo.cpp +@@ -34,6 +34,7 @@ + */ + + #include "conf/OptionBool.hpp" ++#include "conf/ConfigParser.hpp" + + #include "dnf-context.hpp" + #include "hy-repo-private.hpp" +@@ -45,6 +46,7 @@ + #include + #include "hy-util.h" + #include ++#include + #include + #include + +@@ -242,14 +244,17 @@ static gchar * + dnf_repo_substitute(DnfRepo *repo, const gchar *url) + { + DnfRepoPrivate *priv = GET_PRIVATE(repo); +- char *tmp; +- gchar *substituted; + +- /* do a little dance so we can use g_free() rather than lr_free() */ +- tmp = lr_url_substitute(url, priv->urlvars); +- substituted = g_strdup(tmp); +- lr_free(tmp); ++ std::map substitutions; ++ for (LrUrlVars *elem = priv->urlvars; elem; elem = g_slist_next(elem)) { ++ const auto * pair = static_cast(elem->data); ++ substitutions.insert({std::string{pair->var}, std::string{pair->val}}); ++ } ++ ++ std::string tmp{url}; ++ libdnf::ConfigParser::substitute(tmp, substitutions); + ++ auto * substituted = g_strdup(tmp.c_str()); + return substituted; + } + +-- +2.48.1 + diff --git a/0013-C-API-test-shell-style-variable-expressions.patch b/0013-C-API-test-shell-style-variable-expressions.patch new file mode 100644 index 0000000..abec327 --- /dev/null +++ b/0013-C-API-test-shell-style-variable-expressions.patch @@ -0,0 +1,80 @@ +From c6ee39c06e0d18c1d299f5324bf86a4a08910ee9 Mon Sep 17 00:00:00 2001 +From: Evan Goode +Date: Fri, 7 Feb 2025 18:42:43 +0000 +Subject: [PATCH 5/5] C API: test shell-style variable expressions + +--- + data/tests/vars/var1 | 1 + + data/tests/vars/var2 | 1 + + data/tests/yum.repos.d/shell-expansion.repo | 5 +++++ + tests/libdnf/dnf-self-test.c | 10 ++++++++++ + 4 files changed, 17 insertions(+) + create mode 100644 data/tests/vars/var1 + create mode 100644 data/tests/vars/var2 + create mode 100644 data/tests/yum.repos.d/shell-expansion.repo + +diff --git a/data/tests/vars/var1 b/data/tests/vars/var1 +new file mode 100644 +index 00000000..a9f37252 +--- /dev/null ++++ b/data/tests/vars/var1 +@@ -0,0 +1 @@ ++value123 +diff --git a/data/tests/vars/var2 b/data/tests/vars/var2 +new file mode 100644 +index 00000000..8d38505c +--- /dev/null ++++ b/data/tests/vars/var2 +@@ -0,0 +1 @@ ++456 +diff --git a/data/tests/yum.repos.d/shell-expansion.repo b/data/tests/yum.repos.d/shell-expansion.repo +new file mode 100644 +index 00000000..3bd4c1ec +--- /dev/null ++++ b/data/tests/yum.repos.d/shell-expansion.repo +@@ -0,0 +1,5 @@ ++[shell-expansion] ++name=${unset:-${var1:+${var2:+$var2}}} ++baseurl=https://${unset:-${var1:+${var2:+$var2}}} ++enabled=1 ++gpgcheck=0 +diff --git a/tests/libdnf/dnf-self-test.c b/tests/libdnf/dnf-self-test.c +index 2fe792e9..452cf20a 100644 +--- a/tests/libdnf/dnf-self-test.c ++++ b/tests/libdnf/dnf-self-test.c +@@ -843,6 +843,7 @@ dnf_repo_loader_func(void) + DnfState *state; + gboolean ret; + g_autofree gchar *repos_dir = NULL; ++ g_autofree gchar *vars_dir = NULL; + g_autoptr(DnfContext) ctx = NULL; + g_autoptr(DnfRepoLoader) repo_loader = NULL; + guint metadata_expire; +@@ -850,8 +851,10 @@ dnf_repo_loader_func(void) + /* set up local context */ + ctx = dnf_context_new(); + repos_dir = dnf_test_get_filename("yum.repos.d"); ++ vars_dir = dnf_test_get_filename("vars"); + dnf_context_set_repo_dir(ctx, repos_dir); + dnf_context_set_solv_dir(ctx, "/tmp"); ++ dnf_context_set_vars_dir(ctx, (const gchar *[]){vars_dir, NULL}); + ret = dnf_context_setup(ctx, NULL, &error); + g_assert_no_error(error); + g_assert(ret); +@@ -907,6 +910,13 @@ dnf_repo_loader_func(void) + g_assert_error(error, DNF_ERROR, DNF_ERROR_REPO_NOT_AVAILABLE); + g_assert(!ret); + g_clear_error(&error); ++ ++ /* check that shell-style variable expressions are correctly expanded in repo values */ ++ dnf_state_reset(state); ++ repo = dnf_repo_loader_get_repo_by_id(repo_loader, "shell-expansion", &error); ++ g_assert_no_error(error); ++ g_assert(repo != NULL); ++ g_assert_cmpstr(dnf_repo_get_description(repo), ==, "456"); + } + + static void +-- +2.48.1 + diff --git a/libdnf.spec b/libdnf.spec index 1d14364..6fb07d3 100644 --- a/libdnf.spec +++ b/libdnf.spec @@ -56,7 +56,7 @@ Name: libdnf Version: %{libdnf_major_version}.%{libdnf_minor_version}.%{libdnf_micro_version} -Release: 8%{?dist} +Release: 9%{?dist} Summary: Library providing simplified C and Python API to libsolv License: LGPL-2.1-or-later URL: https://github.com/rpm-software-management/libdnf @@ -69,6 +69,11 @@ Patch5: 0005-ConfigParser-fix-use-out-of-scope-leaks.patch Patch6: 0006-Add-tests-for-shell-style-variable-expansion.patch Patch7: 0007-Add-persistence-config-option.patch Patch8: 0008-ConfigParser-make-splitReleasever-public.patch +Patch9: 0009-Split-releasever-to-releasever_major-and-releasever_.patch +Patch10: 0010-C-API-Detect-releasever_major-releasever_minor-from-.patch +Patch11: 0011-C-API-Use-releasever_-major-minor-from-context-inste.patch +Patch12: 0012-C-API-support-shell-style-variable-substitution.patch +Patch13: 0013-C-API-test-shell-style-variable-expressions.patch BuildRequires: cmake BuildRequires: gcc @@ -312,6 +317,9 @@ popd %endif %changelog +* Mon Mar 10 2025 Evan Goode - 0.73.1-9 +- Support releasever_{major,minor}, shell-style variable substitution (RHEL-74025) + * Fri Feb 07 2025 Carl George - 0.73.1-8 - ConfigParser: make splitReleasever public (RHEL-68034)