* Fix include guard

* Add GlobSpec

* Use GlobSpec for MatchSpec build_string

* Make MatchSpec::name a GlobSpec
This commit is contained in:
Antoine Prouvost 2024-01-03 09:17:17 +01:00 committed by GitHub
parent de69846617
commit 18b77d62be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 335 additions and 136 deletions

View File

@ -173,11 +173,12 @@ set(
${LIBMAMBA_SOURCE_DIR}/specs/channel.cpp
${LIBMAMBA_SOURCE_DIR}/specs/channel_spec.cpp
${LIBMAMBA_SOURCE_DIR}/specs/conda_url.cpp
${LIBMAMBA_SOURCE_DIR}/specs/glob_spec.cpp
${LIBMAMBA_SOURCE_DIR}/specs/match_spec.cpp
${LIBMAMBA_SOURCE_DIR}/specs/platform.cpp
${LIBMAMBA_SOURCE_DIR}/specs/repo_data.cpp
${LIBMAMBA_SOURCE_DIR}/specs/version.cpp
${LIBMAMBA_SOURCE_DIR}/specs/version_spec.cpp
${LIBMAMBA_SOURCE_DIR}/specs/match_spec.cpp
# Artifacts validation
${LIBMAMBA_SOURCE_DIR}/validation/tools.cpp
${LIBMAMBA_SOURCE_DIR}/validation/errors.cpp
@ -287,11 +288,12 @@ set(
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/channel.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/channel_spec.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/conda_url.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/glob_spec.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/match_spec.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/platform.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/repo_data.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/version.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/version_spec.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/match_spec.hpp
# Artifacts validation
${LIBMAMBA_INCLUDE_DIR}/mamba/validation/tools.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/validation/errors.hpp

View File

@ -0,0 +1,59 @@
// Copyright (c) 2023, QuantStack and Mamba Contributors
//
// Distributed under the terms of the BSD 3-Clause License.
//
// The full license is in the file LICENSE, distributed with this software.
#ifndef MAMBA_SPECS_GLOB_SPEC
#define MAMBA_SPECS_GLOB_SPEC
#include <string>
#include <string_view>
#include <fmt/core.h>
namespace mamba::specs
{
/**
* A matcher for glob expression.
*
* Currently only support "*" wildcard for matching zero or more characters.
*/
class GlobSpec
{
public:
inline static constexpr std::string_view free_pattern = "*";
GlobSpec() = default;
explicit GlobSpec(std::string pattern);
[[nodiscard]] auto contains(std::string_view str) const -> bool;
/**
* Return true if the spec will match true on any input.
*/
[[nodiscard]] auto is_free() const -> bool;
/**
* Return true if the spec will match exaclty one input.
*/
[[nodiscard]] auto is_exact() const -> bool;
[[nodiscard]] auto str() const -> const std::string&;
private:
std::string m_pattern = std::string(free_pattern);
};
}
template <>
struct fmt::formatter<mamba::specs::GlobSpec>
{
auto parse(format_parse_context& ctx) -> decltype(ctx.begin());
auto format(const ::mamba::specs::GlobSpec& spec, format_context& ctx) -> decltype(ctx.out());
};
#endif

View File

@ -4,8 +4,8 @@
//
// The full license is in the file LICENSE, distributed with this software.
#ifndef MAMBA_CORE_MATCH_SPEC
#define MAMBA_CORE_MATCH_SPEC
#ifndef MAMBA_SPECS_MATCH_SPEC
#define MAMBA_SPECS_MATCH_SPEC
#include <optional>
#include <string>
@ -14,6 +14,7 @@
#include <unordered_map>
#include "mamba/specs/channel_spec.hpp"
#include "mamba/specs/glob_spec.hpp"
#include "mamba/specs/version_spec.hpp"
namespace mamba::specs
@ -22,6 +23,9 @@ namespace mamba::specs
{
public:
using NameSpec = GlobSpec;
using BuildStringSpec = GlobSpec;
[[nodiscard]] static auto parse_version_and_build(std::string_view s)
-> std::tuple<std::string, std::string>;
@ -35,8 +39,8 @@ namespace mamba::specs
[[nodiscard]] auto name_space() const -> const std::string&;
void set_name_space(std::string ns);
[[nodiscard]] auto name() const -> const std::string&;
void set_name(std::string name);
[[nodiscard]] auto name() const -> const NameSpec&;
void set_name(NameSpec name);
[[nodiscard]] auto version() const -> const VersionSpec&;
void set_version(VersionSpec ver);
@ -44,8 +48,8 @@ namespace mamba::specs
[[nodiscard]] auto build_number() const -> const std::string&;
void set_build_number(std::string num);
[[nodiscard]] auto build_string() const -> const std::string&;
void set_build_string(std::string bs);
[[nodiscard]] auto build_string() const -> const BuildStringSpec&;
void set_build_string(BuildStringSpec bs);
[[nodiscard]] auto optional() const -> bool;
void set_optional(bool opt);
@ -69,10 +73,10 @@ namespace mamba::specs
std::optional<ChannelSpec> m_channel;
VersionSpec m_version;
NameSpec m_name;
BuildStringSpec m_build_string;
std::string m_name_space;
std::string m_name;
std::string m_build_number;
std::string m_build_string;
// TODO can put inside channel spec
std::string m_filename;
std::string m_url;

View File

@ -355,9 +355,9 @@ namespace mamba
}
std::size_t hash = u.find_first_of('#');
auto ms = specs::MatchSpec::parse(u.substr(0, hash));
PackageInfo p(ms.name());
PackageInfo p(ms.name().str());
p.url = ms.url();
p.build_string = ms.build_string();
p.build_string = ms.build_string().str();
p.version = ms.version().str();
if (ms.channel().has_value())
{

View File

@ -118,7 +118,7 @@ namespace mamba
std::vector<std::string> keep_specs;
for (auto& it : hist_map)
{
keep_specs.push_back(it.second.name());
keep_specs.push_back(it.second.name().str());
}
solver_flag |= SOLVER_SOLVABLE_ALL;
if (prune_deps)
@ -136,10 +136,10 @@ namespace mamba
std::vector<std::string> remove_specs;
for (auto& it : hist_map)
{
if (std::find(update_specs.begin(), update_specs.end(), it.second.name())
if (std::find(update_specs.begin(), update_specs.end(), it.second.name().str())
== update_specs.end())
{
remove_specs.push_back(it.second.name());
remove_specs.push_back(it.second.name().str());
}
}
solver.add_jobs(remove_specs, SOLVER_ERASE | SOLVER_CLEANDEPS);

View File

@ -58,7 +58,7 @@ namespace mamba
package.info.url = package_node["url"].as<std::string>();
const auto spec = specs::MatchSpec::parse(package.info.url);
package.info.fn = spec.filename();
package.info.build_string = spec.build_string();
package.info.build_string = spec.build_string().str();
if (spec.channel().has_value())
{
package.info.channel = spec.channel()->location();

View File

@ -211,17 +211,17 @@ namespace mamba
auto remove_specs = to_specs(request.remove);
for (auto& spec : remove_specs)
{
map.erase(spec.name());
map.erase(spec.name().str());
}
auto update_specs = to_specs(request.update);
for (auto& spec : update_specs)
{
map[spec.name()] = spec;
map[spec.name().str()] = spec;
}
auto neutered_specs = to_specs(request.neutered);
for (auto& spec : neutered_specs)
{
map[spec.name()] = spec;
map[spec.name().str()] = spec;
}
}

View File

@ -996,7 +996,7 @@ namespace mamba
specs::MatchSpec* requested_spec = nullptr;
for (auto& ms : m_context->requested_specs)
{
if (ms.name() == m_pkg_info.name)
if (ms.name().contains(m_pkg_info.name))
{
requested_spec = &ms;
}

View File

@ -31,7 +31,7 @@ namespace mamba
for (const auto& spec : specs)
{
if (specs::MatchSpec::parse(spec).name() == "python")
if (specs::MatchSpec::parse(spec).name().contains("python"))
{
return "";
}

View File

@ -104,7 +104,7 @@ namespace mamba
auto ms = specs::MatchSpec::parse(dep);
// Ignoring unmatched dependencies, the environment could be broken
// or it could be a matchspec
const auto from_iter = name_to_node_id.find(ms.name());
const auto from_iter = name_to_node_id.find(ms.name().str());
if (from_iter != name_to_node_id.cend())
{
dep_graph.add_edge(from_iter->second, to_id);

View File

@ -265,6 +265,54 @@ namespace mamba
return CompressedProblemsGraph::NamedList<O>(tmp.begin(), tmp.end());
}
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>
auto invoke_build_string(T&& e) -> decltype(auto)
{
using TT = std::remove_cv_t<std::remove_reference_t<T>>;
using Build = decltype(std::invoke(&TT::build_string, std::forward<T>(e)));
Build bld = std::invoke(&TT::build_string, std::forward<T>(e));
if constexpr (std::is_same_v<std::decay_t<decltype(bld)>, specs::GlobSpec>)
{
return std::forward<Build>(bld).str();
}
else
{
return bld;
}
}
template <typename T>
auto invoke_name(T&& e) -> decltype(auto)
{
using TT = std::remove_cv_t<std::remove_reference_t<T>>;
using Name = decltype(std::invoke(&TT::name, std::forward<T>(e)));
Name name = std::invoke(&TT::name, std::forward<T>(e));
if constexpr (std::is_same_v<std::decay_t<decltype(name)>, specs::GlobSpec>)
{
return std::forward<Name>(name).str();
}
else
{
return name;
}
}
/**
* Detect if a type has a ``name`` member (function).
*/
@ -287,7 +335,7 @@ namespace mamba
{
if constexpr (has_name_v<T>)
{
return std::invoke(&T::name, obj);
return invoke_name(obj);
}
else
{
@ -538,32 +586,6 @@ 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>
auto CompressedProblemsGraph::RoughCompare<T>::operator()(const T& a, const T& b) const -> bool
{
@ -573,12 +595,12 @@ namespace mamba
decltype(invoke_name(x)),
decltype(invoke_version(x)),
decltype(std::invoke(&T::build_number, x)),
decltype(std::invoke(&T::build_string, x))>;
decltype(invoke_build_string(x))>;
return Attrs(
invoke_name(x),
invoke_version(x),
std::invoke(&T::build_number, x),
std::invoke(&T::build_string, x)
invoke_build_string(x)
);
};
return attrs(a) < attrs(b);
@ -694,13 +716,13 @@ namespace mamba
) const -> std::pair<std::string, std::size_t>
{
auto builds = std::vector<std::string>(size());
auto invoke_build_string = [](auto&& v) -> decltype(auto)
{
using TT = std::remove_cv_t<std::remove_reference_t<decltype(v)>>;
return std::invoke(&TT::build_string, std::forward<decltype(v)>(v));
};
// TODO(C++20) *this | std::ranges::transform(invoke_buid_string) | ranges::unique
std::transform(begin(), end(), builds.begin(), invoke_build_string);
std::transform(
begin(),
end(),
builds.begin(),
[](const auto& p) { return invoke_build_string(p); }
);
if (remove_duplicates)
{
builds.erase(std::unique(builds.begin(), builds.end()), builds.end());
@ -718,14 +740,7 @@ namespace mamba
{
auto versions_builds = std::vector<std::string>(size());
auto invoke_version_builds = [](auto&& v) -> decltype(auto)
{
using TT = std::remove_cv_t<std::remove_reference_t<decltype(v)>>;
return fmt::format(
"{} {}",
std::invoke(&TT::version, std::forward<decltype(v)>(v)),
std::invoke(&TT::build_string, std::forward<decltype(v)>(v))
);
};
{ return fmt::format("{} {}", invoke_version(v), invoke_build_string(v)); };
// TODO(C++20) *this | std::ranges::transform(invoke_version) | ranges::unique
std::transform(begin(), end(), versions_builds.begin(), invoke_version_builds);
if (remove_duplicates)

View File

@ -78,7 +78,7 @@ namespace mamba
m_pool.pool().for_each_installed_solvable(
[&](solv::ObjSolvableViewConst s)
{
if (s.name() == ms.name())
if (ms.name().contains(s.name()))
{
solvable = s;
return solv::LoopControl::Break;
@ -97,7 +97,7 @@ namespace mamba
}
if (ms.channel().has_value() || !ms.version().is_explicitly_free()
|| !ms.build_string().empty())
|| !ms.build_string().is_free())
{
Console::stream() << ms.conda_build_form()
<< ": overriding channel, version and build from "
@ -107,7 +107,7 @@ namespace mamba
auto ms_modified = ms;
ms_modified.set_channel(specs::ChannelSpec::parse(solvable->channel()));
ms_modified.set_version(specs::VersionSpec::parse(solvable->version()));
ms_modified.set_build_string(std::string(solvable->build_string()));
ms_modified.set_build_string(specs::GlobSpec(std::string(solvable->build_string())));
LOG_INFO << "Reinstall " << ms_modified.conda_build_form() << " from channel "
<< ms_modified.channel()->str();
@ -745,8 +745,8 @@ namespace mamba
// dependency.
auto edge = specs::MatchSpec::parse(source.value().name);
// The package cannot exist without its name in the pool
assert(m_pool.pool().find_string(edge.name()).has_value());
const auto dep_id = m_pool.pool().find_string(edge.name()).value();
assert(m_pool.pool().find_string(edge.name().str()).has_value());
const auto dep_id = m_pool.pool().find_string(edge.name().str()).value();
const bool added = add_expanded_deps_edges(m_root_node, dep_id, edge);
if (!added)
{

View File

@ -69,10 +69,10 @@ namespace mamba
for (auto& ms : specs)
{
out.emplace_back(ms.name());
out.emplace_back(ms.name().str());
auto& p = out.back();
p.url = ms.url();
p.build_string = ms.build_string();
p.build_string = ms.build_string().str();
p.version = ms.version().str_conda_build();
if (ms.channel().has_value())
{
@ -110,7 +110,7 @@ namespace mamba
to_install_specs.cbegin(),
to_install_specs.cend(),
std::back_inserter(to_install_names),
[](const auto& spec) { return spec.name(); }
[](const auto& spec) { return spec.name().str(); }
);
const auto& to_remove_specs = solver.remove_specs();
@ -120,7 +120,7 @@ namespace mamba
to_remove_specs.cbegin(),
to_remove_specs.cend(),
std::back_inserter(to_remove_names),
[](const auto& spec) { return spec.name(); }
[](const auto& spec) { return spec.name().str(); }
);
auto specs = util::flat_set<std::string>{};

View File

@ -0,0 +1,63 @@
// Copyright (c) 2023, QuantStack and Mamba Contributors
//
// Distributed under the terms of the BSD 3-Clause License.
//
// The full license is in the file LICENSE, distributed with this software.
#include <fmt/format.h>
#include "mamba/specs/glob_spec.hpp"
#include "mamba/util/parsers.hpp"
#include "mamba/util/string.hpp"
namespace mamba::specs
{
GlobSpec::GlobSpec(std::string pattern)
: m_pattern(std::move(pattern))
{
// Not sure what to make of empty patterns... A "match nothing"?
if (m_pattern.empty())
{
m_pattern = free_pattern;
}
}
auto GlobSpec::contains(std::string_view str) const -> bool
{
// is_free is not required but returns faster in the default case.
return is_free() || util::glob_match(m_pattern, str);
}
auto GlobSpec::is_free() const -> bool
{
return m_pattern == free_pattern;
}
auto GlobSpec::is_exact() const -> bool
{
return !util::contains(m_pattern, '*');
}
auto GlobSpec::str() const -> const std::string&
{
return m_pattern;
}
}
auto
fmt::formatter<mamba::specs::GlobSpec>::parse(format_parse_context& ctx) -> decltype(ctx.begin())
{
// make sure that range is empty
if (ctx.begin() != ctx.end() && *ctx.begin() != '}')
{
throw fmt::format_error("Invalid format");
}
return ctx.begin();
}
auto
fmt::formatter<mamba::specs::GlobSpec>::format(const ::mamba::specs::GlobSpec& spec, format_context& ctx)
-> decltype(ctx.out())
{
return fmt::format_to(ctx.out(), "{}", spec.str());
}

View File

@ -69,7 +69,7 @@ namespace mamba::specs
// Build string
auto [head, tail] = util::rsplit_once(strip_archive_extension(pkg), '-');
out.m_build_string = tail;
out.m_build_string = BuildStringSpec(std::string(tail));
if (!head.has_value())
{
fail_parse();
@ -84,7 +84,7 @@ namespace mamba::specs
}
// Name
out.m_name = head.value(); // There may be '-' in the name
out.m_name = NameSpec(std::string(head.value())); // There may be '-' in the name
return out;
}
@ -198,12 +198,8 @@ namespace mamba::specs
std::smatch vb_match;
if (std::regex_match(spec_str, vb_match, version_build_re))
{
out.m_name = vb_match[1].str();
out.m_name = NameSpec(vb_match[1].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);
}
}
else
{
@ -226,7 +222,7 @@ namespace mamba::specs
auto [pv, pb] = parse_version_and_build(version_and_build);
out.m_version = VersionSpec::parse(pv);
out.m_build_string = pb;
out.m_build_string = BuildStringSpec(std::string(pb));
}
else // no-op
{
@ -245,7 +241,7 @@ namespace mamba::specs
}
else if (k == "build")
{
out.m_build_string = v;
out.m_build_string = MatchSpec::BuildStringSpec(std::string(v));
}
else if (k == "version")
{
@ -320,12 +316,12 @@ namespace mamba::specs
m_name_space = std::move(ns);
}
auto MatchSpec::name() const -> const std::string&
auto MatchSpec::name() const -> const NameSpec&
{
return m_name;
}
void MatchSpec::set_name(std::string name)
void MatchSpec::set_name(NameSpec name)
{
m_name = std::move(name);
}
@ -350,7 +346,7 @@ namespace mamba::specs
m_build_number = std::move(bn);
}
auto MatchSpec::build_string() const -> const std::string&
auto MatchSpec::build_string() const -> const BuildStringSpec&
{
return m_build_string;
}
@ -365,7 +361,7 @@ namespace mamba::specs
m_optional = opt;
}
void MatchSpec::set_build_string(std::string bs)
void MatchSpec::set_build_string(BuildStringSpec bs)
{
m_build_string = std::move(bs);
}
@ -382,21 +378,24 @@ namespace mamba::specs
auto MatchSpec::conda_build_form() const -> std::string
{
std::stringstream res;
res << m_name;
if (!m_version.is_explicitly_free())
const bool has_version = !m_version.is_explicitly_free();
const bool has_build_str = !m_build_string.is_free();
if (has_version)
{
res << " " << m_version.str_conda_build();
if (has_build_str)
{
return fmt::format("{} {:b} {}", m_name, m_version, m_build_string);
}
else
{
return fmt::format("{} {:b}", m_name, m_version);
}
}
else if (!m_build_string.empty())
if (has_build_str)
{
res << " *";
return fmt::format("{} * {}", m_name, m_build_string);
}
if (!m_build_string.empty())
{
res << " " << m_build_string;
}
return res.str();
return fmt::format("{}", m_name);
}
auto MatchSpec::str() const -> std::string
@ -428,9 +427,8 @@ namespace mamba::specs
// res << ns;
// res << ":";
// }
res << (!m_name.empty() ? m_name : "*");
res << m_name.str();
std::vector<std::string> formatted_brackets;
bool version_exact = false;
auto is_complex_relation = [](const std::string& s)
{ return s.find_first_of("><$^|,") != s.npos; };
@ -445,27 +443,19 @@ namespace mamba::specs
else
{
res << ver;
version_exact = true;
// version_exact = true;
}
}
if (!m_build_string.empty())
if (!m_build_string.is_free())
{
if (is_complex_relation(m_build_string))
if (m_build_string.is_exact())
{
formatted_brackets.push_back(util::concat("build='", m_build_string, '\''));
}
else if (m_build_string.find('*') != m_build_string.npos)
{
formatted_brackets.push_back(util::concat("build=", m_build_string));
}
else if (version_exact)
{
res << "=" << m_build_string;
res << "=" << m_build_string.str();
}
else
{
formatted_brackets.push_back(util::concat("build=", m_build_string));
formatted_brackets.push_back(util::concat("build='", m_build_string.str(), '\''));
}
}
@ -514,7 +504,7 @@ namespace mamba::specs
auto MatchSpec::is_simple() const -> bool
{
return m_version.is_explicitly_free() && m_build_string.empty() && m_build_number.empty();
return m_version.is_explicitly_free() && m_build_string.is_free() && m_build_number.empty();
}
auto MatchSpec::is_file() const -> bool

View File

@ -46,11 +46,12 @@ set(
src/specs/test_channel.cpp
src/specs/test_channel_spec.cpp
src/specs/test_conda_url.cpp
src/specs/test_glob_spec.cpp
src/specs/test_match_spec.cpp
src/specs/test_platform.cpp
src/specs/test_repo_data.cpp
src/specs/test_version.cpp
src/specs/test_version_spec.cpp
src/specs/test_match_spec.cpp
# Artifacts validation
src/validation/test_tools.cpp
src/validation/test_update_framework_v0_6.cpp

View File

@ -479,12 +479,19 @@ namespace
return std::visit(
[](const auto& n) -> bool
{
using Node = std::remove_const_t<std::remove_reference_t<decltype(n)>>;
if constexpr (!std::is_same_v<Node, ProblemsGraph::RootNode>)
using Node = std::decay_t<decltype(n)>;
if constexpr (std::is_same_v<Node, ProblemsGraph::RootNode>)
{
return false;
}
else if constexpr (std::is_same_v<Node, ProblemsGraph::UnresolvedDependencyNode> || std::is_same_v<Node, ProblemsGraph::ConstraintNode>)
{
return util::starts_with(std::invoke(&Node::name, n).str(), "__");
}
else
{
return util::starts_with(std::invoke(&Node::name, n), "__");
}
return false;
},
node
);

View File

@ -0,0 +1,58 @@
// Copyright (c) 2023, QuantStack and Mamba Contributors
//
// Distributed under the terms of the BSD 3-Clause License.
//
// The full license is in the file LICENSE, distributed with this software.
#include <doctest/doctest.h>
#include "mamba/specs/glob_spec.hpp"
using namespace mamba::specs;
TEST_SUITE("specs::glob_spec")
{
// See also test_parser for Glob matcher tests
TEST_CASE("Free")
{
auto spec = GlobSpec();
CHECK(spec.contains(""));
CHECK(spec.contains("hello"));
CHECK_EQ(spec.str(), "*");
CHECK(spec.is_free());
CHECK_FALSE(spec.is_exact());
}
TEST_CASE("*mkl*")
{
auto spec = GlobSpec("mkl");
CHECK(spec.contains("mkl"));
CHECK_FALSE(spec.contains(""));
CHECK_FALSE(spec.contains("nomkl"));
CHECK_FALSE(spec.contains("hello"));
CHECK_EQ(spec.str(), "mkl");
CHECK_FALSE(spec.is_free());
CHECK(spec.is_exact());
}
TEST_CASE("*py*")
{
// See also test_parser for Glob matcher tests
auto spec = GlobSpec("*py*");
CHECK(spec.contains("py"));
CHECK(spec.contains("pypy"));
CHECK(spec.contains("cpython-linux-64"));
CHECK_FALSE(spec.contains("rust"));
CHECK_FALSE(spec.contains("hello"));
CHECK_EQ(spec.str(), "*py*");
CHECK_FALSE(spec.is_free());
CHECK_FALSE(spec.is_exact());
}
}

View File

@ -68,27 +68,27 @@ TEST_SUITE("specs::match_spec")
{
auto ms = MatchSpec::parse("xtensor==0.12.3");
CHECK_EQ(ms.version().str(), "==0.12.3");
CHECK_EQ(ms.name(), "xtensor");
CHECK_EQ(ms.name().str(), "xtensor");
}
{
auto ms = MatchSpec::parse("");
CHECK_EQ(ms.version().str(), "=*");
CHECK_EQ(ms.name(), "");
CHECK_EQ(ms.name().str(), "*");
}
{
auto ms = MatchSpec::parse("ipykernel");
CHECK_EQ(ms.version().str(), "=*");
CHECK_EQ(ms.name(), "ipykernel");
CHECK_EQ(ms.name().str(), "ipykernel");
}
{
auto ms = MatchSpec::parse("ipykernel ");
CHECK_EQ(ms.version().str(), "=*");
CHECK_EQ(ms.name(), "ipykernel");
CHECK_EQ(ms.name().str(), "ipykernel");
}
{
auto ms = MatchSpec::parse("numpy 1.7*");
CHECK_EQ(ms.version().str(), "=1.7");
CHECK_EQ(ms.name(), "numpy");
CHECK_EQ(ms.name().str(), "numpy");
CHECK_EQ(ms.conda_build_form(), "numpy 1.7.*");
CHECK_EQ(ms.str(), "numpy=1.7");
}
@ -96,14 +96,14 @@ TEST_SUITE("specs::match_spec")
auto ms = MatchSpec::parse("numpy[version='1.7|1.8']");
// TODO!
// CHECK_EQ(ms.version, "1.7|1.8");
CHECK_EQ(ms.name(), "numpy");
CHECK_EQ(ms.name().str(), "numpy");
CHECK_EQ(ms.brackets["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().str(), "==0.12.3");
CHECK_EQ(ms.name(), "xtensor");
CHECK_EQ(ms.name().str(), "xtensor");
REQUIRE(ms.channel().has_value());
CHECK_EQ(ms.channel()->location(), "conda-forge");
CHECK_EQ(ms.channel()->platform_filters(), PlatformSet{ "linux-64" });
@ -112,7 +112,7 @@ TEST_SUITE("specs::match_spec")
{
auto ms = MatchSpec::parse("conda-forge::foo[build=3](target=blarg,optional)");
CHECK_EQ(ms.version().str(), "=*");
CHECK_EQ(ms.name(), "foo");
CHECK_EQ(ms.name().str(), "foo");
REQUIRE(ms.channel().has_value());
CHECK_EQ(ms.channel()->location(), "conda-forge");
CHECK_EQ(ms.brackets["build"], "3");
@ -121,13 +121,13 @@ TEST_SUITE("specs::match_spec")
}
{
auto ms = MatchSpec::parse("python[build_number=3]");
CHECK_EQ(ms.name(), "python");
CHECK_EQ(ms.name().str(), "python");
CHECK_EQ(ms.brackets["build_number"], "3");
CHECK_EQ(ms.build_number(), "3");
}
{
auto ms = MatchSpec::parse("python[build_number='<=3']");
CHECK_EQ(ms.name(), "python");
CHECK_EQ(ms.name().str(), "python");
CHECK_EQ(ms.brackets["build_number"], "<=3");
CHECK_EQ(ms.build_number(), "<=3");
}
@ -135,9 +135,9 @@ TEST_SUITE("specs::match_spec")
auto ms = MatchSpec::parse(
"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.name().str(), "_libgcc_mutex");
CHECK_EQ(ms.version().str(), "==0.1");
CHECK_EQ(ms.build_string(), "conda_forge");
CHECK_EQ(ms.build_string().str(), "conda_forge");
CHECK_EQ(
ms.url(),
"https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2"
@ -148,9 +148,9 @@ TEST_SUITE("specs::match_spec")
auto ms = MatchSpec::parse(
"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.name().str(), "libgcc-ng");
CHECK_EQ(ms.version().str(), "==11.2.0");
CHECK_EQ(ms.build_string(), "h1d223b6_13");
CHECK_EQ(ms.build_string().str(), "h1d223b6_13");
CHECK_EQ(
ms.url(),
"https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-11.2.0-h1d223b6_13.tar.bz2"
@ -161,9 +161,9 @@ TEST_SUITE("specs::match_spec")
auto ms = MatchSpec::parse(
"/home/randomguy/Downloads/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2"
);
CHECK_EQ(ms.name(), "_libgcc_mutex");
CHECK_EQ(ms.name().str(), "_libgcc_mutex");
CHECK_EQ(ms.version().str(), "==0.1");
CHECK_EQ(ms.build_string(), "conda_forge");
CHECK_EQ(ms.build_string().str(), "conda_forge");
if (util::on_win)
{
std::string driveletter = fs::absolute(fs::u8path("/")).string().substr(0, 1);
@ -190,7 +190,7 @@ TEST_SUITE("specs::match_spec")
auto ms = MatchSpec::parse(
"xtensor[url=file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2]"
);
CHECK_EQ(ms.name(), "xtensor");
CHECK_EQ(ms.name().str(), "xtensor");
CHECK_EQ(
ms.brackets["url"],
"file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2"

View File

@ -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']"