mirror of https://github.com/mamba-org/mamba.git
MatchSpec use VersionSpec (#3089)
* Don't use members as wip vars * Make conda-build compatible VersionSpec str * Add VersionSpec::is_explicitly_free * Strenghten sat attrs ref * Try pluging VersionSpec in MatchSpec * Change type of MatchSpec::version * Fix MatchSpec::conda_build_str * Adjust MatchSpec tests
This commit is contained in:
parent
108bc9f5a4
commit
b9706dce32
|
@ -14,6 +14,7 @@
|
|||
#include <unordered_map>
|
||||
|
||||
#include "mamba/specs/channel_spec.hpp"
|
||||
#include "mamba/specs/version_spec.hpp"
|
||||
|
||||
namespace mamba::specs
|
||||
{
|
||||
|
@ -37,8 +38,8 @@ namespace mamba::specs
|
|||
[[nodiscard]] auto name() const -> const std::string&;
|
||||
void set_name(std::string name);
|
||||
|
||||
[[nodiscard]] auto version() const -> const std::string&;
|
||||
void set_version(std::string ver);
|
||||
[[nodiscard]] auto version() const -> const VersionSpec&;
|
||||
void set_version(VersionSpec ver);
|
||||
|
||||
[[nodiscard]] auto build_number() const -> const std::string&;
|
||||
void set_build_number(std::string num);
|
||||
|
@ -67,9 +68,9 @@ namespace mamba::specs
|
|||
private:
|
||||
|
||||
std::optional<ChannelSpec> m_channel;
|
||||
VersionSpec m_version;
|
||||
std::string m_name_space;
|
||||
std::string m_name;
|
||||
std::string m_version;
|
||||
std::string m_build_number;
|
||||
std::string m_build_string;
|
||||
// TODO can put inside channel spec
|
||||
|
|
|
@ -48,6 +48,13 @@ namespace mamba::specs
|
|||
|
||||
[[nodiscard]] auto str() const -> std::string;
|
||||
|
||||
/**
|
||||
* An alternative string representation of the version spec.
|
||||
*
|
||||
* Attempts to be compatible with conda-build/libsolv.
|
||||
*/
|
||||
[[nodiscard]] auto str_conda_build() const -> std::string;
|
||||
|
||||
private:
|
||||
|
||||
struct free_interval
|
||||
|
@ -148,6 +155,15 @@ namespace mamba::specs
|
|||
VersionSpec() = default;
|
||||
explicit VersionSpec(tree_type&& tree) noexcept;
|
||||
|
||||
/**
|
||||
* Returns wether the VersionSpec is unconstrained.
|
||||
*
|
||||
* Due to the complex nature of VersionSpec expressions, it is not always easy to know
|
||||
* whether a complex expression can be simpified to the unconstrained one.
|
||||
* This functions only handles the trivial cases.
|
||||
*/
|
||||
[[nodiscard]] auto is_explicitly_free() const -> bool;
|
||||
|
||||
/**
|
||||
* A string representation of the version spec.
|
||||
*
|
||||
|
@ -156,6 +172,13 @@ namespace mamba::specs
|
|||
*/
|
||||
[[nodiscard]] auto str() const -> std::string;
|
||||
|
||||
/**
|
||||
* An alternative string representation of the version spec.
|
||||
*
|
||||
* Attempts to be compatible with conda-build/libsolv.
|
||||
*/
|
||||
[[nodiscard]] auto str_conda_build() const -> std::string;
|
||||
|
||||
/**
|
||||
* True if the set described by the VersionSpec contains the given version.
|
||||
*/
|
||||
|
@ -177,6 +200,11 @@ namespace mamba::specs
|
|||
template <>
|
||||
struct fmt::formatter<mamba::specs::VersionPredicate>
|
||||
{
|
||||
/**
|
||||
* Change the representation of some predicates not understood by conda-build/libsolv.
|
||||
*/
|
||||
bool conda_build_form = false;
|
||||
|
||||
auto parse(format_parse_context& ctx) -> decltype(ctx.begin());
|
||||
|
||||
auto format(const ::mamba::specs::VersionPredicate& pred, format_context& ctx)
|
||||
|
@ -186,6 +214,11 @@ struct fmt::formatter<mamba::specs::VersionPredicate>
|
|||
template <>
|
||||
struct fmt::formatter<mamba::specs::VersionSpec>
|
||||
{
|
||||
/**
|
||||
* Change the representation of some predicates not understood by conda-build/libsolv.
|
||||
*/
|
||||
bool conda_build_form = false;
|
||||
|
||||
auto parse(format_parse_context& ctx) -> decltype(ctx.begin());
|
||||
|
||||
auto format(const ::mamba::specs::VersionSpec& spec, format_context& ctx) -> decltype(ctx.out());
|
||||
|
|
|
@ -358,7 +358,7 @@ namespace mamba
|
|||
PackageInfo p(ms.name());
|
||||
p.url = ms.url();
|
||||
p.build_string = ms.build_string();
|
||||
p.version = ms.version();
|
||||
p.version = ms.version().str();
|
||||
if (ms.channel().has_value())
|
||||
{
|
||||
p.channel = ms.channel()->location();
|
||||
|
|
|
@ -148,7 +148,7 @@ namespace mamba
|
|||
|
||||
std::vector<old_node_id_list> groups{};
|
||||
|
||||
std::size_t const n_nodes = node_indices.size();
|
||||
const std::size_t n_nodes = node_indices.size();
|
||||
std::vector<bool> node_added_to_a_group(n_nodes, false);
|
||||
for (std::size_t i = 0; i < n_nodes; ++i)
|
||||
{
|
||||
|
@ -538,14 +538,45 @@ namespace mamba
|
|||
* Implementation of CompressedProblemsGraph::RoughCompare *
|
||||
*************************************************************/
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename T>
|
||||
auto invoke_name(T&& e) -> decltype(auto)
|
||||
{
|
||||
using TT = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
return std::invoke(&TT::name, std::forward<T>(e));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto invoke_version(T&& e) -> decltype(auto)
|
||||
{
|
||||
using TT = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
using Ver = decltype(std::invoke(&TT::version, std::forward<T>(e)));
|
||||
Ver v = std::invoke(&TT::version, std::forward<T>(e));
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(v)>, specs::VersionSpec>)
|
||||
{
|
||||
return std::forward<Ver>(v).str();
|
||||
}
|
||||
else
|
||||
{
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool CompressedProblemsGraph::RoughCompare<T>::operator()(const T& a, const T& b) const
|
||||
auto CompressedProblemsGraph::RoughCompare<T>::operator()(const T& a, const T& b) const -> bool
|
||||
{
|
||||
auto attrs = [](const auto& x)
|
||||
{
|
||||
return std::tie(
|
||||
std::invoke(&T::name, x),
|
||||
std::invoke(&T::version, x),
|
||||
using Attrs = std::tuple<
|
||||
decltype(invoke_name(x)),
|
||||
decltype(invoke_version(x)),
|
||||
decltype(std::invoke(&T::build_number, x)),
|
||||
decltype(std::invoke(&T::build_string, x))>;
|
||||
return Attrs(
|
||||
invoke_name(x),
|
||||
invoke_version(x),
|
||||
std::invoke(&T::build_number, x),
|
||||
std::invoke(&T::build_string, x)
|
||||
);
|
||||
|
@ -562,16 +593,6 @@ namespace mamba
|
|||
* Implementation of CompressedProblemsGraph::NamedList *
|
||||
**********************************************************/
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename T>
|
||||
decltype(auto) invoke_name(T&& e)
|
||||
{
|
||||
using TT = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
return std::invoke(&TT::name, std::forward<T>(e));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
template <typename InputIterator>
|
||||
CompressedProblemsGraph::NamedList<T, A>::NamedList(InputIterator first, InputIterator last)
|
||||
|
@ -650,13 +671,13 @@ namespace mamba
|
|||
) const -> std::pair<std::string, std::size_t>
|
||||
{
|
||||
auto versions = std::vector<std::string>(size());
|
||||
auto invoke_version = [](auto&& v) -> decltype(auto)
|
||||
{
|
||||
using TT = std::remove_cv_t<std::remove_reference_t<decltype(v)>>;
|
||||
return std::invoke(&TT::version, std::forward<decltype(v)>(v));
|
||||
};
|
||||
// TODO(C++20) *this | std::ranges::transform(invoke_version) | ranges::unique
|
||||
std::transform(begin(), end(), versions.begin(), invoke_version);
|
||||
std::transform(
|
||||
begin(),
|
||||
end(),
|
||||
versions.begin(),
|
||||
[](const auto& x) { return invoke_version(x); }
|
||||
);
|
||||
if (remove_duplicates)
|
||||
{
|
||||
versions.erase(std::unique(versions.begin(), versions.end()), versions.end());
|
||||
|
@ -1036,7 +1057,7 @@ namespace mamba
|
|||
|
||||
const TreeNodeIter children_begin = out;
|
||||
// TODO(C++20) an enumerate view ``views::zip(views::iota(), children_ids)``
|
||||
std::size_t const n_children = children_ids.size();
|
||||
const std::size_t n_children = children_ids.size();
|
||||
for (std::size_t i = 0; i < n_children; ++i)
|
||||
{
|
||||
const bool last = (i == n_children - 1);
|
||||
|
@ -1228,7 +1249,7 @@ namespace mamba
|
|||
|
||||
void TreeExplainer::write_ancestry(const std::vector<SiblingNumber>& ancestry)
|
||||
{
|
||||
std::size_t const size = ancestry.size();
|
||||
const std::size_t size = ancestry.size();
|
||||
const auto indents = m_format.indents;
|
||||
if (size > 0)
|
||||
{
|
||||
|
@ -1434,7 +1455,7 @@ namespace mamba
|
|||
|
||||
void TreeExplainer::write_path(const std::vector<TreeNode>& path)
|
||||
{
|
||||
std::size_t const length = path.size();
|
||||
const std::size_t length = path.size();
|
||||
for (std::size_t i = 0; i < length; ++i)
|
||||
{
|
||||
const bool last = (i == length - 1);
|
||||
|
|
|
@ -96,7 +96,8 @@ namespace mamba
|
|||
return m_jobs->push_back(job_flag | SOLVER_SOLVABLE_PROVIDES, m_pool.matchspec2id(ms));
|
||||
}
|
||||
|
||||
if (ms.channel().has_value() || !ms.version().empty() || !ms.build_string().empty())
|
||||
if (ms.channel().has_value() || !ms.version().is_explicitly_free()
|
||||
|| !ms.build_string().empty())
|
||||
{
|
||||
Console::stream() << ms.conda_build_form()
|
||||
<< ": overriding channel, version and build from "
|
||||
|
@ -105,7 +106,7 @@ namespace mamba
|
|||
|
||||
auto ms_modified = ms;
|
||||
ms_modified.set_channel(specs::ChannelSpec::parse(solvable->channel()));
|
||||
ms_modified.set_version(std::string(solvable->version()));
|
||||
ms_modified.set_version(specs::VersionSpec::parse(solvable->version()));
|
||||
ms_modified.set_build_string(std::string(solvable->build_string()));
|
||||
|
||||
LOG_INFO << "Reinstall " << ms_modified.conda_build_form() << " from channel "
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace mamba
|
|||
auto& p = out.back();
|
||||
p.url = ms.url();
|
||||
p.build_string = ms.build_string();
|
||||
p.version = ms.version();
|
||||
p.version = ms.version().str_conda_build();
|
||||
if (ms.channel().has_value())
|
||||
{
|
||||
p.channel = ms.channel()->location();
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace mamba::specs
|
|||
|
||||
// Version
|
||||
std::tie(head, tail) = util::rsplit_once(head.value(), '-');
|
||||
out.m_version = tail;
|
||||
out.m_version = VersionSpec::parse(tail);
|
||||
if (!head.has_value())
|
||||
{
|
||||
fail_parse();
|
||||
|
@ -192,12 +192,14 @@ namespace mamba::specs
|
|||
spec_str.push_back('*');
|
||||
}
|
||||
// This is #6 of the spec parsing
|
||||
// Look for version *and* build string and separator
|
||||
auto version_and_build = std::string();
|
||||
static std::regex version_build_re("([^ =<>!~]+)?([><!=~ ].+)?");
|
||||
std::smatch vb_match;
|
||||
if (std::regex_match(spec_str, vb_match, version_build_re))
|
||||
{
|
||||
out.m_name = vb_match[1].str();
|
||||
out.m_version = util::strip(vb_match[2].str());
|
||||
version_and_build = util::strip(vb_match[2].str());
|
||||
if (out.m_name.size() == 0)
|
||||
{
|
||||
throw std::runtime_error("Invalid spec, no package name found: " + spec_str);
|
||||
|
@ -210,9 +212,9 @@ namespace mamba::specs
|
|||
|
||||
// # Step 7. otherwise sort out version + build
|
||||
// spec_str = spec_str and spec_str.strip()
|
||||
if (!out.m_version.empty())
|
||||
if (!version_and_build.empty())
|
||||
{
|
||||
if (out.m_version.find('[') != out.m_version.npos)
|
||||
if (version_and_build.find('[') != std::string::npos)
|
||||
{
|
||||
throw std::runtime_error(util::concat(
|
||||
R"(Invalid match spec: multiple bracket sections not allowed ")",
|
||||
|
@ -221,38 +223,15 @@ namespace mamba::specs
|
|||
));
|
||||
}
|
||||
|
||||
out.m_version = std::string(util::strip(out.m_version));
|
||||
auto [pv, pb] = parse_version_and_build(std::string(util::strip(out.m_version)));
|
||||
auto [pv, pb] = parse_version_and_build(version_and_build);
|
||||
|
||||
out.m_version = pv;
|
||||
out.m_version = VersionSpec::parse(pv);
|
||||
out.m_build_string = pb;
|
||||
|
||||
// translate version '=1.2.3' to '1.2.3*'
|
||||
// is it a simple version starting with '='? i.e. '=1.2.3'
|
||||
if (out.m_version.size() >= 2 && out.m_version[0] == '=')
|
||||
{
|
||||
auto rest = out.m_version.substr(1);
|
||||
if (out.m_version[1] == '=' && out.m_build_string.empty())
|
||||
{
|
||||
out.m_version = out.m_version.substr(2);
|
||||
}
|
||||
else if (rest.find_first_of("=,|") == rest.npos)
|
||||
{
|
||||
if (out.m_build_string.empty() && out.m_version.back() != '*')
|
||||
{
|
||||
out.m_version = util::concat(out.m_version, "*");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.m_version = rest;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else // no-op
|
||||
{
|
||||
out.m_version = "";
|
||||
out.m_build_string = "";
|
||||
out.m_version = {};
|
||||
out.m_build_string = {};
|
||||
}
|
||||
|
||||
// TODO think about using a hash function here, (and elsewhere), like:
|
||||
|
@ -270,7 +249,7 @@ namespace mamba::specs
|
|||
}
|
||||
else if (k == "version")
|
||||
{
|
||||
out.m_version = v;
|
||||
out.m_version = VersionSpec::parse(v);
|
||||
}
|
||||
else if (k == "channel")
|
||||
{
|
||||
|
@ -351,12 +330,12 @@ namespace mamba::specs
|
|||
m_name = std::move(name);
|
||||
}
|
||||
|
||||
auto MatchSpec::version() const -> const std::string&
|
||||
auto MatchSpec::version() const -> const VersionSpec&
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
|
||||
void MatchSpec::set_version(std::string ver)
|
||||
void MatchSpec::set_version(VersionSpec ver)
|
||||
{
|
||||
m_version = std::move(ver);
|
||||
}
|
||||
|
@ -405,14 +384,17 @@ namespace mamba::specs
|
|||
{
|
||||
std::stringstream res;
|
||||
res << m_name;
|
||||
if (!m_version.empty())
|
||||
if (!m_version.is_explicitly_free())
|
||||
{
|
||||
res << " " << m_version;
|
||||
// if (!build.empty() && (build != "*"))
|
||||
if (!m_build_string.empty())
|
||||
{
|
||||
res << " " << m_build_string;
|
||||
}
|
||||
res << " " << m_version.str_conda_build();
|
||||
}
|
||||
else if (!m_build_string.empty())
|
||||
{
|
||||
res << " *";
|
||||
}
|
||||
if (!m_build_string.empty())
|
||||
{
|
||||
res << " " << m_build_string;
|
||||
}
|
||||
return res.str();
|
||||
}
|
||||
|
@ -453,50 +435,16 @@ namespace mamba::specs
|
|||
auto is_complex_relation = [](const std::string& s)
|
||||
{ return s.find_first_of("><$^|,") != s.npos; };
|
||||
|
||||
if (!m_version.empty())
|
||||
if (!m_version.is_explicitly_free())
|
||||
{
|
||||
if (is_complex_relation(m_version))
|
||||
auto ver = m_version.str();
|
||||
if (is_complex_relation(ver)) // TODO do on VersionSpec
|
||||
{
|
||||
formatted_brackets.push_back(util::concat("version='", m_version, "'"));
|
||||
}
|
||||
else if (util::starts_with(m_version, "!=") || util::starts_with(m_version, "~="))
|
||||
{
|
||||
if (!m_build_string.empty())
|
||||
{
|
||||
formatted_brackets.push_back(util::concat("version='", m_version, "'"));
|
||||
}
|
||||
else
|
||||
{
|
||||
res << " " << m_version;
|
||||
}
|
||||
}
|
||||
else if (util::ends_with(m_version, ".*"))
|
||||
{
|
||||
res << "=" + m_version.substr(0, m_version.size() - 2);
|
||||
}
|
||||
else if (m_version.back() == '*')
|
||||
{
|
||||
if (m_version.size() == 1)
|
||||
{
|
||||
res << "=*";
|
||||
}
|
||||
else if (util::starts_with(m_version, "="))
|
||||
{
|
||||
res << m_version.substr(0, m_version.size() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
res << "=" + m_version.substr(0, m_version.size() - 1);
|
||||
}
|
||||
}
|
||||
else if (util::starts_with(m_version, "=="))
|
||||
{
|
||||
res << m_version;
|
||||
version_exact = true;
|
||||
formatted_brackets.push_back(util::concat("version='", ver, "'"));
|
||||
}
|
||||
else
|
||||
{
|
||||
res << "==" << m_version;
|
||||
res << ver;
|
||||
version_exact = true;
|
||||
}
|
||||
}
|
||||
|
@ -566,7 +514,7 @@ namespace mamba::specs
|
|||
|
||||
auto MatchSpec::is_simple() const -> bool
|
||||
{
|
||||
return m_version.empty() && m_build_string.empty() && m_build_number.empty();
|
||||
return m_version.is_explicitly_free() && m_build_string.empty() && m_build_number.empty();
|
||||
}
|
||||
|
||||
auto MatchSpec::is_file() const -> bool
|
||||
|
|
|
@ -160,6 +160,11 @@ namespace mamba::specs
|
|||
return fmt::format("{}", *this);
|
||||
}
|
||||
|
||||
auto VersionPredicate::str_conda_build() const -> std::string
|
||||
{
|
||||
return fmt::format("{:b}", *this);
|
||||
}
|
||||
|
||||
VersionPredicate::VersionPredicate(Version ver, BinaryOperator op)
|
||||
: m_version(std::move(ver))
|
||||
, m_operator(std::move(op))
|
||||
|
@ -181,10 +186,10 @@ auto
|
|||
fmt::formatter<mamba::specs::VersionPredicate>::parse(format_parse_context& ctx)
|
||||
-> decltype(ctx.begin())
|
||||
{
|
||||
// make sure that range is empty
|
||||
if (ctx.begin() != ctx.end() && *ctx.begin() != '}')
|
||||
if (auto it = std::find(ctx.begin(), ctx.end(), 'b'); it < ctx.end())
|
||||
{
|
||||
throw fmt::format_error("Invalid format");
|
||||
conda_build_form = true;
|
||||
return ++it;
|
||||
}
|
||||
return ctx.begin();
|
||||
}
|
||||
|
@ -239,7 +244,14 @@ fmt::formatter<mamba::specs::VersionPredicate>::format(
|
|||
}
|
||||
if constexpr (std::is_same_v<Op, VersionPredicate::starts_with>)
|
||||
{
|
||||
out = fmt::format_to(out, "{}{}", VersionSpec::starts_with_str, pred.m_version);
|
||||
if (conda_build_form)
|
||||
{
|
||||
out = fmt::format_to(out, "{}{}", pred.m_version, VersionSpec::glob_suffix_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
out = fmt::format_to(out, "{}{}", VersionSpec::starts_with_str, pred.m_version);
|
||||
}
|
||||
}
|
||||
if constexpr (std::is_same_v<Op, VersionPredicate::not_starts_with>)
|
||||
{
|
||||
|
@ -283,11 +295,23 @@ namespace mamba::specs
|
|||
return m_tree.evaluate([&point](const auto& node) { return node.contains(point); });
|
||||
}
|
||||
|
||||
auto VersionSpec::is_explicitly_free() const -> bool
|
||||
{
|
||||
const auto free_pred = VersionPredicate::make_free();
|
||||
const auto is_free_pred = [&free_pred](const auto& node) { return node == free_pred; };
|
||||
return m_tree.empty() || ((m_tree.size() == 1) && m_tree.evaluate(is_free_pred));
|
||||
}
|
||||
|
||||
auto VersionSpec::str() const -> std::string
|
||||
{
|
||||
return fmt::format("{}", *this);
|
||||
}
|
||||
|
||||
auto VersionSpec::str_conda_build() const -> std::string
|
||||
{
|
||||
return fmt::format("{:b}", *this);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename Val, typename Range>
|
||||
|
@ -464,10 +488,10 @@ namespace mamba::specs
|
|||
auto
|
||||
fmt::formatter<mamba::specs::VersionSpec>::parse(format_parse_context& ctx) -> decltype(ctx.begin())
|
||||
{
|
||||
// make sure that range is empty
|
||||
if (ctx.begin() != ctx.end() && *ctx.begin() != '}')
|
||||
if (auto it = std::find(ctx.begin(), ctx.end(), 'b'); it < ctx.end())
|
||||
{
|
||||
throw fmt::format_error("Invalid format");
|
||||
conda_build_form = true;
|
||||
return ++it;
|
||||
}
|
||||
return ctx.begin();
|
||||
}
|
||||
|
@ -511,7 +535,7 @@ fmt::formatter<mamba::specs::VersionSpec>::format(
|
|||
}
|
||||
if constexpr (std::is_same_v<Token, tree_type::variable_type>)
|
||||
{
|
||||
out = fmt::format_to(out, "{}", token);
|
||||
out = fmt::format_to(out, conda_build_form ? "{:b}" : "{}", token);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -67,29 +67,29 @@ TEST_SUITE("specs::match_spec")
|
|||
{
|
||||
{
|
||||
auto ms = MatchSpec::parse("xtensor==0.12.3");
|
||||
CHECK_EQ(ms.version(), "0.12.3");
|
||||
CHECK_EQ(ms.version().str(), "==0.12.3");
|
||||
CHECK_EQ(ms.name(), "xtensor");
|
||||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse("");
|
||||
CHECK_EQ(ms.version(), "");
|
||||
CHECK_EQ(ms.version().str(), "=*");
|
||||
CHECK_EQ(ms.name(), "");
|
||||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse("ipykernel");
|
||||
CHECK_EQ(ms.version(), "");
|
||||
CHECK_EQ(ms.version().str(), "=*");
|
||||
CHECK_EQ(ms.name(), "ipykernel");
|
||||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse("ipykernel ");
|
||||
CHECK_EQ(ms.version(), "");
|
||||
CHECK_EQ(ms.version().str(), "=*");
|
||||
CHECK_EQ(ms.name(), "ipykernel");
|
||||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse("numpy 1.7*");
|
||||
CHECK_EQ(ms.version(), "1.7*");
|
||||
CHECK_EQ(ms.version().str(), "=1.7");
|
||||
CHECK_EQ(ms.name(), "numpy");
|
||||
CHECK_EQ(ms.conda_build_form(), "numpy 1.7*");
|
||||
CHECK_EQ(ms.conda_build_form(), "numpy 1.7.*");
|
||||
CHECK_EQ(ms.str(), "numpy=1.7");
|
||||
}
|
||||
{
|
||||
|
@ -98,11 +98,11 @@ TEST_SUITE("specs::match_spec")
|
|||
// CHECK_EQ(ms.version, "1.7|1.8");
|
||||
CHECK_EQ(ms.name(), "numpy");
|
||||
CHECK_EQ(ms.brackets["version"], "1.7|1.8");
|
||||
CHECK_EQ(ms.str(), "numpy[version='1.7|1.8']");
|
||||
CHECK_EQ(ms.str(), "numpy[version='==1.7|==1.8']");
|
||||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse("conda-forge/linux-64::xtensor==0.12.3");
|
||||
CHECK_EQ(ms.version(), "0.12.3");
|
||||
CHECK_EQ(ms.version().str(), "==0.12.3");
|
||||
CHECK_EQ(ms.name(), "xtensor");
|
||||
REQUIRE(ms.channel().has_value());
|
||||
CHECK_EQ(ms.channel()->location(), "conda-forge");
|
||||
|
@ -111,7 +111,7 @@ TEST_SUITE("specs::match_spec")
|
|||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse("conda-forge::foo[build=3](target=blarg,optional)");
|
||||
CHECK_EQ(ms.version(), "");
|
||||
CHECK_EQ(ms.version().str(), "=*");
|
||||
CHECK_EQ(ms.name(), "foo");
|
||||
REQUIRE(ms.channel().has_value());
|
||||
CHECK_EQ(ms.channel()->location(), "conda-forge");
|
||||
|
@ -136,7 +136,7 @@ TEST_SUITE("specs::match_spec")
|
|||
"https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2"
|
||||
);
|
||||
CHECK_EQ(ms.name(), "_libgcc_mutex");
|
||||
CHECK_EQ(ms.version(), "0.1");
|
||||
CHECK_EQ(ms.version().str(), "==0.1");
|
||||
CHECK_EQ(ms.build_string(), "conda_forge");
|
||||
CHECK_EQ(
|
||||
ms.url(),
|
||||
|
@ -149,7 +149,7 @@ TEST_SUITE("specs::match_spec")
|
|||
"https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-11.2.0-h1d223b6_13.tar.bz2"
|
||||
);
|
||||
CHECK_EQ(ms.name(), "libgcc-ng");
|
||||
CHECK_EQ(ms.version(), "11.2.0");
|
||||
CHECK_EQ(ms.version().str(), "==11.2.0");
|
||||
CHECK_EQ(ms.build_string(), "h1d223b6_13");
|
||||
CHECK_EQ(
|
||||
ms.url(),
|
||||
|
@ -162,7 +162,7 @@ TEST_SUITE("specs::match_spec")
|
|||
"/home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2"
|
||||
);
|
||||
CHECK_EQ(ms.name(), "_libgcc_mutex");
|
||||
CHECK_EQ(ms.version(), "0.1");
|
||||
CHECK_EQ(ms.version().str(), "==0.1");
|
||||
CHECK_EQ(ms.build_string(), "conda_forge");
|
||||
if (util::on_win)
|
||||
{
|
||||
|
@ -199,21 +199,21 @@ TEST_SUITE("specs::match_spec")
|
|||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse("foo=1.0=2");
|
||||
CHECK_EQ(ms.conda_build_form(), "foo 1.0 2");
|
||||
CHECK_EQ(ms.str(), "foo==1.0=2");
|
||||
CHECK_EQ(ms.conda_build_form(), "foo 1.0.* 2");
|
||||
CHECK_EQ(ms.str(), "foo=1.0=2");
|
||||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse("foo=1.0=2[md5=123123123, license=BSD-3, fn='test 123.tar.bz2']"
|
||||
);
|
||||
CHECK_EQ(ms.conda_build_form(), "foo 1.0 2");
|
||||
CHECK_EQ(ms.str(), "foo==1.0=2[md5=123123123,license=BSD-3,fn='test 123.tar.bz2']");
|
||||
CHECK_EQ(ms.conda_build_form(), "foo 1.0.* 2");
|
||||
CHECK_EQ(ms.str(), "foo=1.0=2[md5=123123123,license=BSD-3,fn='test 123.tar.bz2']");
|
||||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse(
|
||||
"foo=1.0=2[md5=123123123, license=BSD-3, fn='test 123.tar.bz2', url='abcdef']"
|
||||
);
|
||||
CHECK_EQ(ms.conda_build_form(), "foo 1.0 2");
|
||||
CHECK_EQ(ms.str(), "foo==1.0=2[url=abcdef,md5=123123123,license=BSD-3]");
|
||||
CHECK_EQ(ms.conda_build_form(), "foo 1.0.* 2");
|
||||
CHECK_EQ(ms.str(), "foo=1.0=2[url=abcdef,md5=123123123,license=BSD-3]");
|
||||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse("libblas=*=*mkl");
|
||||
|
@ -222,12 +222,14 @@ TEST_SUITE("specs::match_spec")
|
|||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse("libblas=0.15*");
|
||||
CHECK_EQ(ms.conda_build_form(), "libblas 0.15*");
|
||||
CHECK_EQ(ms.conda_build_form(), "libblas 0.15*.*");
|
||||
}
|
||||
{
|
||||
// '*' is part of the version, not the glob
|
||||
auto ms = MatchSpec::parse("xtensor =0.15*");
|
||||
CHECK_EQ(ms.conda_build_form(), "xtensor 0.15*");
|
||||
CHECK_EQ(ms.str(), "xtensor=0.15");
|
||||
CHECK_EQ(ms.conda_build_form(), "xtensor 0.15*.*");
|
||||
CHECK_EQ(ms.str(), "xtensor=0.15*");
|
||||
CHECK_EQ(ms.version().str(), "=0.15*");
|
||||
}
|
||||
{
|
||||
auto ms = MatchSpec::parse("numpy=1.20");
|
||||
|
|
|
@ -80,6 +80,7 @@ TEST_SUITE("specs::version_spec")
|
|||
CHECK_FALSE(sw.contains(v3));
|
||||
CHECK_FALSE(sw.contains(v4));
|
||||
CHECK_EQ(sw.str(), "=2.0");
|
||||
CHECK_EQ(sw.str_conda_build(), "2.0.*");
|
||||
|
||||
const auto nsw = VersionPredicate::make_not_starts_with(v2);
|
||||
CHECK(nsw.contains(v1));
|
||||
|
@ -397,4 +398,42 @@ TEST_SUITE("specs::version_spec")
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("VersionSpec::str")
|
||||
{
|
||||
SUBCASE("2.3")
|
||||
{
|
||||
auto vs = VersionSpec::parse("2.3");
|
||||
CHECK_EQ(vs.str(), "==2.3");
|
||||
CHECK_EQ(vs.str_conda_build(), "==2.3");
|
||||
}
|
||||
|
||||
SUBCASE("=2.3,<3.0")
|
||||
{
|
||||
auto vs = VersionSpec::parse("=2.3,<3.0");
|
||||
CHECK_EQ(vs.str(), "=2.3,<3.0");
|
||||
CHECK_EQ(vs.str_conda_build(), "2.3.*,<3.0");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("VersionSpec::is_free")
|
||||
{
|
||||
{
|
||||
using namespace mamba::util;
|
||||
|
||||
auto parser = InfixParser<VersionPredicate, BoolOperator>{};
|
||||
parser.push_variable(VersionPredicate::make_free());
|
||||
parser.finalize();
|
||||
auto spec = VersionSpec(std::move(parser).tree());
|
||||
|
||||
CHECK(spec.is_explicitly_free());
|
||||
}
|
||||
|
||||
CHECK(VersionSpec().is_explicitly_free());
|
||||
CHECK(VersionSpec::parse("*").is_explicitly_free());
|
||||
CHECK(VersionSpec::parse("").is_explicitly_free());
|
||||
|
||||
CHECK_FALSE(VersionSpec::parse("==2.3|!=2.3").is_explicitly_free());
|
||||
CHECK_FALSE(VersionSpec::parse("=2.3,<3.0").is_explicitly_free());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -666,4 +666,4 @@ def test_MatchSpec():
|
|||
ms = MatchSpec.parse("conda-forge::python=3.7=*pypy")
|
||||
|
||||
# str
|
||||
assert str(ms) == "conda-forge::python==3.7[build=*pypy]"
|
||||
assert str(ms) == "conda-forge::python=3.7[build=*pypy]"
|
||||
|
|
Loading…
Reference in New Issue