Skip to content

Commit

Permalink
Channel initialization (#2953)
Browse files Browse the repository at this point in the history
* Set default_channels at config level

* Resolve default multi channel at the config level

* Fix Yaml source printers

* Resolve local multi channel at the config level

* Remove ChannelContext::make_simple_channel

* Remove Channel::name usage

* Factorize split_once functions

* Try looking for name match in URL path

* Refactor ending_splits_in

* Code improvement

* Replace get_common_parts with concat_dedup

* Remove Channel::name

* Remove Channel::location

* Use URL for priority in channel loader

* Make Channel value-based

* Add range hashing

* Add Channel comparison and hash

* Make channel map/list return by value

* Resolve 1

* Resolve 2

* Resolve 3

* Remove unknown channels

* Hide get_known_platforms

* Add unknown ChannelSpec

* Remove unused function

* Rename Channel::canonical_name > display_name

* Remove Channel friend class

* Add Channel::resolve

* Remove ChannelContext::from_value
  • Loading branch information
AntoinePrv authored Nov 15, 2023
1 parent ddea95e commit cd744e7
Show file tree
Hide file tree
Showing 26 changed files with 839 additions and 672 deletions.
2 changes: 1 addition & 1 deletion Taskfile.dist.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ tasks:
Mamba. Many tasks are automatically run inside this environment.
The environment is located at "{{.DEV_ENV_DIR}}" and can also be activated with micromamba to
benefit from the executables and LSP tools.
cmds: [{task: '_create-env', vars: {prefix: '{{.DEV_ENV_DIR}}'}}]
cmds: [{task: '_create-env', vars: {prefix: '{{.PWD}}/{{.DEV_ENV_DIR}}'}}]

create-test-env:
desc: Create a local test environment with as a copy of the dev environment.
Expand Down
101 changes: 49 additions & 52 deletions libmamba/include/mamba/core/channel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
#ifndef MAMBA_CORE_CHANNEL_HPP
#define MAMBA_CORE_CHANNEL_HPP

#include <map>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>

#include "mamba/specs/conda_url.hpp"
Expand All @@ -26,27 +26,43 @@ namespace mamba
namespace specs
{
class ChannelSpec;
class AuthenticationDataBase;
}

std::vector<std::string> get_known_platforms();

// Note: Channels can only be created using ChannelContext.
class Channel
{
public:

Channel(const Channel&) = delete;
Channel& operator=(const Channel&) = delete;
Channel(Channel&&) noexcept = default;
Channel& operator=(Channel&&) noexcept = default;
struct ResolveParams
{
using platform_list = util::flat_set<std::string>;
using channel_list = std::vector<Channel>;
using channel_map = std::map<std::string, Channel>;
using multichannel_map = std::unordered_map<std::string, channel_list>;

const platform_list& platforms;
const specs::CondaURL& channel_alias;
const channel_map& custom_channels;
const specs::AuthenticationDataBase& auth_db;

// TODO add CWD and home
};

using platform_list = util::flat_set<std::string>;

~Channel();
[[nodiscard]] static auto resolve(specs::ChannelSpec spec, ResolveParams params) -> Channel;

const std::string& location() const;
const std::string& name() const;
const std::string& canonical_name() const;
const util::flat_set<std::string>& platforms() const;
const specs::CondaURL& url() const;
Channel(specs::CondaURL url, std::string display_name, util::flat_set<std::string> platforms = {});

[[nodiscard]] auto url() const -> const specs::CondaURL&;
void set_url(specs::CondaURL url);

[[nodiscard]] auto platforms() const -> const platform_list&;
void set_platforms(platform_list platforms);

[[nodiscard]] auto display_name() const -> const std::string&;
void set_display_name(std::string display_name);

std::string base_url() const;
std::string platform_url(std::string_view platform, bool with_credential = true) const;
Expand All @@ -57,38 +73,33 @@ namespace mamba

private:

Channel(
specs::CondaURL url,
std::string location,
std::string name,
std::string canonical_name,
util::flat_set<std::string> platforms = {}
);

specs::CondaURL m_url;
std::string m_location;
std::string m_name;
std::string m_canonical_name;
std::string m_display_name;
util::flat_set<std::string> m_platforms;

// Note: as long as Channel is not a regular value-type and we want each
// instance only possible to create through ChannelContext, we need
// to have Channel's constructor only available to ChannelContext,
// therefore enabling it's use through this `friend` statement.
// However, all this should be removed as soon as Channel is changed to
// be a regular value-type (regular as in the regular concept).
friend class ChannelContext;
};

using ChannelCache = std::map<std::string, Channel>;
/** Tuple-like equality of all observable members */
auto operator==(const Channel& a, const Channel& b) -> bool;
auto operator!=(const Channel& a, const Channel& b) -> bool;
}

