diff --git a/libmamba/include/mamba/specs/channel_spec.hpp b/libmamba/include/mamba/specs/channel_spec.hpp index a9ab747d03..f73ed5913c 100644 --- a/libmamba/include/mamba/specs/channel_spec.hpp +++ b/libmamba/include/mamba/specs/channel_spec.hpp @@ -7,6 +7,7 @@ #ifndef MAMBA_SPECS_CHANNEL_SPEC_HPP #define MAMBA_SPECS_CHANNEL_SPEC_HPP +#include #include #include @@ -63,10 +64,22 @@ namespace mamba::specs * Example "conda-forge", "locals", "my-channel/my-label". */ Name, + /** + * An unknown channel source. + * + * It is currently unclear why it is needed. + */ + Unknown, }; - static constexpr std::string_view default_name = "defaults"; static constexpr std::string_view platform_separators = "|,;"; + static constexpr std::string_view unknown_channel = ""; + static constexpr std::array invalid_channels_lower = { + "", + "none:///", + "none", + ":///", + }; using dynamic_platform_set = util::flat_set; @@ -87,9 +100,9 @@ namespace mamba::specs private: - std::string m_location = std::string(default_name); + std::string m_location = std::string(unknown_channel); dynamic_platform_set m_platform_filters = {}; - Type m_type = {}; + Type m_type = Type::Unknown; }; } #endif diff --git a/libmamba/src/core/channel.cpp b/libmamba/src/core/channel.cpp index 9cf51acffb..6c03a744e4 100644 --- a/libmamba/src/core/channel.cpp +++ b/libmamba/src/core/channel.cpp @@ -373,6 +373,10 @@ namespace mamba { return resolve_name(std::move(spec), params); } + case specs::ChannelSpec::Type::Unknown: + { + return Channel(specs::CondaURL{}, spec.clear_location()); + } } throw std::invalid_argument("Invalid ChannelSpec::Type"); } diff --git a/libmamba/src/specs/channel_spec.cpp b/libmamba/src/specs/channel_spec.cpp index c9539dfc25..93f2c0179a 100644 --- a/libmamba/src/specs/channel_spec.cpp +++ b/libmamba/src/specs/channel_spec.cpp @@ -4,7 +4,9 @@ // // The full license is in the file LICENSE, distributed with this software. +#include #include +#include #include #include #include @@ -108,14 +110,24 @@ namespace mamba::specs out = util::rstrip(out, '/'); return out; } + + auto is_unknown_channel(std::string_view str) -> bool + { + auto it = std::find( + ChannelSpec::invalid_channels_lower.cbegin(), + ChannelSpec::invalid_channels_lower.cend(), + util::to_lower(str) + ); + return str.empty() || (it != ChannelSpec::invalid_channels_lower.cend()); + } } auto ChannelSpec::parse(std::string_view str) -> ChannelSpec { str = util::strip(str); - if (str.empty()) + if (is_unknown_channel(str)) { - return {}; + return { std::string(unknown_channel), {}, Type::Unknown }; } auto [location, filters] = split_location_platform(str); @@ -148,9 +160,17 @@ namespace mamba::specs , m_platform_filters(std::move(filters)) , m_type(type) { + if (m_type == Type::Unknown) + { + m_location = unknown_channel; + m_platform_filters = {}; + } if (m_location.empty()) { - m_location = std::string(default_name); + throw std::invalid_argument( // + "Cannot channel with empty location, " + "use unknown type instead." + ); } } diff --git a/libmamba/tests/src/specs/test_channel_spec.cpp b/libmamba/tests/src/specs/test_channel_spec.cpp index 144fb23274..3fe6a26e25 100644 --- a/libmamba/tests/src/specs/test_channel_spec.cpp +++ b/libmamba/tests/src/specs/test_channel_spec.cpp @@ -6,22 +6,50 @@ #include -#include "mamba/fs/filesystem.hpp" #include "mamba/specs/channel_spec.hpp" #include "mamba/util/build.hpp" -#include "mamba/util/path_manip.hpp" -#include "mamba/util/string.hpp" using namespace mamba; using namespace mamba::specs; TEST_SUITE("specs::channel_spec") { + TEST_CASE("Constructor") + { + SUBCASE("Default") + { + const auto spec = ChannelSpec(); + CHECK_EQ(spec.type(), ChannelSpec::Type::Unknown); + CHECK_EQ(spec.location(), ""); + CHECK(spec.platform_filters().empty()); + } + + SUBCASE("Unknown") + { + 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()); + } + } + TEST_CASE("Parsing") { using Type = typename ChannelSpec::Type; using PlatformSet = typename util::flat_set; + SUBCASE("Invalid channels") + { + for (std::string_view str : { "", "", ":///", "none" }) + { + CAPTURE(str); + const auto spec = ChannelSpec::parse(str); + CHECK_EQ(spec.type(), Type::Unknown); + CHECK_EQ(spec.location(), ""); + CHECK_EQ(spec.platform_filters(), PlatformSet{}); + } + } + SUBCASE("https://repo.anaconda.com/conda-forge") { const auto spec = ChannelSpec::parse("https://repo.anaconda.com/conda-forge");