diff --git a/libmamba/include/mamba/core/channel_context.hpp b/libmamba/include/mamba/core/channel_context.hpp index 522942472e..672f04c9d2 100644 --- a/libmamba/include/mamba/core/channel_context.hpp +++ b/libmamba/include/mamba/core/channel_context.hpp @@ -51,7 +51,8 @@ namespace mamba */ ChannelContext(ChannelResolveParams params, std::vector has_zst); - auto make_channel(std::string_view name) -> const channel_list&; + [[nodiscard]] auto make_channel(specs::ChannelSpec spec) -> const channel_list&; + [[nodiscard]] auto make_channel(std::string_view name) -> const channel_list&; [[nodiscard]] auto params() const -> const specs::ChannelResolveParams&; diff --git a/libmamba/include/mamba/core/match_spec.hpp b/libmamba/include/mamba/core/match_spec.hpp index 2b8259e0d2..b781474115 100644 --- a/libmamba/include/mamba/core/match_spec.hpp +++ b/libmamba/include/mamba/core/match_spec.hpp @@ -31,7 +31,7 @@ namespace mamba bool is_simple() const; - static std::tuple parse_version_and_build(const std::string& s); + static std::tuple parse_version_and_build(std::string_view s); std::string spec; std::string name; diff --git a/libmamba/include/mamba/specs/channel_spec.hpp b/libmamba/include/mamba/specs/channel_spec.hpp index dd3200cd1f..2bf7e0389e 100644 --- a/libmamba/include/mamba/specs/channel_spec.hpp +++ b/libmamba/include/mamba/specs/channel_spec.hpp @@ -11,6 +11,9 @@ #include #include +#include +#include + #include "mamba/util/flat_set.hpp" namespace mamba::specs @@ -98,6 +101,8 @@ namespace mamba::specs [[nodiscard]] auto platform_filters() && -> dynamic_platform_set; auto clear_platform_filters() -> dynamic_platform_set; + [[nodiscard]] auto str() const -> std::string; + private: std::string m_location = std::string(unknown_channel); @@ -105,4 +110,23 @@ namespace mamba::specs Type m_type = Type::Unknown; }; } + +template <> +struct fmt::formatter +{ + using ChannelSpec = ::mamba::specs::ChannelSpec; + + constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator + { + // make sure that range is empty + if (ctx.begin() != ctx.end() && *ctx.begin() != '}') + { + throw fmt::format_error("Invalid format"); + } + return ctx.begin(); + } + + auto format(const ChannelSpec& spec, format_context& ctx) const -> format_context::iterator; +}; + #endif diff --git a/libmamba/src/core/channel_context.cpp b/libmamba/src/core/channel_context.cpp index 07e9324567..98368be75b 100644 --- a/libmamba/src/core/channel_context.cpp +++ b/libmamba/src/core/channel_context.cpp @@ -214,6 +214,22 @@ namespace mamba return { std::move(params), has_zst }; } + auto ChannelContext::make_channel(specs::ChannelSpec spec) -> const channel_list& + { + auto str = spec.str(); + if (const auto it = m_channel_cache.find(str); it != m_channel_cache.end()) + { + return it->second; + } + + auto [it, inserted] = m_channel_cache.emplace( + std::move(str), + Channel::resolve(std::move(spec), params()) + ); + assert(inserted); + return it->second; + } + auto ChannelContext::make_channel(std::string_view name) -> const channel_list& { if (const auto it = m_channel_cache.find(std::string(name)); it != m_channel_cache.end()) diff --git a/libmamba/src/core/match_spec.cpp b/libmamba/src/core/match_spec.cpp index 5ed46b9e95..3ebc5e8fc8 100644 --- a/libmamba/src/core/match_spec.cpp +++ b/libmamba/src/core/match_spec.cpp @@ -41,14 +41,14 @@ namespace mamba parse(ctx, channel_context); } - std::tuple MatchSpec::parse_version_and_build(const std::string& s) + std::tuple MatchSpec::parse_version_and_build(std::string_view s) { - std::size_t pos = s.find_last_of(" ="); + std::size_t const pos = s.find_last_of(" ="); if (pos == s.npos || pos == 0) { - std::string tmp = s; + std::string tmp = std::string(s); util::replace_all(tmp, " ", ""); - return { tmp, "" }; + return { std::move(tmp), "" }; } else { @@ -59,17 +59,18 @@ namespace mamba char d = s[pm1]; if (d == '=' || d == '!' || d == '|' || d == ',' || d == '<' || d == '>' || d == '~') { - std::string tmp = s; + auto tmp = std::string(s); util::replace_all(tmp, " ", ""); return { tmp, "" }; } } // c is either ' ' or pm1 is none of the forbidden chars - std::string v = s.substr(0, pos), b = s.substr(pos + 1); + auto v = std::string(s.substr(0, pos)); + auto b = std::string(s.substr(pos + 1)); util::replace_all(v, " ", ""); util::replace_all(b, " ", ""); - return { v, b }; + return { std::move(v), std::move(b) }; } } @@ -124,7 +125,7 @@ namespace mamba auto extract_kv = [&spec_str](const std::string& kv_string, auto& map) { - static std::regex kv_re("([a-zA-Z0-9_-]+?)=([\"\']?)([^\'\"]*?)(\\2)(?:[\'\", ]|$)"); + static const std::regex kv_re("([a-zA-Z0-9_-]+?)=([\"\']?)([^\'\"]*?)(\\2)(?:[\'\", ]|$)"); std::cmatch kv_match; const char* text_iter = kv_string.c_str(); diff --git a/libmamba/src/specs/channel_spec.cpp b/libmamba/src/specs/channel_spec.cpp index 93f2c0179a..85614c8c8c 100644 --- a/libmamba/src/specs/channel_spec.cpp +++ b/libmamba/src/specs/channel_spec.cpp @@ -163,7 +163,7 @@ namespace mamba::specs if (m_type == Type::Unknown) { m_location = unknown_channel; - m_platform_filters = {}; + // Allowing in any platform filters for unkown type can be useful in MatchSpec } if (m_location.empty()) { @@ -208,4 +208,21 @@ namespace mamba::specs { return std::exchange(m_platform_filters, {}); } + + auto ChannelSpec::str() const -> std::string + { + return fmt::format("{}", *this); + } +} + +auto +fmt::formatter::format(const ChannelSpec& spec, format_context& ctx) const + -> format_context::iterator +{ + auto out = fmt::format_to(ctx.out(), "{}", spec.location()); + if (!spec.platform_filters().empty()) + { + out = fmt::format_to(ctx.out(), "[{}]", fmt::join(spec.platform_filters(), ",")); + } + return out; } diff --git a/libmamba/tests/CMakeLists.txt b/libmamba/tests/CMakeLists.txt index 96d313883b..4ae099eb19 100644 --- a/libmamba/tests/CMakeLists.txt +++ b/libmamba/tests/CMakeLists.txt @@ -58,6 +58,7 @@ set( src/core/test_activation.cpp src/core/test_channel_context.cpp src/core/test_configuration.cpp + src/core/test_match_spec.cpp src/core/test_cpp.cpp src/core/test_downloader.cpp src/core/test_env_file_reading.cpp diff --git a/libmamba/tests/src/core/test_cpp.cpp b/libmamba/tests/src/core/test_cpp.cpp index 0315fdda64..8c4d3c35ea 100644 --- a/libmamba/tests/src/core/test_cpp.cpp +++ b/libmamba/tests/src/core/test_cpp.cpp @@ -15,7 +15,6 @@ #include "mamba/core/fsutil.hpp" #include "mamba/core/history.hpp" #include "mamba/core/link.hpp" -#include "mamba/core/match_spec.hpp" #include "mamba/core/output.hpp" #include "mamba/core/subdirdata.hpp" #include "mamba/util/build.hpp" @@ -47,268 +46,6 @@ namespace mamba // lp.execute(); // } - TEST_SUITE("match_spec") - { - TEST_CASE("parse_version_build") - { - std::string v, b; - // >>> _parse_version_plus_build("=1.2.3 0") - // ('=1.2.3', '0') - // >>> _parse_version_plus_build("1.2.3=0") - // ('1.2.3', '0') - // >>> _parse_version_plus_build(">=1.0 , < 2.0 py34_0") - // ('>=1.0,<2.0', 'py34_0') - // >>> _parse_version_plus_build(">=1.0 , < 2.0 =py34_0") - // ('>=1.0,<2.0', 'py34_0') - // >>> _parse_version_plus_build("=1.2.3 ") - // ('=1.2.3', None) - // >>> _parse_version_plus_build(">1.8,<2|==1.7") - // ('>1.8,<2|==1.7', None) - // >>> _parse_version_plus_build("* openblas_0") - // ('*', 'openblas_0') - // >>> _parse_version_plus_build("* *") - // ('*', '*') - std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3 0"); - CHECK_EQ(v, "=1.2.3"); - CHECK_EQ(b, "0"); - std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3=0"); - CHECK_EQ(v, "=1.2.3"); - CHECK_EQ(b, "0"); - std::tie(v, b) = MatchSpec::parse_version_and_build(">=1.0 , < 2.0 py34_0"); - CHECK_EQ(v, ">=1.0,<2.0"); - CHECK_EQ(b, "py34_0"); - std::tie(v, b) = MatchSpec::parse_version_and_build(">=1.0 , < 2.0 =py34_0"); - CHECK_EQ(v, ">=1.0,<2.0"); - CHECK_EQ(b, "py34_0"); - std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3 "); - CHECK_EQ(v, "=1.2.3"); - CHECK_EQ(b, ""); - std::tie(v, b) = MatchSpec::parse_version_and_build(">1.8,<2|==1.7"); - CHECK_EQ(v, ">1.8,<2|==1.7"); - CHECK_EQ(b, ""); - std::tie(v, b) = MatchSpec::parse_version_and_build("* openblas_0"); - CHECK_EQ(v, "*"); - CHECK_EQ(b, "openblas_0"); - std::tie(v, b) = MatchSpec::parse_version_and_build("* *"); - CHECK_EQ(v, "*"); - CHECK_EQ(b, "*"); - } - - TEST_CASE("parse") - { - auto& ctx = mambatests::context(); - auto channel_context = ChannelContext::make_conda_compatible(ctx); - { - MatchSpec ms("xtensor==0.12.3", ctx, channel_context); - CHECK_EQ(ms.version, "0.12.3"); - CHECK_EQ(ms.name, "xtensor"); - } - { - MatchSpec ms("", ctx, channel_context); - CHECK_EQ(ms.version, ""); - CHECK_EQ(ms.name, ""); - } - { - MatchSpec ms("ipykernel", ctx, channel_context); - CHECK_EQ(ms.version, ""); - CHECK_EQ(ms.name, "ipykernel"); - } - { - MatchSpec ms("ipykernel ", ctx, channel_context); - CHECK_EQ(ms.version, ""); - CHECK_EQ(ms.name, "ipykernel"); - } - { - MatchSpec ms("numpy 1.7*", ctx, channel_context); - CHECK_EQ(ms.version, "1.7*"); - CHECK_EQ(ms.name, "numpy"); - CHECK_EQ(ms.conda_build_form(), "numpy 1.7*"); - CHECK_EQ(ms.str(), "numpy=1.7"); - } - { - MatchSpec ms("numpy[version='1.7|1.8']", ctx, channel_context); - // TODO! - // CHECK_EQ(ms.version, "1.7|1.8"); - CHECK_EQ(ms.name, "numpy"); - CHECK_EQ(ms.brackets["version"], "1.7|1.8"); - CHECK_EQ(ms.str(), "numpy[version='1.7|1.8']"); - } - { - MatchSpec ms("conda-forge/linux64::xtensor==0.12.3", ctx, channel_context); - CHECK_EQ(ms.version, "0.12.3"); - CHECK_EQ(ms.name, "xtensor"); - CHECK_EQ(ms.channel, "conda-forge/linux64"); - CHECK_EQ(ms.optional, false); - } - { - MatchSpec ms("conda-forge::foo[build=3](target=blarg,optional)", ctx, channel_context); - CHECK_EQ(ms.version, ""); - CHECK_EQ(ms.name, "foo"); - CHECK_EQ(ms.channel, "conda-forge"); - CHECK_EQ(ms.brackets["build"], "3"); - CHECK_EQ(ms.parens["target"], "blarg"); - CHECK_EQ(ms.optional, true); - } - { - MatchSpec ms("python[build_number=3]", ctx, channel_context); - CHECK_EQ(ms.name, "python"); - CHECK_EQ(ms.brackets["build_number"], "3"); - CHECK_EQ(ms.build_number, "3"); - } - { - MatchSpec ms("python[build_number='<=3']", ctx, channel_context); - CHECK_EQ(ms.name, "python"); - CHECK_EQ(ms.brackets["build_number"], "<=3"); - CHECK_EQ(ms.build_number, "<=3"); - } - { - MatchSpec ms( - "https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2", - ctx, - channel_context - ); - CHECK_EQ(ms.name, "_libgcc_mutex"); - CHECK_EQ(ms.version, "0.1"); - CHECK_EQ(ms.build_string, "conda_forge"); - CHECK_EQ( - ms.url, - "https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" - ); - CHECK_EQ(ms.fn, "_libgcc_mutex-0.1-conda_forge.tar.bz2"); - } - { - MatchSpec ms( - "/home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2", - ctx, - channel_context - ); - CHECK_EQ(ms.name, "_libgcc_mutex"); - CHECK_EQ(ms.version, "0.1"); - CHECK_EQ(ms.build_string, "conda_forge"); -#ifdef _WIN32 - std::string driveletter = fs::absolute(fs::u8path("/")).string().substr(0, 1); - CHECK_EQ( - ms.url, - std::string("file://") + driveletter - + ":/home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" - ); -#else - CHECK_EQ( - ms.url, - "file:///home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" - ); -#endif - CHECK_EQ(ms.fn, "_libgcc_mutex-0.1-conda_forge.tar.bz2"); - } - { - MatchSpec ms( - "xtensor[url=file:///home/wolfv/Downloads/" - "xtensor-0.21.4-hc9558a2_0.tar.bz2]", - ctx, - channel_context - ); - CHECK_EQ(ms.name, "xtensor"); - CHECK_EQ( - ms.brackets["url"], - "file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2" - ); - CHECK_EQ(ms.url, "file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2"); - } - { - MatchSpec ms("foo=1.0=2", ctx, channel_context); - CHECK_EQ(ms.conda_build_form(), "foo 1.0 2"); - CHECK_EQ(ms.str(), "foo==1.0=2"); - } - { - MatchSpec ms( - "foo=1.0=2[md5=123123123, license=BSD-3, fn='test 123.tar.bz2']", - ctx, - channel_context - ); - CHECK_EQ(ms.conda_build_form(), "foo 1.0 2"); - CHECK_EQ(ms.str(), "foo==1.0=2[md5=123123123,license=BSD-3,fn='test 123.tar.bz2']"); - } - { - MatchSpec ms( - "foo=1.0=2[md5=123123123, license=BSD-3, fn='test 123.tar.bz2', url='abcdef']", - ctx, - channel_context - ); - CHECK_EQ(ms.conda_build_form(), "foo 1.0 2"); - CHECK_EQ(ms.str(), "foo==1.0=2[url=abcdef,md5=123123123,license=BSD-3]"); - } - { - MatchSpec ms("libblas=*=*mkl", ctx, channel_context); - CHECK_EQ(ms.conda_build_form(), "libblas * *mkl"); - // CHECK_EQ(ms.str(), "foo==1.0=2"); - } - { - MatchSpec ms("libblas=0.15*", ctx, channel_context); - CHECK_EQ(ms.conda_build_form(), "libblas 0.15*"); - } - { - MatchSpec ms("xtensor =0.15*", ctx, channel_context); - CHECK_EQ(ms.conda_build_form(), "xtensor 0.15*"); - CHECK_EQ(ms.str(), "xtensor=0.15"); - } - { - MatchSpec ms("numpy=1.20", ctx, channel_context); - CHECK_EQ(ms.str(), "numpy=1.20"); - } - - { - MatchSpec ms("conda-forge::tzdata", ctx, channel_context); - CHECK_EQ(ms.str(), "conda-forge::tzdata"); - } - { - MatchSpec ms("conda-forge::noarch/tzdata", ctx, channel_context); - CHECK_EQ(ms.str(), "conda-forge::noarch/tzdata"); - } - { - MatchSpec ms("pkgs/main::tzdata", ctx, channel_context); - CHECK_EQ(ms.str(), "pkgs/main::tzdata"); - } - { - MatchSpec ms("pkgs/main/noarch::tzdata", ctx, channel_context); - CHECK_EQ(ms.str(), "pkgs/main/noarch::tzdata"); - } - { - MatchSpec ms("conda-forge/noarch::tzdata[subdir=linux64]", ctx, channel_context); - CHECK_EQ(ms.str(), "conda-forge/noarch::tzdata"); - } - { - MatchSpec ms("conda-forge::tzdata[subdir=linux64]", ctx, channel_context); - CHECK_EQ(ms.str(), "conda-forge/linux64::tzdata"); - } - } - - TEST_CASE("is_simple") - { - auto& ctx = mambatests::context(); - auto channel_context = ChannelContext::make_conda_compatible(ctx); - { - MatchSpec ms("libblas", ctx, channel_context); - CHECK(ms.is_simple()); - } - { - MatchSpec ms("libblas=12.9=abcdef", ctx, channel_context); - CHECK_FALSE(ms.is_simple()); - } - { - MatchSpec ms("libblas=0.15*", ctx, channel_context); - CHECK_FALSE(ms.is_simple()); - } - { - MatchSpec ms("libblas[version=12.2]", ctx, channel_context); - CHECK_FALSE(ms.is_simple()); - } - { - MatchSpec ms("xtensor =0.15*", ctx, channel_context); - CHECK_FALSE(ms.is_simple()); - } - } - } - TEST_SUITE("history") { TEST_CASE("user_request") diff --git a/libmamba/tests/src/core/test_match_spec.cpp b/libmamba/tests/src/core/test_match_spec.cpp new file mode 100644 index 0000000000..11d1a1510b --- /dev/null +++ b/libmamba/tests/src/core/test_match_spec.cpp @@ -0,0 +1,276 @@ +// Copyright (c) 2023, QuantStack and Mamba Contributors +// +// Distributed under the terms of the BSD 3-Clause License. +// +// The full license is in the file LICENSE, distributed with this software. + +#include + +#include "mamba/core/channel_context.hpp" +#include "mamba/core/match_spec.hpp" + +#include "mambatests.hpp" + +using namespace mamba; + +TEST_SUITE("MatchSpec") +{ + TEST_CASE("parse_version_build") + { + std::string v, b; + // >>> _parse_version_plus_build("=1.2.3 0") + // ('=1.2.3', '0') + // >>> _parse_version_plus_build("1.2.3=0") + // ('1.2.3', '0') + // >>> _parse_version_plus_build(">=1.0 , < 2.0 py34_0") + // ('>=1.0,<2.0', 'py34_0') + // >>> _parse_version_plus_build(">=1.0 , < 2.0 =py34_0") + // ('>=1.0,<2.0', 'py34_0') + // >>> _parse_version_plus_build("=1.2.3 ") + // ('=1.2.3', None) + // >>> _parse_version_plus_build(">1.8,<2|==1.7") + // ('>1.8,<2|==1.7', None) + // >>> _parse_version_plus_build("* openblas_0") + // ('*', 'openblas_0') + // >>> _parse_version_plus_build("* *") + // ('*', '*') + std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3 0"); + CHECK_EQ(v, "=1.2.3"); + CHECK_EQ(b, "0"); + std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3=0"); + CHECK_EQ(v, "=1.2.3"); + CHECK_EQ(b, "0"); + std::tie(v, b) = MatchSpec::parse_version_and_build(">=1.0 , < 2.0 py34_0"); + CHECK_EQ(v, ">=1.0,<2.0"); + CHECK_EQ(b, "py34_0"); + std::tie(v, b) = MatchSpec::parse_version_and_build(">=1.0 , < 2.0 =py34_0"); + CHECK_EQ(v, ">=1.0,<2.0"); + CHECK_EQ(b, "py34_0"); + std::tie(v, b) = MatchSpec::parse_version_and_build("=1.2.3 "); + CHECK_EQ(v, "=1.2.3"); + CHECK_EQ(b, ""); + std::tie(v, b) = MatchSpec::parse_version_and_build(">1.8,<2|==1.7"); + CHECK_EQ(v, ">1.8,<2|==1.7"); + CHECK_EQ(b, ""); + std::tie(v, b) = MatchSpec::parse_version_and_build("* openblas_0"); + CHECK_EQ(v, "*"); + CHECK_EQ(b, "openblas_0"); + std::tie(v, b) = MatchSpec::parse_version_and_build("* *"); + CHECK_EQ(v, "*"); + CHECK_EQ(b, "*"); + } + + TEST_CASE("parse") + { + auto& ctx = mambatests::context(); + auto channel_context = ChannelContext::make_conda_compatible(ctx); + { + MatchSpec ms("xtensor==0.12.3", ctx, channel_context); + CHECK_EQ(ms.version, "0.12.3"); + CHECK_EQ(ms.name, "xtensor"); + } + { + MatchSpec ms("", ctx, channel_context); + CHECK_EQ(ms.version, ""); + CHECK_EQ(ms.name, ""); + } + { + MatchSpec ms("ipykernel", ctx, channel_context); + CHECK_EQ(ms.version, ""); + CHECK_EQ(ms.name, "ipykernel"); + } + { + MatchSpec ms("ipykernel ", ctx, channel_context); + CHECK_EQ(ms.version, ""); + CHECK_EQ(ms.name, "ipykernel"); + } + { + MatchSpec ms("numpy 1.7*", ctx, channel_context); + CHECK_EQ(ms.version, "1.7*"); + CHECK_EQ(ms.name, "numpy"); + CHECK_EQ(ms.conda_build_form(), "numpy 1.7*"); + CHECK_EQ(ms.str(), "numpy=1.7"); + } + { + MatchSpec ms("numpy[version='1.7|1.8']", ctx, channel_context); + // TODO! + // CHECK_EQ(ms.version, "1.7|1.8"); + CHECK_EQ(ms.name, "numpy"); + CHECK_EQ(ms.brackets["version"], "1.7|1.8"); + CHECK_EQ(ms.str(), "numpy[version='1.7|1.8']"); + } + { + MatchSpec ms("conda-forge/linux64::xtensor==0.12.3", ctx, channel_context); + CHECK_EQ(ms.version, "0.12.3"); + CHECK_EQ(ms.name, "xtensor"); + CHECK_EQ(ms.channel, "conda-forge/linux64"); + CHECK_EQ(ms.optional, false); + } + { + MatchSpec ms("conda-forge::foo[build=3](target=blarg,optional)", ctx, channel_context); + CHECK_EQ(ms.version, ""); + CHECK_EQ(ms.name, "foo"); + CHECK_EQ(ms.channel, "conda-forge"); + CHECK_EQ(ms.brackets["build"], "3"); + CHECK_EQ(ms.parens["target"], "blarg"); + CHECK_EQ(ms.optional, true); + } + { + MatchSpec ms("python[build_number=3]", ctx, channel_context); + CHECK_EQ(ms.name, "python"); + CHECK_EQ(ms.brackets["build_number"], "3"); + CHECK_EQ(ms.build_number, "3"); + } + { + MatchSpec ms("python[build_number='<=3']", ctx, channel_context); + CHECK_EQ(ms.name, "python"); + CHECK_EQ(ms.brackets["build_number"], "<=3"); + CHECK_EQ(ms.build_number, "<=3"); + } + { + MatchSpec ms( + "https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2", + ctx, + channel_context + ); + CHECK_EQ(ms.name, "_libgcc_mutex"); + CHECK_EQ(ms.version, "0.1"); + CHECK_EQ(ms.build_string, "conda_forge"); + CHECK_EQ( + ms.url, + "https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" + ); + CHECK_EQ(ms.fn, "_libgcc_mutex-0.1-conda_forge.tar.bz2"); + } + { + MatchSpec ms( + "/home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2", + ctx, + channel_context + ); + CHECK_EQ(ms.name, "_libgcc_mutex"); + CHECK_EQ(ms.version, "0.1"); + CHECK_EQ(ms.build_string, "conda_forge"); +#ifdef _WIN32 + std::string driveletter = fs::absolute(fs::u8path("/")).string().substr(0, 1); + CHECK_EQ( + ms.url, + std::string("file://") + driveletter + + ":/home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" + ); +#else + CHECK_EQ( + ms.url, + "file:///home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2" + ); +#endif + CHECK_EQ(ms.fn, "_libgcc_mutex-0.1-conda_forge.tar.bz2"); + } + { + MatchSpec ms( + "xtensor[url=file:///home/wolfv/Downloads/" + "xtensor-0.21.4-hc9558a2_0.tar.bz2]", + ctx, + channel_context + ); + CHECK_EQ(ms.name, "xtensor"); + CHECK_EQ( + ms.brackets["url"], + "file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2" + ); + CHECK_EQ(ms.url, "file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2"); + } + { + MatchSpec ms("foo=1.0=2", ctx, channel_context); + CHECK_EQ(ms.conda_build_form(), "foo 1.0 2"); + CHECK_EQ(ms.str(), "foo==1.0=2"); + } + { + MatchSpec ms( + "foo=1.0=2[md5=123123123, license=BSD-3, fn='test 123.tar.bz2']", + ctx, + channel_context + ); + CHECK_EQ(ms.conda_build_form(), "foo 1.0 2"); + CHECK_EQ(ms.str(), "foo==1.0=2[md5=123123123,license=BSD-3,fn='test 123.tar.bz2']"); + } + { + MatchSpec ms( + "foo=1.0=2[md5=123123123, license=BSD-3, fn='test 123.tar.bz2', url='abcdef']", + ctx, + channel_context + ); + CHECK_EQ(ms.conda_build_form(), "foo 1.0 2"); + CHECK_EQ(ms.str(), "foo==1.0=2[url=abcdef,md5=123123123,license=BSD-3]"); + } + { + MatchSpec ms("libblas=*=*mkl", ctx, channel_context); + CHECK_EQ(ms.conda_build_form(), "libblas * *mkl"); + // CHECK_EQ(ms.str(), "foo==1.0=2"); + } + { + MatchSpec ms("libblas=0.15*", ctx, channel_context); + CHECK_EQ(ms.conda_build_form(), "libblas 0.15*"); + } + { + MatchSpec ms("xtensor =0.15*", ctx, channel_context); + CHECK_EQ(ms.conda_build_form(), "xtensor 0.15*"); + CHECK_EQ(ms.str(), "xtensor=0.15"); + } + { + MatchSpec ms("numpy=1.20", ctx, channel_context); + CHECK_EQ(ms.str(), "numpy=1.20"); + } + + { + MatchSpec ms("conda-forge::tzdata", ctx, channel_context); + CHECK_EQ(ms.str(), "conda-forge::tzdata"); + } + { + MatchSpec ms("conda-forge::noarch/tzdata", ctx, channel_context); + CHECK_EQ(ms.str(), "conda-forge::noarch/tzdata"); + } + { + MatchSpec ms("pkgs/main::tzdata", ctx, channel_context); + CHECK_EQ(ms.str(), "pkgs/main::tzdata"); + } + { + MatchSpec ms("pkgs/main/noarch::tzdata", ctx, channel_context); + CHECK_EQ(ms.str(), "pkgs/main/noarch::tzdata"); + } + { + MatchSpec ms("conda-forge/noarch::tzdata[subdir=linux64]", ctx, channel_context); + CHECK_EQ(ms.str(), "conda-forge/noarch::tzdata"); + } + { + MatchSpec ms("conda-forge::tzdata[subdir=linux64]", ctx, channel_context); + CHECK_EQ(ms.str(), "conda-forge/linux64::tzdata"); + } + } + + TEST_CASE("is_simple") + { + auto& ctx = mambatests::context(); + auto channel_context = ChannelContext::make_conda_compatible(ctx); + { + MatchSpec ms("libblas", ctx, channel_context); + CHECK(ms.is_simple()); + } + { + MatchSpec ms("libblas=12.9=abcdef", ctx, channel_context); + CHECK_FALSE(ms.is_simple()); + } + { + MatchSpec ms("libblas=0.15*", ctx, channel_context); + CHECK_FALSE(ms.is_simple()); + } + { + MatchSpec ms("libblas[version=12.2]", ctx, channel_context); + CHECK_FALSE(ms.is_simple()); + } + { + MatchSpec ms("xtensor =0.15*", ctx, channel_context); + CHECK_FALSE(ms.is_simple()); + } + } +} diff --git a/libmamba/tests/src/specs/test_channel_spec.cpp b/libmamba/tests/src/specs/test_channel_spec.cpp index 3fe6a26e25..c2bd010bf0 100644 --- a/libmamba/tests/src/specs/test_channel_spec.cpp +++ b/libmamba/tests/src/specs/test_channel_spec.cpp @@ -14,6 +14,9 @@ using namespace mamba::specs; TEST_SUITE("specs::channel_spec") { + using PlatformSet = typename util::flat_set; + using Type = typename ChannelSpec::Type; + TEST_CASE("Constructor") { SUBCASE("Default") @@ -29,15 +32,12 @@ TEST_SUITE("specs::channel_spec") const auto spec = ChannelSpec("hello", { "linux-78" }, ChannelSpec::Type::Unknown); CHECK_EQ(spec.type(), ChannelSpec::Type::Unknown); CHECK_EQ(spec.location(), ""); - CHECK(spec.platform_filters().empty()); + CHECK_EQ(spec.platform_filters(), PlatformSet{ "linux-78" }); } } TEST_CASE("Parsing") { - using Type = typename ChannelSpec::Type; - using PlatformSet = typename util::flat_set; - SUBCASE("Invalid channels") { for (std::string_view str : { "", "", ":///", "none" }) @@ -220,4 +220,13 @@ TEST_SUITE("specs::channel_spec") CHECK_EQ(spec.platform_filters(), PlatformSet{ "linux-64" }); } } + + TEST_CASE("str") + { + CHECK_EQ(ChannelSpec("location", {}, Type::Name).str(), "location"); + CHECK_EQ( + ChannelSpec("location", { "linux-64", "noarch" }, Type::Name).str(), + "location[linux-64,noarch]" + ); + } } diff --git a/libmambapy/src/libmambapy/bindings/legacy.cpp b/libmambapy/src/libmambapy/bindings/legacy.cpp index d0c69b6785..07706f2584 100644 --- a/libmambapy/src/libmambapy/bindings/legacy.cpp +++ b/libmambapy/src/libmambapy/bindings/legacy.cpp @@ -714,7 +714,8 @@ bind_submodule_impl(pybind11::module_ m) py::arg("params"), py::arg("has_zst") ) - .def("make_channel", &ChannelContext::make_channel) + .def("make_channel", py::overload_cast(&ChannelContext::make_channel)) + .def("make_channel", py::overload_cast(&ChannelContext::make_channel)) .def("params", &ChannelContext::params) .def("has_zst", &ChannelContext::has_zst);