diff --git a/libmamba/include/mamba/specs/match_spec.hpp b/libmamba/include/mamba/specs/match_spec.hpp index f65c024807..0f2301f499 100644 --- a/libmamba/include/mamba/specs/match_spec.hpp +++ b/libmamba/include/mamba/specs/match_spec.hpp @@ -14,6 +14,7 @@ #include #include "mamba/specs/channel_spec.hpp" +#include "mamba/specs/glob_spec.hpp" #include "mamba/specs/version_spec.hpp" namespace mamba::specs @@ -44,8 +45,8 @@ namespace mamba::specs [[nodiscard]] auto build_number() const -> const std::string&; void set_build_number(std::string num); - [[nodiscard]] auto build_string() const -> const std::string&; - void set_build_string(std::string bs); + [[nodiscard]] auto build_string() const -> const GlobSpec&; + void set_build_string(GlobSpec bs); [[nodiscard]] auto optional() const -> bool; void set_optional(bool opt); @@ -69,10 +70,10 @@ namespace mamba::specs std::optional m_channel; VersionSpec m_version; + GlobSpec m_build_string; std::string m_name_space; std::string m_name; std::string m_build_number; - std::string m_build_string; // TODO can put inside channel spec std::string m_filename; std::string m_url; diff --git a/libmamba/src/api/install.cpp b/libmamba/src/api/install.cpp index 59d32d649b..6d17c7cd83 100644 --- a/libmamba/src/api/install.cpp +++ b/libmamba/src/api/install.cpp @@ -357,7 +357,7 @@ namespace mamba auto ms = specs::MatchSpec::parse(u.substr(0, hash)); PackageInfo p(ms.name()); p.url = ms.url(); - p.build_string = ms.build_string(); + p.build_string = ms.build_string().str(); p.version = ms.version().str(); if (ms.channel().has_value()) { diff --git a/libmamba/src/core/env_lockfile.cpp b/libmamba/src/core/env_lockfile.cpp index 251b2a0893..c680e02eb1 100644 --- a/libmamba/src/core/env_lockfile.cpp +++ b/libmamba/src/core/env_lockfile.cpp @@ -58,7 +58,7 @@ namespace mamba package.info.url = package_node["url"].as(); const auto spec = specs::MatchSpec::parse(package.info.url); package.info.fn = spec.filename(); - package.info.build_string = spec.build_string(); + package.info.build_string = spec.build_string().str(); if (spec.channel().has_value()) { package.info.channel = spec.channel()->location(); diff --git a/libmamba/src/core/satisfiability_error.cpp b/libmamba/src/core/satisfiability_error.cpp index 67379d1169..9e14b48346 100644 --- a/libmamba/src/core/satisfiability_error.cpp +++ b/libmamba/src/core/satisfiability_error.cpp @@ -562,6 +562,22 @@ namespace mamba return v; } } + + template + auto invoke_build_string(T&& e) -> decltype(auto) + { + using TT = std::remove_cv_t>; + using Build = decltype(std::invoke(&TT::build_string, std::forward(e))); + Build bld = std::invoke(&TT::build_string, std::forward(e)); + if constexpr (std::is_same_v, specs::GlobSpec>) + { + return std::forward(bld).str(); + } + else + { + return bld; + } + } } template @@ -573,12 +589,12 @@ namespace mamba decltype(invoke_name(x)), decltype(invoke_version(x)), decltype(std::invoke(&T::build_number, x)), - decltype(std::invoke(&T::build_string, x))>; + decltype(invoke_build_string(x))>; return Attrs( invoke_name(x), invoke_version(x), std::invoke(&T::build_number, x), - std::invoke(&T::build_string, x) + invoke_build_string(x) ); }; return attrs(a) < attrs(b); @@ -694,13 +710,13 @@ namespace mamba ) const -> std::pair { auto builds = std::vector(size()); - auto invoke_build_string = [](auto&& v) -> decltype(auto) - { - using TT = std::remove_cv_t>; - return std::invoke(&TT::build_string, std::forward(v)); - }; // TODO(C++20) *this | std::ranges::transform(invoke_buid_string) | ranges::unique - std::transform(begin(), end(), builds.begin(), invoke_build_string); + std::transform( + begin(), + end(), + builds.begin(), + [](const auto& p) { return invoke_build_string(p); } + ); if (remove_duplicates) { builds.erase(std::unique(builds.begin(), builds.end()), builds.end()); @@ -718,14 +734,7 @@ namespace mamba { auto versions_builds = std::vector(size()); auto invoke_version_builds = [](auto&& v) -> decltype(auto) - { - using TT = std::remove_cv_t>; - return fmt::format( - "{} {}", - std::invoke(&TT::version, std::forward(v)), - std::invoke(&TT::build_string, std::forward(v)) - ); - }; + { return fmt::format("{} {}", invoke_version(v), invoke_build_string(v)); }; // TODO(C++20) *this | std::ranges::transform(invoke_version) | ranges::unique std::transform(begin(), end(), versions_builds.begin(), invoke_version_builds); if (remove_duplicates) diff --git a/libmamba/src/core/solver.cpp b/libmamba/src/core/solver.cpp index 7092a8693d..acfef9210a 100644 --- a/libmamba/src/core/solver.cpp +++ b/libmamba/src/core/solver.cpp @@ -97,7 +97,7 @@ namespace mamba } if (ms.channel().has_value() || !ms.version().is_explicitly_free() - || !ms.build_string().empty()) + || !ms.build_string().is_free()) { Console::stream() << ms.conda_build_form() << ": overriding channel, version and build from " @@ -107,7 +107,7 @@ namespace mamba auto ms_modified = ms; ms_modified.set_channel(specs::ChannelSpec::parse(solvable->channel())); ms_modified.set_version(specs::VersionSpec::parse(solvable->version())); - ms_modified.set_build_string(std::string(solvable->build_string())); + ms_modified.set_build_string(specs::GlobSpec(std::string(solvable->build_string()))); LOG_INFO << "Reinstall " << ms_modified.conda_build_form() << " from channel " << ms_modified.channel()->str(); diff --git a/libmamba/src/core/transaction.cpp b/libmamba/src/core/transaction.cpp index a096b0d054..4dc61d0791 100644 --- a/libmamba/src/core/transaction.cpp +++ b/libmamba/src/core/transaction.cpp @@ -72,7 +72,7 @@ namespace mamba out.emplace_back(ms.name()); auto& p = out.back(); p.url = ms.url(); - p.build_string = ms.build_string(); + p.build_string = ms.build_string().str(); p.version = ms.version().str_conda_build(); if (ms.channel().has_value()) { diff --git a/libmamba/src/specs/match_spec.cpp b/libmamba/src/specs/match_spec.cpp index 2cf0220b19..b80909a2bd 100644 --- a/libmamba/src/specs/match_spec.cpp +++ b/libmamba/src/specs/match_spec.cpp @@ -69,7 +69,7 @@ namespace mamba::specs // Build string auto [head, tail] = util::rsplit_once(strip_archive_extension(pkg), '-'); - out.m_build_string = tail; + out.m_build_string = GlobSpec(std::string(tail)); if (!head.has_value()) { fail_parse(); @@ -226,7 +226,7 @@ namespace mamba::specs auto [pv, pb] = parse_version_and_build(version_and_build); out.m_version = VersionSpec::parse(pv); - out.m_build_string = pb; + out.m_build_string = GlobSpec(std::string(pb)); } else // no-op { @@ -245,7 +245,7 @@ namespace mamba::specs } else if (k == "build") { - out.m_build_string = v; + out.m_build_string = GlobSpec(std::string(v)); } else if (k == "version") { @@ -350,7 +350,7 @@ namespace mamba::specs m_build_number = std::move(bn); } - auto MatchSpec::build_string() const -> const std::string& + auto MatchSpec::build_string() const -> const GlobSpec& { return m_build_string; } @@ -365,7 +365,7 @@ namespace mamba::specs m_optional = opt; } - void MatchSpec::set_build_string(std::string bs) + void MatchSpec::set_build_string(GlobSpec bs) { m_build_string = std::move(bs); } @@ -388,13 +388,13 @@ namespace mamba::specs { res << " " << m_version.str_conda_build(); } - else if (!m_build_string.empty()) + else if (!m_build_string.is_free()) { res << " *"; } - if (!m_build_string.empty()) + if (!m_build_string.is_free()) { - res << " " << m_build_string; + res << " " << m_build_string.str(); } return res.str(); } @@ -449,23 +449,15 @@ namespace mamba::specs } } - if (!m_build_string.empty()) + if (!m_build_string.is_free()) { - if (is_complex_relation(m_build_string)) + if (m_build_string.is_exact()) { - formatted_brackets.push_back(util::concat("build='", m_build_string, '\'')); - } - else if (m_build_string.find('*') != m_build_string.npos) - { - formatted_brackets.push_back(util::concat("build=", m_build_string)); - } - else if (version_exact) - { - res << "=" << m_build_string; + res << "=" << m_build_string.str(); } else { - formatted_brackets.push_back(util::concat("build=", m_build_string)); + formatted_brackets.push_back(util::concat("build='", m_build_string.str(), '\'')); } } @@ -514,7 +506,7 @@ namespace mamba::specs auto MatchSpec::is_simple() const -> bool { - return m_version.is_explicitly_free() && m_build_string.empty() && m_build_number.empty(); + return m_version.is_explicitly_free() && m_build_string.is_free() && m_build_number.empty(); } auto MatchSpec::is_file() const -> bool diff --git a/libmamba/tests/src/specs/test_match_spec.cpp b/libmamba/tests/src/specs/test_match_spec.cpp index f46cfed07f..755b5eb203 100644 --- a/libmamba/tests/src/specs/test_match_spec.cpp +++ b/libmamba/tests/src/specs/test_match_spec.cpp @@ -137,7 +137,7 @@ TEST_SUITE("specs::match_spec") ); CHECK_EQ(ms.name(), "_libgcc_mutex"); CHECK_EQ(ms.version().str(), "==0.1"); - CHECK_EQ(ms.build_string(), "conda_forge"); + CHECK_EQ(ms.build_string().str(), "conda_forge"); CHECK_EQ( ms.url(), "https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" @@ -150,7 +150,7 @@ TEST_SUITE("specs::match_spec") ); CHECK_EQ(ms.name(), "libgcc-ng"); CHECK_EQ(ms.version().str(), "==11.2.0"); - CHECK_EQ(ms.build_string(), "h1d223b6_13"); + CHECK_EQ(ms.build_string().str(), "h1d223b6_13"); CHECK_EQ( ms.url(), "https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-11.2.0-h1d223b6_13.tar.bz2" @@ -163,7 +163,7 @@ TEST_SUITE("specs::match_spec") ); CHECK_EQ(ms.name(), "_libgcc_mutex"); CHECK_EQ(ms.version().str(), "==0.1"); - CHECK_EQ(ms.build_string(), "conda_forge"); + CHECK_EQ(ms.build_string().str(), "conda_forge"); if (util::on_win) { std::string driveletter = fs::absolute(fs::u8path("/")).string().substr(0, 1);