mirror of https://github.com/mamba-org/mamba.git
Migrate Channel::make_channel to resolve multi channels (#2986)
* Add one to many get_channels * Refactor ChannelContext params * ChannelContext::make_channel migration 1 * ChannelContext::make_channel migration 2 * ChannelContext::make_channel migration 3 * ChannelContext::make_channel migration 4 * ChannelContext::make_channel migration 5 * ChannelContext::make_channel migration 6 * ChannelContext::make_channel migration 7 * Remove Channel bindings * Remove ChannelContext::make_channel * ChannelContext::get_channels migration 1 * ChannelContext::get_channels migration 2 * ChannelContext::get_channels migration 3 * Remove get_channels bindings * Remove ChannelContext::get_channels * Channel::resolve return a list * Resolve multi_channel in Channel::resolve * Use weakening map for multi_channels * Split Channel resolve_name * Cleanup signatures * Add Channel::clear_xxx * Force removal of trailing '/' in Channel * Add weak channel comparison * Use better channel comparisons * Remove Channel::base_url * Rename Channel::make_chan > make_channel * Add doc * Resolve Channel paths from params * Review from JohanMabille * Fix absolute path
This commit is contained in:
parent
0177c44383
commit
e874e7ea71
|
@ -55,40 +55,55 @@ namespace mamba
|
||||||
-> std::optional<std::string_view>;
|
-> std::optional<std::string_view>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Key, typename Value>
|
||||||
|
using name_map = util::weakening_map<std::unordered_map<Key, Value>, NameWeakener>;
|
||||||
|
|
||||||
using platform_list = util::flat_set<std::string>;
|
using platform_list = util::flat_set<std::string>;
|
||||||
using channel_list = std::vector<Channel>;
|
using channel_list = std::vector<Channel>;
|
||||||
using channel_map = util::weakening_map<std::unordered_map<std::string, Channel>, NameWeakener>;
|
using channel_map = name_map<std::string, Channel>;
|
||||||
using multichannel_map = std::unordered_map<std::string, channel_list>;
|
using multichannel_map = name_map<std::string, channel_list>;
|
||||||
|
|
||||||
const platform_list& platforms;
|
const platform_list& platforms;
|
||||||
const specs::CondaURL& channel_alias;
|
const specs::CondaURL& channel_alias;
|
||||||
const channel_map& custom_channels;
|
const channel_map& custom_channels;
|
||||||
const specs::AuthenticationDataBase& auth_db;
|
const multichannel_map& custom_multichannels;
|
||||||
|
const specs::AuthenticationDataBase& authentication_db;
|
||||||
// TODO add CWD and home
|
std::string_view home_dir;
|
||||||
|
std::string_view current_working_dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
using platform_list = util::flat_set<std::string>;
|
using platform_list = ResolveParams::platform_list;
|
||||||
|
using channel_list = ResolveParams::channel_list;
|
||||||
|
|
||||||
[[nodiscard]] static auto resolve(specs::ChannelSpec spec, ResolveParams params) -> Channel;
|
[[nodiscard]] static auto resolve(specs::ChannelSpec spec, ResolveParams params)
|
||||||
|
-> channel_list;
|
||||||
|
|
||||||
Channel(specs::CondaURL url, std::string display_name, util::flat_set<std::string> platforms = {});
|
Channel(specs::CondaURL url, std::string display_name, util::flat_set<std::string> platforms = {});
|
||||||
|
|
||||||
[[nodiscard]] auto url() const -> const specs::CondaURL&;
|
[[nodiscard]] auto url() const -> const specs::CondaURL&;
|
||||||
|
auto clear_url() -> const specs::CondaURL;
|
||||||
void set_url(specs::CondaURL url);
|
void set_url(specs::CondaURL url);
|
||||||
|
|
||||||
[[nodiscard]] auto platforms() const -> const platform_list&;
|
[[nodiscard]] auto platforms() const -> const platform_list&;
|
||||||
|
auto clear_platforms() -> platform_list;
|
||||||
void set_platforms(platform_list platforms);
|
void set_platforms(platform_list platforms);
|
||||||
|
|
||||||
[[nodiscard]] auto display_name() const -> const std::string&;
|
[[nodiscard]] auto display_name() const -> const std::string&;
|
||||||
|
auto clear_display_name() -> std::string;
|
||||||
void set_display_name(std::string display_name);
|
void set_display_name(std::string display_name);
|
||||||
|
|
||||||
std::string base_url() const;
|
[[nodiscard]] auto url_equivalent_with(const Channel& other) const -> bool;
|
||||||
std::string platform_url(std::string_view platform, bool with_credential = true) const;
|
|
||||||
|
[[nodiscard]] auto is_equivalent_to(const Channel& other) const -> bool;
|
||||||
|
|
||||||
|
[[nodiscard]] auto contains_equivalent(const Channel& other) const -> bool;
|
||||||
|
|
||||||
|
[[nodiscard]] auto
|
||||||
|
platform_url(std::string_view platform, bool with_credential = true) const -> std::string;
|
||||||
// The pairs consist of (platform,url)
|
// The pairs consist of (platform,url)
|
||||||
util::flat_set<std::pair<std::string, std::string>>
|
[[nodiscard]] auto platform_urls(bool with_credential = true) const
|
||||||
platform_urls(bool with_credential = true) const;
|
-> util::flat_set<std::pair<std::string, std::string>>;
|
||||||
util::flat_set<std::string> urls(bool with_credential = true) const;
|
[[nodiscard]] auto urls(bool with_credential = true) const -> util::flat_set<std::string>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -118,40 +133,42 @@ namespace mamba
|
||||||
|
|
||||||
using channel_map = Channel::ResolveParams::channel_map;
|
using channel_map = Channel::ResolveParams::channel_map;
|
||||||
using channel_list = Channel::ResolveParams::channel_list;
|
using channel_list = Channel::ResolveParams::channel_list;
|
||||||
|
using multichannel_map = Channel::ResolveParams::multichannel_map;
|
||||||
using platform_list = Channel::ResolveParams::platform_list;
|
using platform_list = Channel::ResolveParams::platform_list;
|
||||||
using multichannel_map = std::unordered_map<std::string, channel_list>;
|
|
||||||
|
|
||||||
ChannelContext(Context& context);
|
ChannelContext(Context& context);
|
||||||
~ChannelContext();
|
~ChannelContext();
|
||||||
|
|
||||||
ChannelContext(const ChannelContext&) = delete;
|
ChannelContext(const ChannelContext&) = delete;
|
||||||
ChannelContext& operator=(const ChannelContext&) = delete;
|
auto operator=(const ChannelContext&) -> ChannelContext& = delete;
|
||||||
ChannelContext(ChannelContext&&) = delete;
|
ChannelContext(ChannelContext&&) = delete;
|
||||||
ChannelContext& operator=(ChannelContext&&) = delete;
|
auto operator=(ChannelContext&&) -> ChannelContext& = delete;
|
||||||
|
|
||||||
const Channel& make_channel(const std::string& value);
|
auto make_channel(std::string_view name) -> channel_list;
|
||||||
auto get_channels(const std::vector<std::string>& channel_names) -> channel_list;
|
|
||||||
|
|
||||||
const specs::CondaURL& get_channel_alias() const;
|
auto get_channel_alias() const -> const specs::CondaURL&;
|
||||||
const channel_map& get_custom_channels() const;
|
auto get_custom_channels() const -> const channel_map&;
|
||||||
const multichannel_map& get_custom_multichannels() const;
|
auto get_custom_multichannels() const -> const multichannel_map&;
|
||||||
|
|
||||||
Context& context() const
|
auto context() const -> Context&
|
||||||
{
|
{
|
||||||
return m_context;
|
return m_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
using ChannelCache = std::map<std::string, Channel>;
|
using ChannelCache = std::unordered_map<std::string, channel_list>;
|
||||||
|
|
||||||
Context& m_context;
|
Context& m_context;
|
||||||
ChannelCache m_channel_cache;
|
ChannelCache m_channel_cache;
|
||||||
specs::CondaURL m_channel_alias;
|
specs::CondaURL m_channel_alias;
|
||||||
platform_list m_platforms;
|
|
||||||
channel_map m_custom_channels;
|
channel_map m_custom_channels;
|
||||||
multichannel_map m_custom_multichannels;
|
multichannel_map m_custom_multichannels;
|
||||||
|
platform_list m_platforms;
|
||||||
|
std::string m_home_dir;
|
||||||
|
std::string m_current_working_dir;
|
||||||
|
|
||||||
|
auto params() -> Channel::ResolveParams;
|
||||||
void init_custom_channels();
|
void init_custom_channels();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,16 @@
|
||||||
|
|
||||||
namespace mamba::util
|
namespace mamba::util
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Lightweight file path manipulation.
|
||||||
|
*
|
||||||
|
* The purpose of this file is to provide a lightweight functions for manipulating paths
|
||||||
|
* for things that manipulate "path-like" objects, such as parsers and URLs.
|
||||||
|
* In general, users should prefer using the correct abstraction, such as @ref URL
|
||||||
|
* and @ref u8path.
|
||||||
|
* However some features provided here, such as @ref expand_home, are not available elsewhere.
|
||||||
|
*/
|
||||||
|
|
||||||
inline static constexpr char preferred_path_separator_posix = '/';
|
inline static constexpr char preferred_path_separator_posix = '/';
|
||||||
inline static constexpr char preferred_path_separator_win = '\\';
|
inline static constexpr char preferred_path_separator_win = '\\';
|
||||||
|
|
||||||
|
|
|
@ -51,50 +51,51 @@ namespace mamba
|
||||||
|
|
||||||
auto& ctx = pool.context();
|
auto& ctx = pool.context();
|
||||||
|
|
||||||
std::vector<std::string> channel_urls = ctx.channels;
|
|
||||||
|
|
||||||
std::vector<MSubdirData> subdirs;
|
std::vector<MSubdirData> subdirs;
|
||||||
|
|
||||||
std::vector<std::pair<int, int>> priorities;
|
std::vector<std::pair<int, int>> priorities;
|
||||||
int max_prio = static_cast<int>(channel_urls.size());
|
int max_prio = static_cast<int>(ctx.channels.size());
|
||||||
auto prev_channel_url = specs::CondaURL();
|
auto prev_channel_url = specs::CondaURL();
|
||||||
|
|
||||||
Console::instance().init_progress_bar_manager(ProgressBarMode::multi);
|
Console::instance().init_progress_bar_manager(ProgressBarMode::multi);
|
||||||
|
|
||||||
std::vector<mamba_error> error_list;
|
std::vector<mamba_error> error_list;
|
||||||
|
|
||||||
for (auto channel : pool.channel_context().get_channels(channel_urls))
|
for (const auto& location : ctx.channels)
|
||||||
{
|
{
|
||||||
for (auto& [platform, url] : channel.platform_urls(true))
|
for (auto channel : pool.channel_context().make_channel(location))
|
||||||
{
|
{
|
||||||
auto sdires = MSubdirData::create(
|
for (auto& [platform, url] : channel.platform_urls(true))
|
||||||
pool.channel_context(),
|
|
||||||
channel,
|
|
||||||
platform,
|
|
||||||
url,
|
|
||||||
package_caches,
|
|
||||||
"repodata.json"
|
|
||||||
);
|
|
||||||
if (!sdires.has_value())
|
|
||||||
{
|
{
|
||||||
error_list.push_back(std::move(sdires).error());
|
auto sdires = MSubdirData::create(
|
||||||
continue;
|
pool.channel_context(),
|
||||||
}
|
channel,
|
||||||
auto sdir = std::move(sdires).value();
|
platform,
|
||||||
subdirs.push_back(std::move(sdir));
|
url,
|
||||||
if (ctx.channel_priority == ChannelPriority::Disabled)
|
package_caches,
|
||||||
{
|
"repodata.json"
|
||||||
priorities.push_back(std::make_pair(0, 0));
|
);
|
||||||
}
|
if (!sdires.has_value())
|
||||||
else
|
|
||||||
{
|
|
||||||
// Consider 'flexible' and 'strict' the same way
|
|
||||||
if (channel.url() != prev_channel_url)
|
|
||||||
{
|
{
|
||||||
max_prio--;
|
error_list.push_back(std::move(sdires).error());
|
||||||
prev_channel_url = channel.url();
|
continue;
|
||||||
|
}
|
||||||
|
auto sdir = std::move(sdires).value();
|
||||||
|
subdirs.push_back(std::move(sdir));
|
||||||
|
if (ctx.channel_priority == ChannelPriority::Disabled)
|
||||||
|
{
|
||||||
|
priorities.push_back(std::make_pair(0, 0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Consider 'flexible' and 'strict' the same way
|
||||||
|
if (channel.url() != prev_channel_url)
|
||||||
|
{
|
||||||
|
max_prio--;
|
||||||
|
prev_channel_url = channel.url();
|
||||||
|
}
|
||||||
|
priorities.push_back(std::make_pair(max_prio, 0));
|
||||||
}
|
}
|
||||||
priorities.push_back(std::make_pair(max_prio, 0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,16 +160,17 @@ namespace mamba
|
||||||
}
|
}
|
||||||
items.push_back({ "virtual packages", virtual_pkgs });
|
items.push_back({ "virtual packages", virtual_pkgs });
|
||||||
|
|
||||||
std::vector<std::string> channels = ctx.channels;
|
|
||||||
// Always append context channels
|
// Always append context channels
|
||||||
auto& ctx_channels = ctx.channels;
|
|
||||||
std::copy(ctx_channels.begin(), ctx_channels.end(), std::back_inserter(channels));
|
|
||||||
std::vector<std::string> channel_urls;
|
std::vector<std::string> channel_urls;
|
||||||
for (auto channel : channel_context.get_channels(channels))
|
channel_urls.reserve(ctx.channels.size() * 2); // Lower bound * (platform + noarch)
|
||||||
|
for (const auto& loc : ctx.channels)
|
||||||
{
|
{
|
||||||
for (auto url : channel.urls(true))
|
for (auto channel : channel_context.make_channel(loc))
|
||||||
{
|
{
|
||||||
channel_urls.push_back(url);
|
for (auto url : channel.urls(true))
|
||||||
|
{
|
||||||
|
channel_urls.push_back(url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
items.push_back({ "channels", channel_urls });
|
items.push_back({ "channels", channel_urls });
|
||||||
|
|
|
@ -73,11 +73,13 @@ namespace mamba
|
||||||
|
|
||||||
if (regex.empty() || std::regex_search(pkg_info.name, spec_pat))
|
if (regex.empty() || std::regex_search(pkg_info.name, spec_pat))
|
||||||
{
|
{
|
||||||
auto& channel = channel_context.make_channel(pkg_info.url);
|
auto channels = channel_context.make_channel(pkg_info.url);
|
||||||
obj["base_url"] = channel.base_url();
|
assert(channels.size() == 1); // A URL can only resolve to one channel
|
||||||
|
obj["base_url"] = channels.front().url().str(specs::CondaURL::Credentials::Remove
|
||||||
|
);
|
||||||
obj["build_number"] = pkg_info.build_number;
|
obj["build_number"] = pkg_info.build_number;
|
||||||
obj["build_string"] = pkg_info.build_string;
|
obj["build_string"] = pkg_info.build_string;
|
||||||
obj["channel"] = channel.display_name();
|
obj["channel"] = channels.front().display_name();
|
||||||
obj["dist_name"] = pkg_info.str();
|
obj["dist_name"] = pkg_info.str();
|
||||||
obj["name"] = pkg_info.name;
|
obj["name"] = pkg_info.name;
|
||||||
obj["platform"] = pkg_info.subdir;
|
obj["platform"] = pkg_info.subdir;
|
||||||
|
@ -111,8 +113,9 @@ namespace mamba
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const Channel& channel = channel_context.make_channel(package.second.url);
|
auto channels = channel_context.make_channel(package.second.url);
|
||||||
formatted_pkgs.channel = channel.display_name();
|
assert(channels.size() == 1); // A URL can only resolve to one channel
|
||||||
|
formatted_pkgs.channel = channels.front().display_name();
|
||||||
}
|
}
|
||||||
packages.push_back(formatted_pkgs);
|
packages.push_back(formatted_pkgs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <unordered_set>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "mamba/core/channel.hpp"
|
#include "mamba/core/channel.hpp"
|
||||||
#include "mamba/core/context.hpp"
|
#include "mamba/core/context.hpp"
|
||||||
#include "mamba/specs/channel_spec.hpp"
|
#include "mamba/specs/channel_spec.hpp"
|
||||||
#include "mamba/specs/conda_url.hpp"
|
#include "mamba/specs/conda_url.hpp"
|
||||||
|
#include "mamba/util/environment.hpp"
|
||||||
#include "mamba/util/path_manip.hpp"
|
#include "mamba/util/path_manip.hpp"
|
||||||
#include "mamba/util/string.hpp"
|
#include "mamba/util/string.hpp"
|
||||||
#include "mamba/util/tuple_hash.hpp"
|
#include "mamba/util/tuple_hash.hpp"
|
||||||
|
@ -22,9 +22,9 @@
|
||||||
|
|
||||||
namespace mamba
|
namespace mamba
|
||||||
{
|
{
|
||||||
/********************************
|
/*********************************
|
||||||
* NameWeakener Implmentation *
|
* NameWeakener Implementation *
|
||||||
********************************/
|
*********************************/
|
||||||
|
|
||||||
auto Channel::ResolveParams::NameWeakener::make_first_key(std::string_view key) const
|
auto Channel::ResolveParams::NameWeakener::make_first_key(std::string_view key) const
|
||||||
-> std::string_view
|
-> std::string_view
|
||||||
|
@ -47,6 +47,9 @@ namespace mamba
|
||||||
, m_display_name(std::move(display_name))
|
, m_display_name(std::move(display_name))
|
||||||
, m_platforms(std::move(platforms))
|
, m_platforms(std::move(platforms))
|
||||||
{
|
{
|
||||||
|
auto p = m_url.clear_path();
|
||||||
|
p = util::rstrip(p, '/');
|
||||||
|
m_url.set_path(std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Channel::url() const -> const specs::CondaURL&
|
auto Channel::url() const -> const specs::CondaURL&
|
||||||
|
@ -54,6 +57,11 @@ namespace mamba
|
||||||
return m_url;
|
return m_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Channel::clear_url() -> const specs::CondaURL
|
||||||
|
{
|
||||||
|
return std::exchange(m_url, {});
|
||||||
|
}
|
||||||
|
|
||||||
void Channel::set_url(specs::CondaURL url)
|
void Channel::set_url(specs::CondaURL url)
|
||||||
{
|
{
|
||||||
m_url = std::move(url);
|
m_url = std::move(url);
|
||||||
|
@ -64,6 +72,11 @@ namespace mamba
|
||||||
return m_platforms;
|
return m_platforms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Channel::clear_platforms() -> platform_list
|
||||||
|
{
|
||||||
|
return std::exchange(m_platforms, {});
|
||||||
|
}
|
||||||
|
|
||||||
void Channel::set_platforms(platform_list platforms)
|
void Channel::set_platforms(platform_list platforms)
|
||||||
{
|
{
|
||||||
m_platforms = std::move(platforms);
|
m_platforms = std::move(platforms);
|
||||||
|
@ -74,17 +87,41 @@ namespace mamba
|
||||||
return m_display_name;
|
return m_display_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Channel::clear_display_name() -> std::string
|
||||||
|
{
|
||||||
|
return std::exchange(m_display_name, {});
|
||||||
|
}
|
||||||
|
|
||||||
void Channel::set_display_name(std::string display_name)
|
void Channel::set_display_name(std::string display_name)
|
||||||
{
|
{
|
||||||
m_display_name = std::move(display_name);
|
m_display_name = std::move(display_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Channel::base_url() const
|
auto Channel::url_equivalent_with(const Channel& other) const -> bool
|
||||||
{
|
{
|
||||||
return url().str(specs::CondaURL::Credentials::Remove);
|
using Decode = typename specs::CondaURL::Decode;
|
||||||
|
|
||||||
|
const auto& this_url = url();
|
||||||
|
const auto& other_url = other.url();
|
||||||
|
// Not checking users, passwords, and tokens
|
||||||
|
return
|
||||||
|
// Schemes
|
||||||
|
(this_url.scheme() == other_url.scheme())
|
||||||
|
// Hosts
|
||||||
|
&& (this_url.host(Decode::no) == other_url.host(Decode::no))
|
||||||
|
// Different ports are considered different channels
|
||||||
|
&& (this_url.port() == other_url.port())
|
||||||
|
// Removing potential trailing '/'
|
||||||
|
&& (util::rstrip(this_url.path_without_token(Decode::no), '/')
|
||||||
|
== util::rstrip(other_url.path_without_token(Decode::no), '/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
util::flat_set<std::string> Channel::urls(bool with_credential) const
|
auto Channel::contains_equivalent(const Channel& other) const -> bool
|
||||||
|
{
|
||||||
|
return url_equivalent_with(other) && util::set_is_superset_of(platforms(), other.platforms());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Channel::urls(bool with_credential) const -> util::flat_set<std::string>
|
||||||
{
|
{
|
||||||
if (!url().package().empty())
|
if (!url().package().empty())
|
||||||
{
|
{
|
||||||
|
@ -102,8 +139,8 @@ namespace mamba
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::flat_set<std::pair<std::string, std::string>>
|
auto Channel::platform_urls(bool with_credential) const
|
||||||
Channel::platform_urls(bool with_credential) const
|
-> util::flat_set<std::pair<std::string, std::string>>
|
||||||
{
|
{
|
||||||
if (!url().package().empty())
|
if (!url().package().empty())
|
||||||
{
|
{
|
||||||
|
@ -118,7 +155,7 @@ namespace mamba
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Channel::platform_url(std::string_view platform, bool with_credential) const
|
auto Channel::platform_url(std::string_view platform, bool with_credential) const -> std::string
|
||||||
{
|
{
|
||||||
auto cred = with_credential ? specs::CondaURL::Credentials::Show
|
auto cred = with_credential ? specs::CondaURL::Credentials::Show
|
||||||
: specs::CondaURL::Credentials::Remove;
|
: specs::CondaURL::Credentials::Remove;
|
||||||
|
@ -256,9 +293,25 @@ namespace mamba
|
||||||
return uri.pretty_str();
|
return uri.pretty_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto resolve_path_location(std::string location, Channel::ResolveParams params) -> std::string
|
||||||
|
{
|
||||||
|
if (util::url_has_scheme(location))
|
||||||
|
{
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto home = util::path_to_posix(std::string(params.home_dir));
|
||||||
|
auto path = fs::u8path(util::expand_home(location, home));
|
||||||
|
if (path.is_relative())
|
||||||
|
{
|
||||||
|
path = (fs::u8path(params.current_working_dir) / std::move(path)).lexically_normal();
|
||||||
|
}
|
||||||
|
return util::abs_path_to_url(std::move(path).string());
|
||||||
|
}
|
||||||
|
|
||||||
auto resolve_path(specs::ChannelSpec&& spec, Channel::ResolveParams params) -> Channel
|
auto resolve_path(specs::ChannelSpec&& spec, Channel::ResolveParams params) -> Channel
|
||||||
{
|
{
|
||||||
auto uri = specs::CondaURL::parse(util::path_or_url_to_url(spec.location()));
|
auto uri = specs::CondaURL::parse(resolve_path_location(spec.clear_location(), params));
|
||||||
auto display_name = resolve_path_name(uri, params);
|
auto display_name = resolve_path_name(uri, params);
|
||||||
auto platforms = Channel::ResolveParams::platform_list{};
|
auto platforms = Channel::ResolveParams::platform_list{};
|
||||||
if (spec.type() == specs::ChannelSpec::Type::Path)
|
if (spec.type() == specs::ChannelSpec::Type::Path)
|
||||||
|
@ -266,7 +319,7 @@ namespace mamba
|
||||||
platforms = make_platforms(spec.clear_platform_filters(), params.platforms);
|
platforms = make_platforms(spec.clear_platform_filters(), params.platforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Channel(std::move(uri), std::move(display_name), std::move(platforms));
|
return { std::move(uri), std::move(display_name), std::move(platforms) };
|
||||||
}
|
}
|
||||||
|
|
||||||
auto resolve_url_name(const specs::CondaURL& url, Channel::ResolveParams params) -> std::string
|
auto resolve_url_name(const specs::CondaURL& url, Channel::ResolveParams params) -> std::string
|
||||||
|
@ -300,68 +353,110 @@ namespace mamba
|
||||||
|
|
||||||
auto url = specs::CondaURL::parse(spec.location());
|
auto url = specs::CondaURL::parse(spec.location());
|
||||||
auto display_name = resolve_url_name(url, params);
|
auto display_name = resolve_url_name(url, params);
|
||||||
set_fallback_credential_from_db(url, params.auth_db);
|
set_fallback_credential_from_db(url, params.authentication_db);
|
||||||
auto platforms = Channel::ResolveParams::platform_list{};
|
auto platforms = Channel::ResolveParams::platform_list{};
|
||||||
if (spec.type() == specs::ChannelSpec::Type::URL)
|
if (spec.type() == specs::ChannelSpec::Type::URL)
|
||||||
{
|
{
|
||||||
platforms = make_platforms(spec.clear_platform_filters(), params.platforms);
|
platforms = make_platforms(spec.clear_platform_filters(), params.platforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Channel(std::move(url), std::move(display_name), std::move(platforms));
|
return { std::move(url), std::move(display_name), std::move(platforms) };
|
||||||
}
|
}
|
||||||
|
|
||||||
auto resolve_name(specs::ChannelSpec&& spec, Channel::ResolveParams params) -> Channel
|
auto resolve_name_in_custom_channel(
|
||||||
|
specs::ChannelSpec&& spec,
|
||||||
|
Channel::ResolveParams params,
|
||||||
|
const Channel& match
|
||||||
|
) -> Channel
|
||||||
{
|
{
|
||||||
std::string name = spec.clear_location();
|
auto url = match.url();
|
||||||
|
// we can have a channel like
|
||||||
|
// testchannel: https://server.com/private/testchannel
|
||||||
|
// where `name == private/testchannel` and we need to join the remaining label part
|
||||||
|
// of the channel (e.g. -c testchannel/mylabel/xyz)
|
||||||
|
// needs to result in `name = private/testchannel/mylabel/xyz`
|
||||||
|
std::string combined_name = util::concat_dedup_splits(
|
||||||
|
util::rstrip(url.path(), '/'),
|
||||||
|
util::lstrip(spec.location(), '/'),
|
||||||
|
'/'
|
||||||
|
);
|
||||||
|
url.set_path(combined_name);
|
||||||
|
|
||||||
const auto& custom_chans = params.custom_channels;
|
set_fallback_credential_from_db(url, params.authentication_db);
|
||||||
if (auto it = custom_chans.find_weaken(name); it != custom_chans.cend())
|
return {
|
||||||
|
/* url= */ std::move(url),
|
||||||
|
/* display_name= */ spec.clear_location(),
|
||||||
|
/* platforms= */ make_platforms(spec.clear_platform_filters(), params.platforms),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto resolve_name_in_custom_mulitchannels(
|
||||||
|
const specs::ChannelSpec& spec,
|
||||||
|
Channel::ResolveParams params,
|
||||||
|
const Channel::channel_list& matches
|
||||||
|
) -> Channel::channel_list
|
||||||
|
{
|
||||||
|
auto out = Channel::channel_list();
|
||||||
|
out.reserve(matches.size());
|
||||||
|
|
||||||
|
for (const auto& chan : matches)
|
||||||
{
|
{
|
||||||
auto url = it->second.url();
|
auto url = chan.url();
|
||||||
// we can have a channel like
|
set_fallback_credential_from_db(url, params.authentication_db);
|
||||||
// testchannel: https://server.com/private/testchannel
|
out.emplace_back(
|
||||||
// where `name == private/testchannel` and we need to join the remaining label part
|
|
||||||
// of the channel (e.g. -c testchannel/mylabel/xyz)
|
|
||||||
// needs to result in `name = private/testchannel/mylabel/xyz`
|
|
||||||
std::string combined_name = util::concat_dedup_splits(
|
|
||||||
util::rstrip(url.path(), '/'),
|
|
||||||
util::lstrip(name, '/'),
|
|
||||||
'/'
|
|
||||||
);
|
|
||||||
url.set_path(combined_name);
|
|
||||||
|
|
||||||
set_fallback_credential_from_db(url, params.auth_db);
|
|
||||||
return Channel(
|
|
||||||
/* url= */ std::move(url),
|
/* url= */ std::move(url),
|
||||||
/* display_name= */ std::move(name),
|
/* display_name= */ chan.display_name(), // Not using multi_channel name
|
||||||
/* platforms= */ make_platforms(spec.clear_platform_filters(), params.platforms)
|
/* platforms= */ make_platforms(spec.platform_filters(), params.platforms)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto resolve_name_from_alias(specs::ChannelSpec&& spec, Channel::ResolveParams params)
|
||||||
|
-> Channel
|
||||||
|
{
|
||||||
auto url = params.channel_alias;
|
auto url = params.channel_alias;
|
||||||
url.append_path(name);
|
url.append_path(spec.location());
|
||||||
set_fallback_credential_from_db(url, params.auth_db);
|
set_fallback_credential_from_db(url, params.authentication_db);
|
||||||
return Channel(
|
return {
|
||||||
/* url= */ std::move(url),
|
/* url= */ std::move(url),
|
||||||
/* display_name= */ name,
|
/* display_name= */ spec.clear_location(),
|
||||||
/* platforms= */ make_platforms(spec.clear_platform_filters(), params.platforms)
|
/* platforms= */ make_platforms(spec.clear_platform_filters(), params.platforms),
|
||||||
);
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto resolve_name(specs::ChannelSpec&& spec, Channel::ResolveParams params)
|
||||||
|
-> Channel::channel_list
|
||||||
|
{
|
||||||
|
if (auto it = params.custom_channels.find_weaken(spec.location());
|
||||||
|
it != params.custom_channels.cend())
|
||||||
|
{
|
||||||
|
return { resolve_name_in_custom_channel(std::move(spec), params, it->second) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto it = params.custom_multichannels.find(spec.location());
|
||||||
|
it != params.custom_multichannels.end())
|
||||||
|
{
|
||||||
|
return resolve_name_in_custom_mulitchannels(spec, params, it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { resolve_name_from_alias(std::move(spec), params) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Channel::resolve(specs::ChannelSpec spec, ResolveParams params) -> Channel
|
auto Channel::resolve(specs::ChannelSpec spec, ResolveParams params) -> channel_list
|
||||||
{
|
{
|
||||||
switch (spec.type())
|
switch (spec.type())
|
||||||
{
|
{
|
||||||
case specs::ChannelSpec::Type::PackagePath:
|
case specs::ChannelSpec::Type::PackagePath:
|
||||||
case specs::ChannelSpec::Type::Path:
|
case specs::ChannelSpec::Type::Path:
|
||||||
{
|
{
|
||||||
return resolve_path(std::move(spec), params);
|
return { resolve_path(std::move(spec), params) };
|
||||||
}
|
}
|
||||||
case specs::ChannelSpec::Type::PackageURL:
|
case specs::ChannelSpec::Type::PackageURL:
|
||||||
case specs::ChannelSpec::Type::URL:
|
case specs::ChannelSpec::Type::URL:
|
||||||
{
|
{
|
||||||
return resolve_url(std::move(spec), params);
|
return { resolve_url(std::move(spec), params) };
|
||||||
}
|
}
|
||||||
case specs::ChannelSpec::Type::Name:
|
case specs::ChannelSpec::Type::Name:
|
||||||
{
|
{
|
||||||
|
@ -369,69 +464,41 @@ namespace mamba
|
||||||
}
|
}
|
||||||
case specs::ChannelSpec::Type::Unknown:
|
case specs::ChannelSpec::Type::Unknown:
|
||||||
{
|
{
|
||||||
return Channel(specs::CondaURL{}, spec.clear_location());
|
return { { specs::CondaURL{}, spec.clear_location() } };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw std::invalid_argument("Invalid ChannelSpec::Type");
|
throw std::invalid_argument("Invalid ChannelSpec::Type");
|
||||||
}
|
}
|
||||||
|
|
||||||
const Channel& ChannelContext::make_channel(const std::string& value)
|
auto ChannelContext::params() -> Channel::ResolveParams
|
||||||
{
|
{
|
||||||
if (const auto it = m_channel_cache.find(value); it != m_channel_cache.end())
|
return {
|
||||||
|
/* .platforms= */ m_platforms,
|
||||||
|
/* .channel_alias= */ m_channel_alias,
|
||||||
|
/* .custom_channels= */ m_custom_channels,
|
||||||
|
/* .custom_multichannels= */ m_custom_multichannels,
|
||||||
|
/* .authentication_db= */ m_context.authentication_info(),
|
||||||
|
/* .home_dir= */ m_home_dir,
|
||||||
|
/* .current_working_dir= */ m_current_working_dir,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ChannelContext::make_channel(std::string_view name) -> channel_list
|
||||||
|
{
|
||||||
|
if (const auto it = m_channel_cache.find(std::string(name)); it != m_channel_cache.end())
|
||||||
{
|
{
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto spec = specs::ChannelSpec::parse(value);
|
auto [it, inserted] = m_channel_cache.emplace(
|
||||||
auto params = Channel::ResolveParams{
|
name,
|
||||||
/* .platforms */ m_platforms,
|
Channel::resolve(specs::ChannelSpec::parse(name), params())
|
||||||
/* .channel_alias */ m_channel_alias,
|
);
|
||||||
/* .custom_channels */ m_custom_channels,
|
|
||||||
/* .auth_db */ m_context.authentication_info(),
|
|
||||||
};
|
|
||||||
|
|
||||||
auto [it, inserted] = m_channel_cache.emplace(value, Channel::resolve(std::move(spec), params));
|
|
||||||
assert(inserted);
|
assert(inserted);
|
||||||
return it->second;
|
return { it->second };
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ChannelContext::get_channels(const std::vector<std::string>& channel_names) -> channel_list
|
auto ChannelContext::get_channel_alias() const -> const specs::CondaURL&
|
||||||
{
|
|
||||||
auto added = std::unordered_set<Channel>();
|
|
||||||
auto result = channel_list();
|
|
||||||
for (auto name : channel_names)
|
|
||||||
{
|
|
||||||
auto spec = specs::ChannelSpec::parse(name);
|
|
||||||
|
|
||||||
const auto& multi_chan = get_custom_multichannels();
|
|
||||||
if (auto iter = multi_chan.find(spec.location()); iter != multi_chan.end())
|
|
||||||
{
|
|
||||||
for (const auto& chan : iter->second)
|
|
||||||
{
|
|
||||||
auto channel = chan;
|
|
||||||
if (!spec.platform_filters().empty())
|
|
||||||
{
|
|
||||||
channel.set_platforms(spec.platform_filters());
|
|
||||||
}
|
|
||||||
if (added.insert(channel).second)
|
|
||||||
{
|
|
||||||
result.push_back(std::move(channel));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto channel = make_channel(name);
|
|
||||||
if (added.insert(channel).second)
|
|
||||||
{
|
|
||||||
result.push_back(std::move(channel));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const specs::CondaURL& ChannelContext::get_channel_alias() const
|
|
||||||
{
|
{
|
||||||
return m_channel_alias;
|
return m_channel_alias;
|
||||||
}
|
}
|
||||||
|
@ -449,9 +516,13 @@ namespace mamba
|
||||||
ChannelContext::ChannelContext(Context& context)
|
ChannelContext::ChannelContext(Context& context)
|
||||||
: m_context(context)
|
: m_context(context)
|
||||||
, m_channel_alias(specs::CondaURL::parse(util::path_or_url_to_url(m_context.channel_alias)))
|
, m_channel_alias(specs::CondaURL::parse(util::path_or_url_to_url(m_context.channel_alias)))
|
||||||
|
, m_home_dir(util::user_home_dir())
|
||||||
|
, m_current_working_dir(fs::current_path())
|
||||||
{
|
{
|
||||||
m_platforms = [](const auto& plats)
|
{
|
||||||
{ return platform_list(plats.cbegin(), plats.cend()); }(m_context.platforms());
|
const auto& plats = m_context.platforms();
|
||||||
|
m_platforms = Channel::ResolveParams::platform_list(plats.cbegin(), plats.cend());
|
||||||
|
}
|
||||||
init_custom_channels();
|
init_custom_channels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,9 +532,10 @@ namespace mamba
|
||||||
{
|
{
|
||||||
for (const auto& [name, location] : m_context.custom_channels)
|
for (const auto& [name, location] : m_context.custom_channels)
|
||||||
{
|
{
|
||||||
auto channel = make_channel(location);
|
auto channels = make_channel(location);
|
||||||
channel.set_display_name(name);
|
assert(channels.size() == 1);
|
||||||
m_custom_channels.emplace(name, std::move(channel));
|
channels.front().set_display_name(name);
|
||||||
|
m_custom_channels.emplace(name, std::move(channels.front()));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& [multi_name, location_list] : m_context.custom_multichannels)
|
for (const auto& [multi_name, location_list] : m_context.custom_multichannels)
|
||||||
|
@ -472,7 +544,10 @@ namespace mamba
|
||||||
channels.reserve(location_list.size());
|
channels.reserve(location_list.size());
|
||||||
for (auto& location : location_list)
|
for (auto& location : location_list)
|
||||||
{
|
{
|
||||||
channels.push_back(make_channel(location));
|
for (auto& chan : make_channel(location))
|
||||||
|
{
|
||||||
|
channels.push_back(std::move(chan));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_custom_multichannels.emplace(multi_name, std::move(channels));
|
m_custom_multichannels.emplace(multi_name, std::move(channels));
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,9 +93,11 @@ namespace mamba
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& parsed_channel = channel_context.make_channel(spec_str);
|
auto channels = channel_context.make_channel(spec_str);
|
||||||
|
|
||||||
if (auto pkg = parsed_channel.url().package(); !pkg.empty())
|
// TODO we are not handling the custom_multichannel case where `channels` can have
|
||||||
|
// more than one element.
|
||||||
|
if (auto pkg = channels.front().url().package(); !pkg.empty())
|
||||||
{
|
{
|
||||||
auto dist = parse_legacy_dist(pkg);
|
auto dist = parse_legacy_dist(pkg);
|
||||||
|
|
||||||
|
@ -103,9 +105,9 @@ namespace mamba
|
||||||
version = dist[1];
|
version = dist[1];
|
||||||
build_string = dist[2];
|
build_string = dist[2];
|
||||||
|
|
||||||
channel = parsed_channel.display_name();
|
channel = channels.front().display_name();
|
||||||
// TODO how to handle this with multiple platforms?
|
// TODO how to handle this with multiple platforms?
|
||||||
if (const auto& plats = parsed_channel.platforms(); !plats.empty())
|
if (const auto& plats = channels.front().platforms(); !plats.empty())
|
||||||
{
|
{
|
||||||
subdir = plats.front();
|
subdir = plats.front();
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,9 @@ namespace mamba
|
||||||
// FIXME: only do this for micromamba for now
|
// FIXME: only do this for micromamba for now
|
||||||
if (channel_context.context().command_params.is_micromamba)
|
if (channel_context.context().command_params.is_micromamba)
|
||||||
{
|
{
|
||||||
m_url = channel_context.make_channel(pkg_info.url).urls(true)[0];
|
auto channels = channel_context.make_channel(pkg_info.url);
|
||||||
|
assert(channels.size() == 1); // A URL can only resolve to one channel
|
||||||
|
m_url = channels.front().urls(true)[0];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -140,63 +140,37 @@ namespace mamba
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool
|
enum struct ChannelMatch
|
||||||
channel_match(ChannelContext& channel_context, const Channel& chan, const Channel& needle)
|
|
||||||
{
|
{
|
||||||
if (chan.base_url() == needle.base_url())
|
None,
|
||||||
{
|
ChannelOnly,
|
||||||
return true;
|
ChannelAndSubdir,
|
||||||
}
|
};
|
||||||
|
|
||||||
auto& custom_multichannels = channel_context.context().custom_multichannels;
|
auto channel_match(
|
||||||
auto x = custom_multichannels.find(needle.display_name());
|
const std::vector<Channel>& repo_channels,
|
||||||
if (x != custom_multichannels.end())
|
const std::vector<Channel>& candidate_channels
|
||||||
|
) -> ChannelMatch
|
||||||
|
{
|
||||||
|
// More than one element means the channel spec was a custom_multi_channel,
|
||||||
|
// which should never happen for the repo
|
||||||
|
for (const auto& repo_chan : repo_channels)
|
||||||
{
|
{
|
||||||
for (auto el : (x->second))
|
// More than one element means the channel spec was a custom_multi_channel.
|
||||||
|
// We need to add any repo that matches.
|
||||||
|
for (const auto& cand_chan : candidate_channels)
|
||||||
{
|
{
|
||||||
const Channel& inner = channel_context.make_channel(el);
|
if (repo_chan.url_equivalent_with(cand_chan))
|
||||||
if (chan.base_url() == inner.base_url())
|
|
||||||
{
|
{
|
||||||
return true;
|
if (util::set_is_subset_of(repo_chan.platforms(), cand_chan.platforms()))
|
||||||
|
{
|
||||||
|
return ChannelMatch::ChannelAndSubdir;
|
||||||
|
}
|
||||||
|
return ChannelMatch::ChannelOnly;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ChannelMatch::None;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool subdir_match(std::string candidate_repo_url, std::string needle_spec)
|
|
||||||
{
|
|
||||||
// Example candidate_repo_url: https://.../conda-forge/linux-64
|
|
||||||
// example needle_spec: conda-forge/osx-64::xtensor
|
|
||||||
|
|
||||||
std::string needle_channel = util::split(needle_spec, ":", 1)[0];
|
|
||||||
if (!util::contains(needle_channel, "/"))
|
|
||||||
{
|
|
||||||
// Subdir not specified, so any subdir is fine
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
std::string needle_subdir = util::rsplit(needle_channel, "/", 1)[1];
|
|
||||||
|
|
||||||
auto known_platforms = specs::known_platform_names();
|
|
||||||
if (std::find(known_platforms.begin(), known_platforms.end(), needle_subdir)
|
|
||||||
== known_platforms.end())
|
|
||||||
{
|
|
||||||
// Not a known subdir. This can happen for specs like pkgs/main.
|
|
||||||
// so any subdir is fine
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string candidate_repo_subdir = util::rsplit(candidate_repo_url, "/", 1)[1];
|
|
||||||
|
|
||||||
if (candidate_repo_subdir == needle_subdir)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
throw std::runtime_error(fmt::format(
|
|
||||||
"The package \"{}\" is not available for the specified platform",
|
|
||||||
needle_spec
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -223,18 +197,8 @@ namespace mamba
|
||||||
ms.conda_build_form().c_str()
|
ms.conda_build_form().c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
const auto& multi_chan = channel_context.get_custom_multichannels();
|
|
||||||
auto channels = std::vector<Channel>();
|
|
||||||
if (auto iter = multi_chan.find(ms.channel); iter != multi_chan.end())
|
|
||||||
{
|
|
||||||
channels.insert(channels.end(), iter->second.cbegin(), iter->second.cend());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
channels.push_back(channel_context.make_channel(ms.channel));
|
|
||||||
}
|
|
||||||
|
|
||||||
solv::ObjQueue selected_pkgs = {};
|
solv::ObjQueue selected_pkgs = {};
|
||||||
|
bool found_partial_matches = false;
|
||||||
pool.for_each_whatprovides(
|
pool.for_each_whatprovides(
|
||||||
match,
|
match,
|
||||||
[&](solv::ObjSolvableViewConst s)
|
[&](solv::ObjSolvableViewConst s)
|
||||||
|
@ -242,21 +206,46 @@ namespace mamba
|
||||||
// TODO this does not work with s.url(), we need to proper channel class
|
// TODO this does not work with s.url(), we need to proper channel class
|
||||||
// to properly manage this.
|
// to properly manage this.
|
||||||
auto repo = solv::ObjRepoView(*s.raw()->repo);
|
auto repo = solv::ObjRepoView(*s.raw()->repo);
|
||||||
// TODO make_channel should disapear avoiding conflict here
|
// TODO Replace MatchSpec channel and subdir with a ChannelSpec
|
||||||
auto const url = std::string(repo.url());
|
const auto chan_spec = [&]() -> std::string
|
||||||
for (auto const& c : channels)
|
|
||||||
{
|
{
|
||||||
if (channel_match(channel_context, channel_context.make_channel(url), c))
|
if (ms.subdir.empty())
|
||||||
|
{
|
||||||
|
return ms.channel;
|
||||||
|
}
|
||||||
|
return util::concat(ms.channel, '[', ms.subdir, ']');
|
||||||
|
}();
|
||||||
|
const auto match = channel_match(
|
||||||
|
channel_context.make_channel(repo.url()),
|
||||||
|
channel_context.make_channel(chan_spec)
|
||||||
|
);
|
||||||
|
switch (match)
|
||||||
|
{
|
||||||
|
case (ChannelMatch::ChannelAndSubdir):
|
||||||
|
{
|
||||||
|
selected_pkgs.push_back(s.id());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (ChannelMatch::ChannelOnly):
|
||||||
|
{
|
||||||
|
found_partial_matches = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (ChannelMatch::None):
|
||||||
{
|
{
|
||||||
if (subdir_match(url, ms.spec))
|
|
||||||
{
|
|
||||||
selected_pkgs.push_back(s.id());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (selected_pkgs.empty() && found_partial_matches)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(fmt::format(
|
||||||
|
R"(The package "{}" is not available for the specified platform)",
|
||||||
|
ms.spec
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
const solv::StringId repr_id = pool.add_string(repr);
|
const solv::StringId repr_id = pool.add_string(repr);
|
||||||
// FRAGILE This get deleted when calling ``pool_createwhatprovides`` so care
|
// FRAGILE This get deleted when calling ``pool_createwhatprovides`` so care
|
||||||
// must be taken to do it before
|
// must be taken to do it before
|
||||||
|
|
|
@ -164,8 +164,12 @@ namespace mamba
|
||||||
// and conda-meta json files with channel names while mamba expects
|
// and conda-meta json files with channel names while mamba expects
|
||||||
// PackageInfo channels to be platform urls. This fixes the issue described
|
// PackageInfo channels to be platform urls. This fixes the issue described
|
||||||
// in https://github.com/mamba-org/mamba/issues/2665
|
// in https://github.com/mamba-org/mamba/issues/2665
|
||||||
const Channel& channel = m_channel_context.make_channel(prec.channel);
|
|
||||||
prec.channel = channel.platform_url(prec.subdir);
|
auto channels = m_channel_context.make_channel(prec.channel);
|
||||||
|
// If someone wrote multichannel names in repodata_record, we don't know which one is the
|
||||||
|
// correct URL. This is must never happen!
|
||||||
|
assert(channels.size() == 1);
|
||||||
|
prec.channel = channels.front().platform_url(prec.subdir);
|
||||||
m_package_records.insert({ prec.name, std::move(prec) });
|
m_package_records.insert({ prec.name, std::move(prec) });
|
||||||
}
|
}
|
||||||
} // namespace mamba
|
} // namespace mamba
|
||||||
|
|
|
@ -107,8 +107,19 @@ namespace mamba
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchSpec modified_spec(ms);
|
MatchSpec modified_spec(ms);
|
||||||
const Channel& chan = m_pool.channel_context().make_channel(std::string(solvable->channel()));
|
{
|
||||||
modified_spec.channel = chan.display_name();
|
auto channels = m_pool.channel_context().make_channel(std::string(solvable->channel()));
|
||||||
|
if (channels.size() == 1)
|
||||||
|
{
|
||||||
|
modified_spec.channel = channels.front().display_name();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If there is more than one, it's a custom_multi_channel name.
|
||||||
|
// This should never happen.
|
||||||
|
modified_spec.channel = solvable->channel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
modified_spec.version = solvable->version();
|
modified_spec.version = solvable->version();
|
||||||
modified_spec.build_string = solvable->build_string();
|
modified_spec.build_string = solvable->build_string();
|
||||||
|
@ -146,7 +157,7 @@ namespace mamba
|
||||||
// moment
|
// moment
|
||||||
}
|
}
|
||||||
|
|
||||||
::Id const job_id = m_pool.matchspec2id(ms);
|
const ::Id job_id = m_pool.matchspec2id(ms);
|
||||||
|
|
||||||
// This is checking if SOLVER_ERASE and SOLVER_INSTALL are set
|
// This is checking if SOLVER_ERASE and SOLVER_INSTALL are set
|
||||||
// which are the flags for SOLVER_UPDATE
|
// which are the flags for SOLVER_UPDATE
|
||||||
|
@ -224,7 +235,7 @@ namespace mamba
|
||||||
// Add dummy solvable with a constraint on the pin (not installed if not present)
|
// Add dummy solvable with a constraint on the pin (not installed if not present)
|
||||||
auto [cons_solv_id, cons_solv] = installed->add_solvable();
|
auto [cons_solv_id, cons_solv] = installed->add_solvable();
|
||||||
// TODO set some "pin" key on the solvable so that we can retrieve it during error messages
|
// TODO set some "pin" key on the solvable so that we can retrieve it during error messages
|
||||||
std::string const cons_solv_name = fmt::format("pin-{}", m_pinned_specs.size());
|
const std::string cons_solv_name = fmt::format("pin-{}", m_pinned_specs.size());
|
||||||
cons_solv.set_name(cons_solv_name);
|
cons_solv.set_name(cons_solv_name);
|
||||||
cons_solv.set_version("1");
|
cons_solv.set_version("1");
|
||||||
cons_solv.add_constraints(solv::ObjQueue{ m_pool.matchspec2id(pin_ms) });
|
cons_solv.add_constraints(solv::ObjQueue{ m_pool.matchspec2id(pin_ms) });
|
||||||
|
|
|
@ -378,11 +378,16 @@ namespace mamba
|
||||||
|
|
||||||
bool check_zst(ChannelContext& channel_context, const Channel& channel)
|
bool check_zst(ChannelContext& channel_context, const Channel& channel)
|
||||||
{
|
{
|
||||||
|
// TODO the list of channels with zst should really be computed only once in
|
||||||
|
// the ChannelContext
|
||||||
for (const auto& c : channel_context.context().repodata_has_zst)
|
for (const auto& c : channel_context.context().repodata_has_zst)
|
||||||
{
|
{
|
||||||
if (channel_context.make_channel(c).base_url() == channel.base_url())
|
for (const auto& chan : channel_context.make_channel(c))
|
||||||
{
|
{
|
||||||
return true;
|
if (chan.contains_equivalent(channel))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1231,8 +1231,17 @@ namespace mamba
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const Channel& chan = m_pool.channel_context().make_channel(str);
|
auto channels = m_pool.channel_context().make_channel(str);
|
||||||
chan_name = chan.display_name();
|
if (channels.size() == 1)
|
||||||
|
{
|
||||||
|
chan_name = channels.front().display_name();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If there is more than on, it's a custom_multi_channel name
|
||||||
|
// This should never happen
|
||||||
|
chan_name = str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -89,10 +89,14 @@ namespace mamba
|
||||||
CHECK_EQ(it->second.display_name(), "pkgs/main");
|
CHECK_EQ(it->second.display_name(), "pkgs/main");
|
||||||
|
|
||||||
std::string value = "conda-forge";
|
std::string value = "conda-forge";
|
||||||
const Channel& c = channel_context.make_channel(value);
|
const auto channels = channel_context.make_channel(value);
|
||||||
CHECK_EQ(c.url(), CondaURL::parse("https://mydomain.com/channels/conda-forge"));
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
CHECK_EQ(c.display_name(), "conda-forge");
|
CHECK_EQ(
|
||||||
CHECK_EQ(c.platforms(), PlatformSet({ platform, "noarch" }));
|
channels.front().url(),
|
||||||
|
CondaURL::parse("https://mydomain.com/channels/conda-forge")
|
||||||
|
);
|
||||||
|
CHECK_EQ(channels.front().display_name(), "conda-forge");
|
||||||
|
CHECK_EQ(channels.front().platforms(), PlatformSet({ platform, "noarch" }));
|
||||||
|
|
||||||
ctx.channel_alias = "https://conda.anaconda.org";
|
ctx.channel_alias = "https://conda.anaconda.org";
|
||||||
}
|
}
|
||||||
|
@ -108,8 +112,9 @@ namespace mamba
|
||||||
|
|
||||||
ChannelContext channel_context{ ctx };
|
ChannelContext channel_context{ ctx };
|
||||||
auto base = std::string("https://ali.as/prefix-and-more/");
|
auto base = std::string("https://ali.as/prefix-and-more/");
|
||||||
auto& chan = channel_context.make_channel(base);
|
const auto channels = channel_context.make_channel(base);
|
||||||
CHECK_EQ(chan.urls(), UrlSet{ base + platform, base + "noarch" });
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
|
CHECK_EQ(channels.front().urls(), UrlSet{ base + platform, base + "noarch" });
|
||||||
|
|
||||||
ctx.channel_alias = "https://conda.anaconda.org";
|
ctx.channel_alias = "https://conda.anaconda.org";
|
||||||
ctx.custom_channels.clear();
|
ctx.custom_channels.clear();
|
||||||
|
@ -133,28 +138,33 @@ namespace mamba
|
||||||
|
|
||||||
{
|
{
|
||||||
std::string value = "test_channel";
|
std::string value = "test_channel";
|
||||||
const Channel& c = channel_context.make_channel(value);
|
const auto channels = channel_context.make_channel(value);
|
||||||
CHECK_EQ(c.url(), CondaURL::parse("file:///tmp/test_channel"));
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
CHECK_EQ(c.display_name(), "test_channel");
|
CHECK_EQ(channels.front().url(), CondaURL::parse("file:///tmp/test_channel"));
|
||||||
CHECK_EQ(c.platforms(), PlatformSet({ platform, "noarch" }));
|
CHECK_EQ(channels.front().display_name(), "test_channel");
|
||||||
|
CHECK_EQ(channels.front().platforms(), PlatformSet({ platform, "noarch" }));
|
||||||
const UrlSet exp_urls({
|
const UrlSet exp_urls({
|
||||||
std::string("file:///tmp/test_channel/") + platform,
|
std::string("file:///tmp/test_channel/") + platform,
|
||||||
"file:///tmp/test_channel/noarch",
|
"file:///tmp/test_channel/noarch",
|
||||||
});
|
});
|
||||||
CHECK_EQ(c.urls(), exp_urls);
|
CHECK_EQ(channels.front().urls(), exp_urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::string value = "some_channel";
|
std::string value = "some_channel";
|
||||||
const Channel& c = channel_context.make_channel(value);
|
const auto channels = channel_context.make_channel(value);
|
||||||
CHECK_EQ(c.url(), CondaURL::parse("https://conda.mydomain.xyz/some_channel"));
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
CHECK_EQ(c.display_name(), "some_channel");
|
CHECK_EQ(
|
||||||
CHECK_EQ(c.platforms(), PlatformSet({ platform, "noarch" }));
|
channels.front().url(),
|
||||||
|
CondaURL::parse("https://conda.mydomain.xyz/some_channel")
|
||||||
|
);
|
||||||
|
CHECK_EQ(channels.front().display_name(), "some_channel");
|
||||||
|
CHECK_EQ(channels.front().platforms(), PlatformSet({ platform, "noarch" }));
|
||||||
const UrlSet exp_urls({
|
const UrlSet exp_urls({
|
||||||
std::string("https://conda.mydomain.xyz/some_channel/") + platform,
|
std::string("https://conda.mydomain.xyz/some_channel/") + platform,
|
||||||
"https://conda.mydomain.xyz/some_channel/noarch",
|
"https://conda.mydomain.xyz/some_channel/noarch",
|
||||||
});
|
});
|
||||||
CHECK_EQ(c.urls(), exp_urls);
|
CHECK_EQ(channels.front().urls(), exp_urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.channel_alias = "https://conda.anaconda.org";
|
ctx.channel_alias = "https://conda.anaconda.org";
|
||||||
|
@ -179,7 +189,7 @@ namespace mamba
|
||||||
|
|
||||||
ChannelContext channel_context{ ctx };
|
ChannelContext channel_context{ ctx };
|
||||||
|
|
||||||
auto x = channel_context.get_channels({ "xtest" });
|
auto x = channel_context.make_channel("xtest");
|
||||||
|
|
||||||
CHECK_EQ(x.size(), 3);
|
CHECK_EQ(x.size(), 3);
|
||||||
auto c1 = x[0];
|
auto c1 = x[0];
|
||||||
|
@ -196,7 +206,7 @@ namespace mamba
|
||||||
"https://otherdomain.com/snakepit/noarch",
|
"https://otherdomain.com/snakepit/noarch",
|
||||||
});
|
});
|
||||||
|
|
||||||
auto y = channel_context.get_channels({ "ytest" });
|
auto y = channel_context.make_channel("ytest");
|
||||||
auto y3 = y[2];
|
auto y3 = y[2];
|
||||||
|
|
||||||
CHECK_EQ(y3.urls(), exp_urlsy3);
|
CHECK_EQ(y3.urls(), exp_urlsy3);
|
||||||
|
@ -223,7 +233,7 @@ namespace mamba
|
||||||
|
|
||||||
ChannelContext channel_context{ ctx };
|
ChannelContext channel_context{ ctx };
|
||||||
|
|
||||||
auto x = channel_context.get_channels({ "everything" });
|
auto x = channel_context.make_channel("everything");
|
||||||
|
|
||||||
CHECK_EQ(x.size(), 3);
|
CHECK_EQ(x.size(), 3);
|
||||||
auto c1 = x[0];
|
auto c1 = x[0];
|
||||||
|
@ -266,7 +276,7 @@ namespace mamba
|
||||||
|
|
||||||
ChannelContext channel_context{ ctx };
|
ChannelContext channel_context{ ctx };
|
||||||
|
|
||||||
auto x = channel_context.get_channels({ "defaults" });
|
auto x = channel_context.make_channel("defaults");
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
const Channel c1 = x[0];
|
const Channel c1 = x[0];
|
||||||
const Channel c2 = x[1];
|
const Channel c2 = x[1];
|
||||||
|
@ -301,7 +311,7 @@ namespace mamba
|
||||||
ctx.custom_multichannels["defaults"] = ctx.default_channels;
|
ctx.custom_multichannels["defaults"] = ctx.default_channels;
|
||||||
ChannelContext channel_context{ ctx };
|
ChannelContext channel_context{ ctx };
|
||||||
|
|
||||||
auto x = channel_context.get_channels({ "defaults" });
|
auto x = channel_context.make_channel("defaults");
|
||||||
const Channel c1 = x[0];
|
const Channel c1 = x[0];
|
||||||
const Channel c2 = x[1];
|
const Channel c2 = x[1];
|
||||||
|
|
||||||
|
@ -338,7 +348,7 @@ namespace mamba
|
||||||
|
|
||||||
CHECK_EQ(channel_context.get_custom_multichannels().at("local").size(), 3);
|
CHECK_EQ(channel_context.get_custom_multichannels().at("local").size(), 3);
|
||||||
|
|
||||||
auto local_channels = channel_context.get_channels({ "local" });
|
auto local_channels = channel_context.make_channel("local");
|
||||||
CHECK_EQ(local_channels.size(), 3);
|
CHECK_EQ(local_channels.size(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,50 +363,56 @@ namespace mamba
|
||||||
|
|
||||||
{
|
{
|
||||||
std::string value = "test_channel";
|
std::string value = "test_channel";
|
||||||
const Channel& c = channel_context.make_channel(value);
|
const auto channels = channel_context.make_channel(value);
|
||||||
CHECK_EQ(c.url(), CondaURL::parse("https://server.com/private/channels/test_channel"));
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
CHECK_EQ(c.display_name(), "test_channel");
|
CHECK_EQ(
|
||||||
CHECK_EQ(c.platforms(), PlatformSet({ platform, "noarch" }));
|
channels.front().url(),
|
||||||
|
CondaURL::parse("https://server.com/private/channels/test_channel")
|
||||||
|
);
|
||||||
|
CHECK_EQ(channels.front().display_name(), "test_channel");
|
||||||
|
CHECK_EQ(channels.front().platforms(), PlatformSet({ platform, "noarch" }));
|
||||||
const UrlSet exp_urls({
|
const UrlSet exp_urls({
|
||||||
std::string("https://server.com/private/channels/test_channel/") + platform,
|
std::string("https://server.com/private/channels/test_channel/") + platform,
|
||||||
"https://server.com/private/channels/test_channel/noarch",
|
"https://server.com/private/channels/test_channel/noarch",
|
||||||
});
|
});
|
||||||
CHECK_EQ(c.urls(), exp_urls);
|
CHECK_EQ(channels.front().urls(), exp_urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::string value = "test_channel/mylabel/xyz";
|
std::string value = "test_channel/mylabel/xyz";
|
||||||
const Channel& c = channel_context.make_channel(value);
|
const auto channels = channel_context.make_channel(value);
|
||||||
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
c.url(),
|
channels.front().url(),
|
||||||
CondaURL::parse("https://server.com/private/channels/test_channel/mylabel/xyz")
|
CondaURL::parse("https://server.com/private/channels/test_channel/mylabel/xyz")
|
||||||
);
|
);
|
||||||
CHECK_EQ(c.display_name(), "test_channel/mylabel/xyz");
|
CHECK_EQ(channels.front().display_name(), "test_channel/mylabel/xyz");
|
||||||
CHECK_EQ(c.platforms(), PlatformSet({ platform, "noarch" }));
|
CHECK_EQ(channels.front().platforms(), PlatformSet({ platform, "noarch" }));
|
||||||
const UrlSet exp_urls({
|
const UrlSet exp_urls({
|
||||||
std::string("https://server.com/private/channels/test_channel/mylabel/xyz/")
|
std::string("https://server.com/private/channels/test_channel/mylabel/xyz/")
|
||||||
+ platform,
|
+ platform,
|
||||||
"https://server.com/private/channels/test_channel/mylabel/xyz/noarch",
|
"https://server.com/private/channels/test_channel/mylabel/xyz/noarch",
|
||||||
});
|
});
|
||||||
CHECK_EQ(c.urls(), exp_urls);
|
CHECK_EQ(channels.front().urls(), exp_urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// https://github.com/mamba-org/mamba/issues/2553
|
// https://github.com/mamba-org/mamba/issues/2553
|
||||||
std::string value = "random/test_channel/pkg";
|
std::string value = "random/test_channel/pkg";
|
||||||
const Channel& c = channel_context.make_channel(value);
|
const auto channels = channel_context.make_channel(value);
|
||||||
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
c.url(),
|
channels.front().url(),
|
||||||
CondaURL::parse("https://server.com/random/channels/random/test_channel/pkg")
|
CondaURL::parse("https://server.com/random/channels/random/test_channel/pkg")
|
||||||
);
|
);
|
||||||
CHECK_EQ(c.display_name(), "random/test_channel/pkg");
|
CHECK_EQ(channels.front().display_name(), "random/test_channel/pkg");
|
||||||
CHECK_EQ(c.platforms(), PlatformSet({ platform, "noarch" }));
|
CHECK_EQ(channels.front().platforms(), PlatformSet({ platform, "noarch" }));
|
||||||
const UrlSet exp_urls({
|
const UrlSet exp_urls({
|
||||||
std::string("https://server.com/random/channels/random/test_channel/pkg/")
|
std::string("https://server.com/random/channels/random/test_channel/pkg/")
|
||||||
+ platform,
|
+ platform,
|
||||||
"https://server.com/random/channels/random/test_channel/pkg/noarch",
|
"https://server.com/random/channels/random/test_channel/pkg/noarch",
|
||||||
});
|
});
|
||||||
CHECK_EQ(c.urls(), exp_urls);
|
CHECK_EQ(channels.front().urls(), exp_urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.channel_alias = "https://conda.anaconda.org";
|
ctx.channel_alias = "https://conda.anaconda.org";
|
||||||
|
@ -410,69 +426,82 @@ namespace mamba
|
||||||
{
|
{
|
||||||
std::string value = "https://repo.mamba.pm/conda-forge";
|
std::string value = "https://repo.mamba.pm/conda-forge";
|
||||||
ChannelContext channel_context{ mambatests::context() };
|
ChannelContext channel_context{ mambatests::context() };
|
||||||
const Channel& c = channel_context.make_channel(value);
|
const auto channels = channel_context.make_channel(value);
|
||||||
CHECK_EQ(c.url(), CondaURL::parse("https://repo.mamba.pm/conda-forge"));
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
CHECK_EQ(c.display_name(), "https://repo.mamba.pm/conda-forge");
|
CHECK_EQ(channels.front().url(), CondaURL::parse("https://repo.mamba.pm/conda-forge"));
|
||||||
CHECK_EQ(c.platforms(), PlatformSet({ platform, "noarch" }));
|
CHECK_EQ(channels.front().display_name(), "https://repo.mamba.pm/conda-forge");
|
||||||
|
CHECK_EQ(channels.front().platforms(), PlatformSet({ platform, "noarch" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("make_channel")
|
TEST_CASE("make_chan")
|
||||||
{
|
{
|
||||||
std::string value = "conda-forge";
|
std::string value1 = "conda-forge";
|
||||||
ChannelContext channel_context{ mambatests::context() };
|
ChannelContext channel_context{ mambatests::context() };
|
||||||
const Channel& c = channel_context.make_channel(value);
|
const auto channels1 = channel_context.make_channel(value1);
|
||||||
CHECK_EQ(c.url(), CondaURL::parse("https://conda.anaconda.org/conda-forge"));
|
REQUIRE_EQ(channels1.size(), 1);
|
||||||
CHECK_EQ(c.display_name(), "conda-forge");
|
CHECK_EQ(channels1.front().url(), CondaURL::parse("https://conda.anaconda.org/conda-forge"));
|
||||||
CHECK_EQ(c.platforms(), PlatformSet({ platform, "noarch" }));
|
CHECK_EQ(channels1.front().display_name(), "conda-forge");
|
||||||
|
CHECK_EQ(channels1.front().platforms(), PlatformSet({ platform, "noarch" }));
|
||||||
|
|
||||||
std::string value2 = "https://repo.anaconda.com/pkgs/main[" + platform + "]";
|
std::string value2 = "https://repo.anaconda.com/pkgs/main[" + platform + "]";
|
||||||
const Channel& c2 = channel_context.make_channel(value2);
|
const auto channels2 = channel_context.make_channel(value2);
|
||||||
CHECK_EQ(c2.url(), CondaURL::parse("https://repo.anaconda.com/pkgs/main"));
|
REQUIRE_EQ(channels2.size(), 1);
|
||||||
CHECK_EQ(c2.display_name(), "https://repo.anaconda.com/pkgs/main");
|
CHECK_EQ(channels2.front().url(), CondaURL::parse("https://repo.anaconda.com/pkgs/main"));
|
||||||
CHECK_EQ(c2.platforms(), PlatformSet({ platform }));
|
CHECK_EQ(channels2.front().display_name(), "https://repo.anaconda.com/pkgs/main");
|
||||||
|
CHECK_EQ(channels2.front().platforms(), PlatformSet({ platform }));
|
||||||
|
|
||||||
std::string value3 = "https://conda.anaconda.org/conda-forge[" + platform + "]";
|
std::string value3 = "https://conda.anaconda.org/conda-forge[" + platform + "]";
|
||||||
const Channel& c3 = channel_context.make_channel(value3);
|
const auto channels3 = channel_context.make_channel(value3);
|
||||||
CHECK_EQ(c3.url(), c.url());
|
REQUIRE_EQ(channels3.size(), 1);
|
||||||
CHECK_EQ(c3.display_name(), c.display_name());
|
CHECK_EQ(channels3.front().url(), channels1.front().url());
|
||||||
CHECK_EQ(c3.platforms(), PlatformSet({ platform }));
|
CHECK_EQ(channels3.front().display_name(), channels1.front().display_name());
|
||||||
|
CHECK_EQ(channels3.front().platforms(), PlatformSet({ platform }));
|
||||||
|
|
||||||
std::string value4 = "/home/mamba/test/channel_b";
|
std::string value4 = "/home/mamba/test/channel_b";
|
||||||
const Channel& c4 = channel_context.make_channel(value4);
|
const auto channels4 = channel_context.make_channel(value4);
|
||||||
CHECK_EQ(c4.url(), CondaURL::parse(util::path_to_url(value4)));
|
REQUIRE_EQ(channels4.size(), 1);
|
||||||
CHECK_EQ(c4.display_name(), c4.url().pretty_str());
|
CHECK_EQ(channels4.front().url(), CondaURL::parse(util::path_to_url(value4)));
|
||||||
CHECK_EQ(c4.platforms(), PlatformSet({ platform, "noarch" }));
|
CHECK_EQ(channels4.front().display_name(), channels4.front().url().pretty_str());
|
||||||
|
CHECK_EQ(channels4.front().platforms(), PlatformSet({ platform, "noarch" }));
|
||||||
|
|
||||||
std::string path5 = "/home/mamba/test/channel_b";
|
std::string path5 = "/home/mamba/test/channel_b";
|
||||||
std::string value5 = util::concat(path5, '[', platform, ']');
|
std::string value5 = util::concat(path5, '[', platform, ']');
|
||||||
const Channel& c5 = channel_context.make_channel(value5);
|
const auto channels5 = channel_context.make_channel(value5);
|
||||||
CHECK_EQ(c5.url(), CondaURL::parse(util::path_to_url(path5)));
|
REQUIRE_EQ(channels5.size(), 1);
|
||||||
CHECK_EQ(c5.display_name(), c5.url().pretty_str());
|
CHECK_EQ(channels5.front().url(), CondaURL::parse(util::path_to_url(path5)));
|
||||||
CHECK_EQ(c5.platforms(), PlatformSet({ platform }));
|
CHECK_EQ(channels5.front().display_name(), channels5.front().url().pretty_str());
|
||||||
|
CHECK_EQ(channels5.front().platforms(), PlatformSet({ platform }));
|
||||||
|
|
||||||
std::string value6a = "http://localhost:8000/conda-forge[noarch]";
|
std::string value6a = "http://localhost:8000/conda-forge[noarch]";
|
||||||
const Channel& c6a = channel_context.make_channel(value6a);
|
const auto channels6a = channel_context.make_channel(value6a);
|
||||||
CHECK_EQ(c6a.urls(false), UrlSet({ "http://localhost:8000/conda-forge/noarch" }));
|
REQUIRE_EQ(channels6a.size(), 1);
|
||||||
|
CHECK_EQ(
|
||||||
|
channels6a.front().urls(false),
|
||||||
|
UrlSet({ "http://localhost:8000/conda-forge/noarch" })
|
||||||
|
);
|
||||||
|
|
||||||
std::string value6b = "http://localhost:8000/conda_mirror/conda-forge[noarch]";
|
std::string value6b = "http://localhost:8000/conda_mirror/conda-forge[noarch]";
|
||||||
const Channel& c6b = channel_context.make_channel(value6b);
|
const auto channels6b = channel_context.make_channel(value6b);
|
||||||
|
REQUIRE_EQ(channels6b.size(), 1);
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
c6b.urls(false),
|
channels6b.front().urls(false),
|
||||||
UrlSet({ "http://localhost:8000/conda_mirror/conda-forge/noarch" })
|
UrlSet({ "http://localhost:8000/conda_mirror/conda-forge/noarch" })
|
||||||
);
|
);
|
||||||
|
|
||||||
std::string value7 = "conda-forge[noarch,arbitrary]";
|
std::string value7 = "conda-forge[noarch,arbitrary]";
|
||||||
const Channel& c7 = channel_context.make_channel(value7);
|
const auto channels7 = channel_context.make_channel(value7);
|
||||||
CHECK_EQ(c7.platforms(), PlatformSet({ "noarch", "arbitrary" }));
|
REQUIRE_EQ(channels7.size(), 1);
|
||||||
|
CHECK_EQ(channels7.front().platforms(), PlatformSet({ "noarch", "arbitrary" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("urls")
|
TEST_CASE("urls")
|
||||||
{
|
{
|
||||||
std::string value = "https://conda.anaconda.org/conda-forge[noarch,win-64,arbitrary]";
|
std::string value1 = "https://conda.anaconda.org/conda-forge[noarch,win-64,arbitrary]";
|
||||||
ChannelContext channel_context{ mambatests::context() };
|
ChannelContext channel_context{ mambatests::context() };
|
||||||
const Channel& c = channel_context.make_channel(value);
|
const auto channels1 = channel_context.make_channel(value1);
|
||||||
|
REQUIRE_EQ(channels1.size(), 1);
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
c.urls(),
|
channels1.front().urls(),
|
||||||
UrlSet({
|
UrlSet({
|
||||||
"https://conda.anaconda.org/conda-forge/arbitrary",
|
"https://conda.anaconda.org/conda-forge/arbitrary",
|
||||||
"https://conda.anaconda.org/conda-forge/noarch",
|
"https://conda.anaconda.org/conda-forge/noarch",
|
||||||
|
@ -480,9 +509,11 @@ namespace mamba
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const Channel& c1 = channel_context.make_channel("https://conda.anaconda.org/conda-forge");
|
const auto channels2 = channel_context.make_channel("https://conda.anaconda.org/conda-forge"
|
||||||
|
);
|
||||||
|
REQUIRE_EQ(channels2.size(), 1);
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
c1.urls(),
|
channels2.front().urls(),
|
||||||
UrlSet({
|
UrlSet({
|
||||||
"https://conda.anaconda.org/conda-forge/" + platform,
|
"https://conda.anaconda.org/conda-forge/" + platform,
|
||||||
"https://conda.anaconda.org/conda-forge/noarch",
|
"https://conda.anaconda.org/conda-forge/noarch",
|
||||||
|
@ -500,13 +531,17 @@ namespace mamba
|
||||||
|
|
||||||
ChannelContext channel_context{ ctx };
|
ChannelContext channel_context{ ctx };
|
||||||
|
|
||||||
const auto& chan = channel_context.make_channel("conda-forge[noarch]");
|
const auto channels = channel_context.make_channel("conda-forge[noarch]");
|
||||||
CHECK_EQ(chan.url().token(), "my-12345-token");
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
|
CHECK_EQ(channels.front().url().token(), "my-12345-token");
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
chan.urls(true),
|
channels.front().urls(true),
|
||||||
UrlSet({ "https://conda.anaconda.org/t/my-12345-token/conda-forge/noarch" })
|
UrlSet({ "https://conda.anaconda.org/t/my-12345-token/conda-forge/noarch" })
|
||||||
);
|
);
|
||||||
CHECK_EQ(chan.urls(false), UrlSet({ "https://conda.anaconda.org/conda-forge/noarch" }));
|
CHECK_EQ(
|
||||||
|
channels.front().urls(false),
|
||||||
|
UrlSet({ "https://conda.anaconda.org/conda-forge/noarch" })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("add_multiple_tokens")
|
TEST_CASE("add_multiple_tokens")
|
||||||
|
@ -520,8 +555,9 @@ namespace mamba
|
||||||
|
|
||||||
ChannelContext channel_context{ ctx };
|
ChannelContext channel_context{ ctx };
|
||||||
|
|
||||||
const auto& chan = channel_context.make_channel("conda-forge[noarch]");
|
const auto channels = channel_context.make_channel("conda-forge[noarch]");
|
||||||
CHECK_EQ(chan.url().token(), "channel-token");
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
|
CHECK_EQ(channels.front().url().token(), "channel-token");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("fix_win_file_path")
|
TEST_CASE("fix_win_file_path")
|
||||||
|
@ -529,17 +565,19 @@ namespace mamba
|
||||||
ChannelContext channel_context{ mambatests::context() };
|
ChannelContext channel_context{ mambatests::context() };
|
||||||
if (platform == "win-64")
|
if (platform == "win-64")
|
||||||
{
|
{
|
||||||
const Channel& c = channel_context.make_channel("C:\\test\\channel");
|
const auto channels = channel_context.make_channel(R"(C:\test\channel)");
|
||||||
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
c.urls(false),
|
channels.front().urls(false),
|
||||||
UrlSet({ "file:///C:/test/channel/win-64", "file:///C:/test/channel/noarch" })
|
UrlSet({ "file:///C:/test/channel/win-64", "file:///C:/test/channel/noarch" })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const Channel& c = channel_context.make_channel("/test/channel");
|
const auto channels = channel_context.make_channel("/test/channel");
|
||||||
|
REQUIRE_EQ(channels.size(), 1);
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
c.urls(false),
|
channels.front().urls(false),
|
||||||
UrlSet({ std::string("file:///test/channel/") + platform,
|
UrlSet({ std::string("file:///test/channel/") + platform,
|
||||||
"file:///test/channel/noarch" })
|
"file:///test/channel/noarch" })
|
||||||
);
|
);
|
||||||
|
@ -549,33 +587,42 @@ namespace mamba
|
||||||
TEST_CASE("trailing_slash")
|
TEST_CASE("trailing_slash")
|
||||||
{
|
{
|
||||||
ChannelContext channel_context{ mambatests::context() };
|
ChannelContext channel_context{ mambatests::context() };
|
||||||
const Channel& c = channel_context.make_channel("http://localhost:8000/");
|
|
||||||
CHECK_EQ(c.platform_url("win-64", false), "http://localhost:8000/win-64");
|
const auto channels1 = channel_context.make_channel("http://localhost:8000/");
|
||||||
CHECK_EQ(c.base_url(), "http://localhost:8000/");
|
REQUIRE_EQ(channels1.size(), 1);
|
||||||
|
CHECK_EQ(channels1.front().platform_url("win-64", false), "http://localhost:8000/win-64");
|
||||||
|
CHECK_EQ(channels1.front().url().str(), "http://localhost:8000/");
|
||||||
const UrlSet expected_urls({ std::string("http://localhost:8000/") + platform,
|
const UrlSet expected_urls({ std::string("http://localhost:8000/") + platform,
|
||||||
"http://localhost:8000/noarch" });
|
"http://localhost:8000/noarch" });
|
||||||
CHECK_EQ(c.urls(true), expected_urls);
|
CHECK_EQ(channels1.front().urls(true), expected_urls);
|
||||||
const Channel& c4 = channel_context.make_channel("http://localhost:8000");
|
|
||||||
CHECK_EQ(c4.platform_url("linux-64", false), "http://localhost:8000/linux-64");
|
const auto channels4 = channel_context.make_channel("http://localhost:8000");
|
||||||
const Channel& c2 = channel_context.make_channel("http://user:test@localhost:8000/");
|
REQUIRE_EQ(channels4.size(), 1);
|
||||||
CHECK_EQ(c2.platform_url("win-64", false), "http://localhost:8000/win-64");
|
CHECK_EQ(channels4.front().platform_url("linux-64", false), "http://localhost:8000/linux-64");
|
||||||
CHECK_EQ(c2.platform_url("win-64", true), "http://user:test@localhost:8000/win-64");
|
|
||||||
const Channel& c3 = channel_context.make_channel(
|
const auto channels2 = channel_context.make_channel("http://user:test@localhost:8000/");
|
||||||
"https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012"
|
REQUIRE_EQ(channels2.size(), 1);
|
||||||
);
|
CHECK_EQ(channels2.front().platform_url("win-64", false), "http://localhost:8000/win-64");
|
||||||
CHECK_EQ(c3.platform_url("win-64", false), "https://localhost:8000/win-64");
|
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
c3.platform_url("win-64", true),
|
channels2.front().platform_url("win-64", true),
|
||||||
"https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/win-64"
|
"http://user:test@localhost:8000/win-64"
|
||||||
);
|
);
|
||||||
|
|
||||||
const UrlSet expected_urls2({
|
const auto channels3 = channel_context.make_channel(
|
||||||
|
"https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012"
|
||||||
|
);
|
||||||
|
REQUIRE_EQ(channels3.size(), 1);
|
||||||
|
CHECK_EQ(channels3.front().platform_url("win-64", false), "https://localhost:8000/win-64");
|
||||||
|
CHECK_EQ(
|
||||||
|
channels3.front().platform_url("win-64", true),
|
||||||
|
"https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/win-64"
|
||||||
|
);
|
||||||
|
const UrlSet expected_urls3({
|
||||||
std::string("https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/")
|
std::string("https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/")
|
||||||
+ platform,
|
+ platform,
|
||||||
"https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/noarch",
|
"https://localhost:8000/t/xy-12345678-1234-1234-1234-123456789012/noarch",
|
||||||
});
|
});
|
||||||
|
CHECK_EQ(channels3.front().urls(true), expected_urls3);
|
||||||
CHECK_EQ(c3.urls(true), expected_urls2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("load_tokens")
|
TEST_CASE("load_tokens")
|
||||||
|
|
|
@ -330,14 +330,17 @@ namespace
|
||||||
auto load_channels(MPool& pool, MultiPackageCache& cache, std::vector<std::string>&& channels)
|
auto load_channels(MPool& pool, MultiPackageCache& cache, std::vector<std::string>&& channels)
|
||||||
{
|
{
|
||||||
auto sub_dirs = std::vector<MSubdirData>();
|
auto sub_dirs = std::vector<MSubdirData>();
|
||||||
for (const auto& chan : pool.channel_context().get_channels(channels))
|
for (const auto& location : channels)
|
||||||
{
|
{
|
||||||
for (auto& [platform, url] : chan.platform_urls(true))
|
for (const auto& chan : pool.channel_context().make_channel(location))
|
||||||
{
|
{
|
||||||
auto sub_dir = expected_value_or_throw(
|
for (auto& [platform, url] : chan.platform_urls(true))
|
||||||
MSubdirData::create(pool.channel_context(), chan, platform, url, cache)
|
{
|
||||||
);
|
auto sub_dir = expected_value_or_throw(
|
||||||
sub_dirs.push_back(std::move(sub_dir));
|
MSubdirData::create(pool.channel_context(), chan, platform, url, cache)
|
||||||
|
);
|
||||||
|
sub_dirs.push_back(std::move(sub_dir));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1147,47 +1147,8 @@ bind_submodule_impl(pybind11::module_ m)
|
||||||
py::arg("json_str")
|
py::arg("json_str")
|
||||||
);
|
);
|
||||||
|
|
||||||
pyChannel
|
|
||||||
.def(py::init(
|
|
||||||
[](const std::string& value) {
|
|
||||||
return const_cast<Channel*>(&mambapy::singletons.channel_context().make_channel(value)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
))
|
|
||||||
.def_property_readonly("platforms", &Channel::platforms)
|
|
||||||
.def_property_readonly("canonical_name", &Channel::display_name)
|
|
||||||
.def("urls", &Channel::urls, py::arg("with_credentials") = true)
|
|
||||||
.def("platform_urls", &Channel::platform_urls, py::arg("with_credentials") = true)
|
|
||||||
.def("platform_url", &Channel::platform_url, py::arg("platform"), py::arg("with_credentials") = true)
|
|
||||||
.def(
|
|
||||||
"__repr__",
|
|
||||||
[](const Channel& c)
|
|
||||||
{
|
|
||||||
auto s = c.display_name();
|
|
||||||
s += "[";
|
|
||||||
bool first = true;
|
|
||||||
for (const auto& platform : c.platforms())
|
|
||||||
{
|
|
||||||
if (!first)
|
|
||||||
{
|
|
||||||
s += ",";
|
|
||||||
}
|
|
||||||
s += platform;
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
s += "]";
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
m.def("clean", [](int flags) { return clean(mambapy::singletons.config(), flags); });
|
m.def("clean", [](int flags) { return clean(mambapy::singletons.config(), flags); });
|
||||||
|
|
||||||
m.def(
|
|
||||||
"get_channels",
|
|
||||||
[](const std::vector<std::string>& channel_names)
|
|
||||||
{ return mambapy::singletons.channel_context().get_channels(channel_names); }
|
|
||||||
);
|
|
||||||
|
|
||||||
m.def(
|
m.def(
|
||||||
"transmute",
|
"transmute",
|
||||||
+[](const fs::u8path& pkg_file, const fs::u8path& target, int compression_level, int compression_threads
|
+[](const fs::u8path& pkg_file, const fs::u8path& target, int compression_level, int compression_threads
|
||||||
|
|
|
@ -144,11 +144,8 @@ set_env_command(CLI::App* com, Configuration& config)
|
||||||
|
|
||||||
for (const auto& record : records)
|
for (const auto& record : records)
|
||||||
{
|
{
|
||||||
auto url = specs::CondaURL::parse(record.url);
|
using Credentials = typename specs::CondaURL::Credentials;
|
||||||
url.clear_token();
|
std::cout << specs::CondaURL::parse(record.url).str(Credentials::Hide);
|
||||||
url.clear_password();
|
|
||||||
url.clear_user();
|
|
||||||
std::cout << url.str();
|
|
||||||
if (no_md5 != 1)
|
if (no_md5 != 1)
|
||||||
{
|
{
|
||||||
std::cout << "#" << record.md5;
|
std::cout << "#" << record.md5;
|
||||||
|
@ -176,7 +173,7 @@ set_env_command(CLI::App* com, Configuration& config)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Channel& channel = channel_context.make_channel(v.channel);
|
auto chans = channel_context.make_channel(v.channel);
|
||||||
|
|
||||||
if (from_history)
|
if (from_history)
|
||||||
{
|
{
|
||||||
|
@ -187,7 +184,10 @@ set_env_command(CLI::App* com, Configuration& config)
|
||||||
dependencies << "- ";
|
dependencies << "- ";
|
||||||
if (channel_subdir)
|
if (channel_subdir)
|
||||||
{
|
{
|
||||||
dependencies << channel.display_name() << "/" << v.subdir << "::";
|
dependencies
|
||||||
|
// If the size is not one, it's a custom mutli channel
|
||||||
|
<< ((chans.size() == 1) ? chans.front().display_name() : v.channel)
|
||||||
|
<< "/" << v.subdir << "::";
|
||||||
}
|
}
|
||||||
dependencies << v.name << "=" << v.version;
|
dependencies << v.name << "=" << v.version;
|
||||||
if (!no_build)
|
if (!no_build)
|
||||||
|
@ -201,7 +201,10 @@ set_env_command(CLI::App* com, Configuration& config)
|
||||||
dependencies << "\n";
|
dependencies << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
channels.insert(channel.display_name());
|
for (auto const& chan : chans)
|
||||||
|
{
|
||||||
|
channels.insert(chan.display_name());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& c : channels)
|
for (const auto& c : channels)
|
||||||
|
|
Loading…
Reference in New Issue