template <>
struct std::hash<mamba::Channel>
{
auto operator()(const mamba::Channel& c) const -> std::size_t;
};


namespace mamba
{

class ChannelContext
{
public:

using channel_list = std::vector<std::string>;
using channel_map = std::map<std::string, Channel>;
using multichannel_map = std::map<std::string, std::vector<std::string>>;
using channel_list = std::vector<Channel>;
using multichannel_map = std::unordered_map<std::string, channel_list>;

ChannelContext(Context& context);
~ChannelContext();
Expand All @@ -99,7 +110,7 @@ namespace mamba
ChannelContext& operator=(ChannelContext&&) = delete;

const Channel& make_channel(const std::string& value);
std::vector<const Channel*> get_channels(const std::vector<std::string>& channel_names);
auto get_channels(const std::vector<std::string>& channel_names) -> channel_list;

const specs::CondaURL& get_channel_alias() const;
const channel_map& get_custom_channels() const;
Expand All @@ -112,29 +123,15 @@ namespace mamba

private:

using ChannelCache = std::map<std::string, Channel>;

Context& m_context;
ChannelCache m_channel_cache;
specs::CondaURL m_channel_alias;
channel_map m_custom_channels;
multichannel_map m_custom_multichannels;

void init_custom_channels();

Channel make_simple_channel(
const specs::CondaURL& channel_alias,
const std::string& channel_url,
const std::string& channel_name,
const std::string& channel_canonical_name
);

Channel from_any_path(specs::ChannelSpec&& spec);
Channel from_package_path(specs::ChannelSpec&& spec);
Channel from_path(specs::ChannelSpec&& spec);
Channel from_any_url(specs::ChannelSpec&& spec);
Channel from_package_url(specs::ChannelSpec&& spec);
Channel from_url(specs::ChannelSpec&& spec);
Channel from_name(specs::ChannelSpec&& spec);
Channel from_value(const std::string& value);
};

} // namespace mamba
Expand Down
19 changes: 16 additions & 3 deletions libmamba/include/mamba/specs/channel_spec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#ifndef MAMBA_SPECS_CHANNEL_SPEC_HPP
#define MAMBA_SPECS_CHANNEL_SPEC_HPP

#include <array>
#include <string>
#include <string_view>

Expand Down Expand Up @@ -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 = "<unknown>";
static constexpr std::array<std::string_view, 4> invalid_channels_lower = {
"<unknown>",
"none:///<unknown>",
"none",
":///<unknown>",
};

using dynamic_platform_set = util::flat_set<std::string>;

Expand All @@ -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
32 changes: 24 additions & 8 deletions libmamba/include/mamba/util/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <optional>
#include <sstream>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -192,6 +194,16 @@ namespace mamba::util
template <typename UnaryFunc>
std::array<std::wstring_view, 3> strip_if_parts(std::wstring_view input, UnaryFunc should_strip);

[[nodiscard]] auto split_once(std::string_view str, char sep)
-> std::tuple<std::string_view, std::optional<std::string_view>>;
[[nodiscard]] auto split_once(std::string_view str, std::string_view sep)
-> std::tuple<std::string_view, std::optional<std::string_view>>;

[[nodiscard]] auto rsplit_once(std::string_view str, char sep)
-> std::tuple<std::optional<std::string_view>, std::string_view>;
[[nodiscard]] auto rsplit_once(std::string_view str, std::string_view sep)
-> std::tuple<std::optional<std::string_view>, std::string_view>;

std::vector<std::string>
split(std::string_view input, std::string_view sep, std::size_t max_split = SIZE_MAX);
std::vector<std::wstring>
Expand All @@ -202,6 +214,18 @@ namespace mamba::util
std::vector<std::wstring>
rsplit(std::wstring_view input, std::wstring_view sep, std::size_t max_split = SIZE_MAX);

/**
* Concatenate string while removing the suffix of the first that may be prefix of second.
*
* Comparison are done as if comparing elements in a split given by @p sep.
* For instance "private/channel" and "channel/label/foo" with separator "/"
* would return "private/channel/label/foo", but "private/chan" and "channel/label/foo"
* would return the "private/chan/channel/label/foo".
*/
std::string concat_dedup_splits(std::string_view str1, std::string_view str2, char sep);
std::string
concat_dedup_splits(std::string_view str1, std::string_view str2, std::string_view sep);

void replace_all(std::string& data, std::string_view search, std::string_view replace);
void replace_all(std::wstring& data, std::wstring_view search, std::wstring_view replace);

Expand Down Expand Up @@ -643,14 +667,6 @@ namespace mamba::util
return hex_string(buffer, buffer.size());
}

/**
* Return the common parts of two strings by blocks located between the given sep,
* and considering that these common parts would be located at the end of str1 (search from
* left to right).
* str1 is considered smaller than (or equal to) str2.
* cf. Channels use case.
*/
std::string get_common_parts(std::string_view str1, std::string_view str2, std::string_view sep);
}

#endif
29 changes: 25 additions & 4 deletions libmamba/include/mamba/util/tuple_hash.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,41 @@

#include <functional>
#include <tuple>
#include <type_traits>

namespace mamba::util
{
constexpr void hash_combine(std::size_t& seed, std::size_t other)
constexpr auto hash_combine(std::size_t seed, std::size_t other) -> std::size_t
{
const auto boost_magic_num = 0x9e3779b9;
seed ^= other + boost_magic_num + (seed << 6) + (seed >> 2);
return seed;
}

template <class T, typename Hasher = std::hash<T>>
constexpr void hash_combine_val(std::size_t& seed, const T& val, const Hasher& hasher = {})
constexpr auto hash_combine_val(std::size_t seed, const T& val, const Hasher& hasher = {})
-> std::size_t
{
hash_combine(seed, hasher(val));
return hash_combine(seed, hasher(val));
}

template <typename Iter, typename Hasher = std::hash<std::decay_t<decltype(*std::declval<Iter>())>>>
auto hash_combine_val_range(std::size_t seed, Iter first, Iter last, const Hasher& hasher = {})
-> std::size_t
{
for (; first != last; ++first)
{
seed = hash_combine_val(seed, hasher(*first));
}
return seed;
}

template <typename... T>
constexpr auto hash_vals(const T&... vals) -> std::size_t
{
std::size_t seed = 0;
(hash_combine_val(seed, vals), ...);
auto combine = [&seed](const auto& val) { seed = hash_combine_val(seed, val); };
(combine(vals), ...);
return seed;
}

Expand All @@ -46,5 +61,11 @@ namespace mamba::util
return hash_tuple(t);
}
};

template <typename Range>
constexpr auto hash_range(const Range& rng) -> std::size_t
{
return hash_combine_val_range(0, rng.begin(), rng.end());
}
}
#endif
10 changes: 5 additions & 5 deletions libmamba/src/api/channel_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,19 @@ namespace mamba

std::vector<std::pair<int, int>> priorities;
int max_prio = static_cast<int>(channel_urls.size());
std::string prev_channel_name;
auto prev_channel_url = specs::CondaURL();

Console::instance().init_progress_bar_manager(ProgressBarMode::multi);

std::vector<mamba_error> error_list;

for (auto channel : pool.channel_context().get_channels(channel_urls))
{
for (auto& [platform, url] : channel->platform_urls(true))
for (auto& [platform, url] : channel.platform_urls(true))
{
auto sdires = MSubdirData::create(
pool.channel_context(),
*channel,
channel,
platform,
url,
package_caches,
Expand All @@ -89,10 +89,10 @@ namespace mamba
else
{
// Consider 'flexible' and 'strict' the same way
if (channel->canonical_name() != prev_channel_name)
if (channel.url() != prev_channel_url)
{
max_prio--;
prev_channel_name = channel->canonical_name();
prev_channel_url = channel.url();
}
priorities.push_back(std::make_pair(max_prio, 0));
}
Expand Down
Loading

0 comments on commit cd744e7

Please sign in to comment.