mirror of https://github.com/mamba-org/mamba.git
Remove implicit zero in Version formatting (#3915)
This commit is contained in:
parent
e1f0543810
commit
6ad6a6afc7
|
@ -43,13 +43,6 @@ namespace mamba::specs
|
|||
|
||||
[[nodiscard]] auto str() const -> std::string;
|
||||
|
||||
auto operator==(const VersionPartAtom& other) const -> bool;
|
||||
auto operator!=(const VersionPartAtom& other) const -> bool;
|
||||
auto operator<(const VersionPartAtom& other) const -> bool;
|
||||
auto operator<=(const VersionPartAtom& other) const -> bool;
|
||||
auto operator>(const VersionPartAtom& other) const -> bool;
|
||||
auto operator>=(const VersionPartAtom& other) const -> bool;
|
||||
|
||||
private:
|
||||
|
||||
// Stored in decreasing size order for performance
|
||||
|
@ -57,18 +50,56 @@ namespace mamba::specs
|
|||
std::size_t m_numeral = 0;
|
||||
};
|
||||
|
||||
auto operator==(const VersionPartAtom& left, const VersionPartAtom& right) -> bool;
|
||||
auto operator!=(const VersionPartAtom& left, const VersionPartAtom& right) -> bool;
|
||||
auto operator<(const VersionPartAtom& left, const VersionPartAtom& right) -> bool;
|
||||
auto operator<=(const VersionPartAtom& left, const VersionPartAtom& right) -> bool;
|
||||
auto operator>(const VersionPartAtom& left, const VersionPartAtom& right) -> bool;
|
||||
auto operator>=(const VersionPartAtom& left, const VersionPartAtom& right) -> bool;
|
||||
|
||||
extern template VersionPartAtom::VersionPartAtom(std::size_t, std::string);
|
||||
|
||||
/**
|
||||
* A sequence of VersionPartAtom meant to represent a part of a version (e.g. major, minor).
|
||||
*
|
||||
* In a version like ``1.3.0post1dev``, the parts are ``1``, ``3``, and ``0post1dev``.
|
||||
* Version parts can have a arbitrary number of atoms, such as {0, "post"} {1, "dev"}
|
||||
* in 0post1dev
|
||||
* in ``0post1dev``.
|
||||
*
|
||||
* @see Version::parse for how this is computed from strings.
|
||||
* @todo Use a small vector of expected size 1 if performance ar not good enough.
|
||||
*/
|
||||
using VersionPart = std::vector<VersionPartAtom>;
|
||||
struct VersionPart
|
||||
{
|
||||
/** The atoms of the version part */
|
||||
std::vector<VersionPartAtom> atoms = {};
|
||||
|
||||
/**
|
||||
* Whether a potential leading zero in the first atom should be considered implicit.
|
||||
*
|
||||
* During parsing of ``Version``, if a part starts with a literal atom, it is considered
|
||||
* the same as if it started with a leading ``0``.
|
||||
* For instance ``0post1dev`` is parsed in the same way as ``post1dev``.
|
||||
* Marking it as implicit enables the possibility to remove it when reconstructing a string
|
||||
* representation.
|
||||
* This is desirable for compatibility with other version formats, such as Python, where
|
||||
* a version modifier might be expressed as ``1.3.0.dev3``.
|
||||
*/
|
||||
bool implicit_leading_zero = false;
|
||||
|
||||
VersionPart();
|
||||
VersionPart(std::initializer_list<VersionPartAtom> init);
|
||||
VersionPart(std::vector<VersionPartAtom> atoms, bool implicit_leading_zero);
|
||||
|
||||
[[nodiscard]] auto str() const -> std::string;
|
||||
};
|
||||
|
||||
auto operator==(const VersionPart& left, const VersionPart& other) -> bool;
|
||||
auto operator!=(const VersionPart& left, const VersionPart& other) -> bool;
|
||||
auto operator<(const VersionPart& left, const VersionPart& other) -> bool;
|
||||
auto operator<=(const VersionPart& left, const VersionPart& other) -> bool;
|
||||
auto operator>(const VersionPart& left, const VersionPart& other) -> bool;
|
||||
auto operator>=(const VersionPart& left, const VersionPart& other) -> bool;
|
||||
|
||||
/**
|
||||
* A sequence of VersionPart meant to represent all parts of a version.
|
||||
|
@ -139,13 +170,6 @@ namespace mamba::specs
|
|||
*/
|
||||
[[nodiscard]] auto str_glob() const -> std::string;
|
||||
|
||||
[[nodiscard]] auto operator==(const Version& other) const -> bool;
|
||||
[[nodiscard]] auto operator!=(const Version& other) const -> bool;
|
||||
[[nodiscard]] auto operator<(const Version& other) const -> bool;
|
||||
[[nodiscard]] auto operator<=(const Version& other) const -> bool;
|
||||
[[nodiscard]] auto operator>(const Version& other) const -> bool;
|
||||
[[nodiscard]] auto operator>=(const Version& other) const -> bool;
|
||||
|
||||
/**
|
||||
* Return true if this version starts with the other prefix.
|
||||
*
|
||||
|
@ -174,6 +198,13 @@ namespace mamba::specs
|
|||
std::size_t m_epoch = 0;
|
||||
};
|
||||
|
||||
auto operator==(const Version& left, const Version& other) -> bool;
|
||||
auto operator!=(const Version& left, const Version& other) -> bool;
|
||||
auto operator<(const Version& left, const Version& other) -> bool;
|
||||
auto operator<=(const Version& left, const Version& other) -> bool;
|
||||
auto operator>(const Version& left, const Version& other) -> bool;
|
||||
auto operator>=(const Version& left, const Version& other) -> bool;
|
||||
|
||||
namespace version_literals
|
||||
{
|
||||
auto operator""_v(const char* str, std::size_t len) -> Version;
|
||||
|
@ -189,6 +220,15 @@ struct fmt::formatter<mamba::specs::VersionPartAtom>
|
|||
-> decltype(ctx.out());
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<mamba::specs::VersionPart>
|
||||
{
|
||||
auto parse(format_parse_context& ctx) -> decltype(ctx.begin());
|
||||
|
||||
auto format(const ::mamba::specs::VersionPart atom, format_context& ctx) const
|
||||
-> decltype(ctx.out());
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<mamba::specs::Version>
|
||||
{
|
||||
|
|
|
@ -48,6 +48,92 @@ namespace mamba::specs
|
|||
{
|
||||
return compare_three_way(std::strcmp(a.c_str(), b.c_str()), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two ranges where some trailing elements can be considered as empty.
|
||||
*
|
||||
* If ``0`` is considered "empty" then all the ranges ``[1, 2] and ``[1, 2, 0]``,
|
||||
* ``[1, 2, 0, 0]`` are considered equal, however ``[1, 2]`` and ``[1, 0, 2]`` are not.
|
||||
* Similarly ``[1, 1] is less than ``[1, 2, 0]`` but more than ``[1, 1, -1]``
|
||||
* because ``-1 < 0``.
|
||||
*
|
||||
* @return The comparison between the two sequences
|
||||
* @return The first index where the two sequences diverge.
|
||||
*/
|
||||
template <typename Iter1, typename Iter2, typename Empty1, typename Empty2, typename Cmp>
|
||||
constexpr auto lexicographical_compare_three_way_trailing(
|
||||
Iter1 first1,
|
||||
Iter1 last1,
|
||||
Iter2 first2,
|
||||
Iter2 last2,
|
||||
const Empty1& empty1,
|
||||
const Empty2& empty2,
|
||||
Cmp comp
|
||||
) -> std::pair<strong_ordering, std::size_t>
|
||||
{
|
||||
assert(std::distance(first1, last1) >= 0);
|
||||
assert(std::distance(first2, last2) >= 0);
|
||||
|
||||
auto iter1 = first1;
|
||||
auto iter2 = first2;
|
||||
for (; (iter1 != last1) && (iter2 != last2); ++iter1, ++iter2)
|
||||
{
|
||||
if (auto c = comp(*iter1, *iter2); c != strong_ordering::equal)
|
||||
{
|
||||
return { c, static_cast<std::size_t>(std::distance(first1, iter1)) };
|
||||
}
|
||||
}
|
||||
|
||||
// They have the same leading elements but 1 has more elements
|
||||
// We do a lexicographic comparison with an infinite sequence of empties
|
||||
if ((iter1 != last1))
|
||||
{
|
||||
for (; iter1 != last1; ++iter1)
|
||||
{
|
||||
if (auto c = comp(*iter1, empty2); c != strong_ordering::equal)
|
||||
{
|
||||
return { c, static_cast<std::size_t>(std::distance(first1, iter1)) };
|
||||
}
|
||||
}
|
||||
}
|
||||
// first2 != last2
|
||||
// They have the same leading elements but 2 has more elements
|
||||
// We do a lexicographic comparison with an infinite sequence of empties
|
||||
if ((iter2 != last2))
|
||||
{
|
||||
for (; iter2 != last2; ++iter2)
|
||||
{
|
||||
if (auto c = comp(empty1, *iter2); c != strong_ordering::equal)
|
||||
{
|
||||
return { c, static_cast<std::size_t>(std::distance(first2, iter2)) };
|
||||
}
|
||||
}
|
||||
}
|
||||
// They have the same elements
|
||||
return { strong_ordering::equal, static_cast<std::size_t>(std::distance(first1, iter1)) };
|
||||
}
|
||||
|
||||
template <typename Iter1, typename Iter2, typename Empty, typename Cmp>
|
||||
constexpr auto lexicographical_compare_three_way_trailing(
|
||||
Iter1 first1,
|
||||
Iter1 last1,
|
||||
Iter2 first2,
|
||||
Iter2 last2,
|
||||
const Empty& empty,
|
||||
Cmp comp
|
||||
) -> std::pair<strong_ordering, std::size_t>
|
||||
{
|
||||
return lexicographical_compare_three_way_trailing(
|
||||
first1,
|
||||
last1,
|
||||
first2,
|
||||
last2,
|
||||
empty,
|
||||
empty,
|
||||
comp
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***************************************
|
||||
|
@ -142,38 +228,38 @@ namespace mamba::specs
|
|||
}
|
||||
}
|
||||
|
||||
auto VersionPartAtom::operator==(const VersionPartAtom& other) const -> bool
|
||||
auto operator==(const VersionPartAtom& left, const VersionPartAtom& right) -> bool
|
||||
{
|
||||
// More efficient than three way comparison because of edge cases
|
||||
auto attrs = [](const VersionPartAtom& a) -> std::tuple<std::size_t, const std::string&>
|
||||
{ return { a.numeral(), a.literal() }; };
|
||||
return attrs(*this) == attrs(other);
|
||||
return attrs(left) == attrs(right);
|
||||
}
|
||||
|
||||
auto VersionPartAtom::operator!=(const VersionPartAtom& other) const -> bool
|
||||
auto operator!=(const VersionPartAtom& left, const VersionPartAtom& right) -> bool
|
||||
{
|
||||
// More efficient than three way comparison
|
||||
return !(*this == other);
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
auto VersionPartAtom::operator<(const VersionPartAtom& other) const -> bool
|
||||
auto operator<(const VersionPartAtom& left, const VersionPartAtom& right) -> bool
|
||||
{
|
||||
return compare_three_way(*this, other) == strong_ordering::less;
|
||||
return compare_three_way(left, right) == strong_ordering::less;
|
||||
}
|
||||
|
||||
auto VersionPartAtom::operator<=(const VersionPartAtom& other) const -> bool
|
||||
auto operator<=(const VersionPartAtom& left, const VersionPartAtom& right) -> bool
|
||||
{
|
||||
return compare_three_way(*this, other) != strong_ordering::greater;
|
||||
return compare_three_way(left, right) != strong_ordering::greater;
|
||||
}
|
||||
|
||||
auto VersionPartAtom::operator>(const VersionPartAtom& other) const -> bool
|
||||
auto operator>(const VersionPartAtom& left, const VersionPartAtom& right) -> bool
|
||||
{
|
||||
return compare_three_way(*this, other) == strong_ordering::greater;
|
||||
return compare_three_way(left, right) == strong_ordering::greater;
|
||||
}
|
||||
|
||||
auto VersionPartAtom::operator>=(const VersionPartAtom& other) const -> bool
|
||||
auto operator>=(const VersionPartAtom& left, const VersionPartAtom& other) -> bool
|
||||
{
|
||||
return compare_three_way(*this, other) != strong_ordering::less;
|
||||
return compare_three_way(left, other) != strong_ordering::less;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,6 +284,124 @@ fmt::formatter<mamba::specs::VersionPartAtom>::format(
|
|||
return fmt::format_to(ctx.out(), "{}{}", atom.numeral(), atom.literal());
|
||||
}
|
||||
|
||||
namespace mamba::specs
|
||||
{
|
||||
|
||||
/***********************************
|
||||
* Implementation of VersionPart *
|
||||
***********************************/
|
||||
|
||||
VersionPart::VersionPart()
|
||||
: atoms()
|
||||
, implicit_leading_zero(false)
|
||||
{
|
||||
}
|
||||
|
||||
VersionPart::VersionPart(std::initializer_list<VersionPartAtom> init)
|
||||
: atoms(init)
|
||||
{
|
||||
}
|
||||
|
||||
VersionPart::VersionPart(std::vector<VersionPartAtom> p_atoms, bool p_implicit_leading_zero)
|
||||
: atoms(std::move(p_atoms))
|
||||
, implicit_leading_zero(p_implicit_leading_zero)
|
||||
{
|
||||
}
|
||||
|
||||
auto VersionPart::str() const -> std::string
|
||||
{
|
||||
return fmt::format("{}", *this);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template <>
|
||||
auto compare_three_way(const VersionPart& a, const VersionPart& b) -> strong_ordering
|
||||
{
|
||||
return lexicographical_compare_three_way_trailing(
|
||||
a.atoms.cbegin(),
|
||||
a.atoms.cend(),
|
||||
b.atoms.cbegin(),
|
||||
b.atoms.cend(),
|
||||
VersionPartAtom{},
|
||||
[](const auto& x, const auto& y) { return compare_three_way(x, y); }
|
||||
).first;
|
||||
}
|
||||
}
|
||||
|
||||
auto operator==(const VersionPart& left, const VersionPart& right) -> bool
|
||||
{
|
||||
return compare_three_way(left, right) == strong_ordering::equal;
|
||||
}
|
||||
|
||||
auto operator!=(const VersionPart& left, const VersionPart& right) -> bool
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
auto operator<(const VersionPart& left, const VersionPart& right) -> bool
|
||||
{
|
||||
return compare_three_way(left, right) == strong_ordering::less;
|
||||
}
|
||||
|
||||
auto operator<=(const VersionPart& left, const VersionPart& right) -> bool
|
||||
{
|
||||
return compare_three_way(left, right) != strong_ordering::greater;
|
||||
}
|
||||
|
||||
auto operator>(const VersionPart& left, const VersionPart& right) -> bool
|
||||
{
|
||||
return compare_three_way(left, right) == strong_ordering::greater;
|
||||
}
|
||||
|
||||
auto operator>=(const VersionPart& left, const VersionPart& right) -> bool
|
||||
{
|
||||
return compare_three_way(left, right) != strong_ordering::less;
|
||||
}
|
||||
}
|
||||
|
||||
auto
|
||||
fmt::formatter<mamba::specs::VersionPart>::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::VersionPart>::format(
|
||||
const ::mamba::specs::VersionPart part,
|
||||
format_context& ctx
|
||||
) const -> decltype(ctx.out())
|
||||
{
|
||||
auto out = ctx.out();
|
||||
if (part.atoms.empty())
|
||||
{
|
||||
return out;
|
||||
}
|
||||
|
||||
const auto& first = part.atoms.front();
|
||||
if (part.implicit_leading_zero && (first.numeral() == 0) && (!first.literal().empty()))
|
||||
{
|
||||
// The implicit leading zero is omitted
|
||||
out = fmt::format_to(out, "{}", first.literal());
|
||||
}
|
||||
else
|
||||
{
|
||||
out = fmt::format_to(out, "{}", first);
|
||||
}
|
||||
|
||||
const auto n_atoms = part.atoms.size();
|
||||
for (std::size_t i = 1; i < n_atoms; ++i)
|
||||
{
|
||||
out = fmt::format_to(out, "{}", part.atoms[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
namespace mamba::specs
|
||||
{
|
||||
|
||||
|
@ -248,104 +452,6 @@ namespace mamba::specs
|
|||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* Compare two ranges where some trailing elements can be considered as empty.
|
||||
*
|
||||
* If ``0`` is considered "empty" then all the ranges ``[1, 2] and ``[1, 2, 0]``,
|
||||
* ``[1, 2, 0, 0]`` are considered equal, however ``[1, 2]`` and ``[1, 0, 2]`` are not.
|
||||
* Similarly ``[1, 1] is less than ``[1, 2, 0]`` but more than ``[1, 1, -1]``
|
||||
* because ``-1 < 0``.
|
||||
*
|
||||
* @return The comparison between the two sequences
|
||||
* @return The first index where the two sequences diverge.
|
||||
*/
|
||||
template <typename Iter1, typename Iter2, typename Empty1, typename Empty2, typename Cmp>
|
||||
constexpr auto lexicographical_compare_three_way_trailing(
|
||||
Iter1 first1,
|
||||
Iter1 last1,
|
||||
Iter2 first2,
|
||||
Iter2 last2,
|
||||
const Empty1& empty1,
|
||||
const Empty2& empty2,
|
||||
Cmp comp
|
||||
) -> std::pair<strong_ordering, std::size_t>
|
||||
{
|
||||
assert(std::distance(first1, last1) >= 0);
|
||||
assert(std::distance(first2, last2) >= 0);
|
||||
|
||||
auto iter1 = first1;
|
||||
auto iter2 = first2;
|
||||
for (; (iter1 != last1) && (iter2 != last2); ++iter1, ++iter2)
|
||||
{
|
||||
if (auto c = comp(*iter1, *iter2); c != strong_ordering::equal)
|
||||
{
|
||||
return { c, static_cast<std::size_t>(std::distance(first1, iter1)) };
|
||||
}
|
||||
}
|
||||
|
||||
// They have the same leading elements but 1 has more elements
|
||||
// We do a lexicographic comparison with an infinite sequence of empties
|
||||
if ((iter1 != last1))
|
||||
{
|
||||
for (; iter1 != last1; ++iter1)
|
||||
{
|
||||
if (auto c = comp(*iter1, empty2); c != strong_ordering::equal)
|
||||
{
|
||||
return { c, static_cast<std::size_t>(std::distance(first1, iter1)) };
|
||||
}
|
||||
}
|
||||
}
|
||||
// first2 != last2
|
||||
// They have the same leading elements but 2 has more elements
|
||||
// We do a lexicographic comparison with an infinite sequence of empties
|
||||
if ((iter2 != last2))
|
||||
{
|
||||
for (; iter2 != last2; ++iter2)
|
||||
{
|
||||
if (auto c = comp(empty1, *iter2); c != strong_ordering::equal)
|
||||
{
|
||||
return { c, static_cast<std::size_t>(std::distance(first2, iter2)) };
|
||||
}
|
||||
}
|
||||
}
|
||||
// They have the same elements
|
||||
return { strong_ordering::equal, static_cast<std::size_t>(std::distance(first1, iter1)) };
|
||||
}
|
||||
|
||||
template <typename Iter1, typename Iter2, typename Empty, typename Cmp>
|
||||
constexpr auto lexicographical_compare_three_way_trailing(
|
||||
Iter1 first1,
|
||||
Iter1 last1,
|
||||
Iter2 first2,
|
||||
Iter2 last2,
|
||||
const Empty& empty,
|
||||
Cmp comp
|
||||
) -> std::pair<strong_ordering, std::size_t>
|
||||
{
|
||||
return lexicographical_compare_three_way_trailing(
|
||||
first1,
|
||||
last1,
|
||||
first2,
|
||||
last2,
|
||||
empty,
|
||||
empty,
|
||||
comp
|
||||
);
|
||||
}
|
||||
|
||||
template <>
|
||||
auto compare_three_way(const VersionPart& a, const VersionPart& b) -> strong_ordering
|
||||
{
|
||||
return lexicographical_compare_three_way_trailing(
|
||||
a.cbegin(),
|
||||
a.cend(),
|
||||
b.cbegin(),
|
||||
b.cend(),
|
||||
VersionPartAtom{},
|
||||
[](const auto& x, const auto& y) { return compare_three_way(x, y); }
|
||||
).first;
|
||||
}
|
||||
|
||||
template <>
|
||||
auto compare_three_way(const CommonVersion& a, const CommonVersion& b) -> strong_ordering
|
||||
{
|
||||
|
@ -375,34 +481,34 @@ namespace mamba::specs
|
|||
}
|
||||
|
||||
// TODO(C++20) use operator<=> to simplify code and improve operator<=
|
||||
auto Version::operator==(const Version& other) const -> bool
|
||||
auto operator==(const Version& left, const Version& right) -> bool
|
||||
{
|
||||
return compare_three_way(*this, other) == strong_ordering::equal;
|
||||
return compare_three_way(left, right) == strong_ordering::equal;
|
||||
}
|
||||
|
||||
auto Version::operator!=(const Version& other) const -> bool
|
||||
auto operator!=(const Version& left, const Version& right) -> bool
|
||||
{
|
||||
return !(*this == other);
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
auto Version::operator<(const Version& other) const -> bool
|
||||
auto operator<(const Version& left, const Version& right) -> bool
|
||||
{
|
||||
return compare_three_way(*this, other) == strong_ordering::less;
|
||||
return compare_three_way(left, right) == strong_ordering::less;
|
||||
}
|
||||
|
||||
auto Version::operator<=(const Version& other) const -> bool
|
||||
auto operator<=(const Version& left, const Version& right) -> bool
|
||||
{
|
||||
return compare_three_way(*this, other) != strong_ordering::greater;
|
||||
return compare_three_way(left, right) != strong_ordering::greater;
|
||||
}
|
||||
|
||||
auto Version::operator>(const Version& other) const -> bool
|
||||
auto operator>(const Version& left, const Version& right) -> bool
|
||||
{
|
||||
return compare_three_way(*this, other) == strong_ordering::greater;
|
||||
return compare_three_way(left, right) == strong_ordering::greater;
|
||||
}
|
||||
|
||||
auto Version::operator>=(const Version& other) const -> bool
|
||||
auto operator>=(const Version& left, const Version& right) -> bool
|
||||
{
|
||||
return compare_three_way(*this, other) != strong_ordering::less;
|
||||
return compare_three_way(left, right) != strong_ordering::less;
|
||||
}
|
||||
|
||||
namespace
|
||||
|
@ -444,10 +550,10 @@ namespace mamba::specs
|
|||
auto starts_with_three_way(const VersionPart& a, const VersionPart& b) -> strong_ordering
|
||||
{
|
||||
return lexicographical_compare_three_way_trailing(
|
||||
a.cbegin(),
|
||||
a.cend(),
|
||||
b.cbegin(),
|
||||
b.cend(),
|
||||
a.atoms.cbegin(),
|
||||
a.atoms.cend(),
|
||||
b.atoms.cbegin(),
|
||||
b.atoms.cend(),
|
||||
VersionPartAtom{},
|
||||
AlwaysEqual{},
|
||||
[](const auto& x, const auto& y) { return starts_with_three_way(x, y); }
|
||||
|
@ -615,11 +721,13 @@ namespace mamba::specs
|
|||
{
|
||||
assert(!str.empty());
|
||||
|
||||
VersionPart atoms = {};
|
||||
auto atoms = VersionPart();
|
||||
atoms.implicit_leading_zero = !util::is_digit(str.front());
|
||||
|
||||
while (!str.empty())
|
||||
{
|
||||
atoms.emplace_back();
|
||||
std::tie(atoms.back(), str) = parse_leading_part_atom(str);
|
||||
atoms.atoms.emplace_back();
|
||||
std::tie(atoms.atoms.back(), str) = parse_leading_part_atom(str);
|
||||
}
|
||||
return atoms;
|
||||
}
|
||||
|
@ -843,10 +951,7 @@ fmt::formatter<mamba::specs::Version>::format(const ::mamba::specs::Version v, f
|
|||
}
|
||||
else
|
||||
{
|
||||
for (const auto& atom : version[i])
|
||||
{
|
||||
l_out = fmt::format_to(l_out, "{}", atom);
|
||||
}
|
||||
l_out = fmt::format_to(l_out, "{}", version[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -160,10 +160,10 @@ namespace
|
|||
auto ms = MatchSpec::parse("mingw-w64-ucrt-x86_64-crt-git v12.0.0.r2.ggc561118da h707e725_0")
|
||||
.value();
|
||||
REQUIRE(ms.name().str() == "mingw-w64-ucrt-x86_64-crt-git");
|
||||
REQUIRE(ms.version().str() == "==0v12.0.0.0r2.0ggc561118da");
|
||||
REQUIRE(ms.version().str() == "==v12.0.0.r2.ggc561118da");
|
||||
REQUIRE(ms.build_string().str() == "h707e725_0");
|
||||
REQUIRE(ms.build_number().is_explicitly_free());
|
||||
REQUIRE(ms.str() == "mingw-w64-ucrt-x86_64-crt-git==0v12.0.0.0r2.0ggc561118da=h707e725_0");
|
||||
REQUIRE(ms.str() == "mingw-w64-ucrt-x86_64-crt-git==v12.0.0.r2.ggc561118da=h707e725_0");
|
||||
}
|
||||
|
||||
SECTION("openblas 0.2.18|0.2.18.*.")
|
||||
|
@ -216,20 +216,20 @@ namespace
|
|||
{
|
||||
auto ms = MatchSpec::parse("disperse=v0.9.24").value();
|
||||
REQUIRE(ms.name().str() == "disperse");
|
||||
REQUIRE(ms.version().str() == "=0v0.9.24");
|
||||
REQUIRE(ms.version().str() == "=v0.9.24");
|
||||
REQUIRE(ms.build_string().is_explicitly_free());
|
||||
REQUIRE(ms.build_number().is_explicitly_free());
|
||||
REQUIRE(ms.str() == "disperse=0v0.9.24");
|
||||
REQUIRE(ms.str() == "disperse=v0.9.24");
|
||||
}
|
||||
|
||||
SECTION("disperse v0.9.24")
|
||||
{
|
||||
auto ms = MatchSpec::parse("disperse v0.9.24").value();
|
||||
REQUIRE(ms.name().str() == "disperse");
|
||||
REQUIRE(ms.version().str() == "==0v0.9.24");
|
||||
REQUIRE(ms.version().str() == "==v0.9.24");
|
||||
REQUIRE(ms.build_string().is_explicitly_free());
|
||||
REQUIRE(ms.build_number().is_explicitly_free());
|
||||
REQUIRE(ms.str() == "disperse==0v0.9.24");
|
||||
REQUIRE(ms.str() == "disperse==v0.9.24");
|
||||
}
|
||||
|
||||
SECTION("foo V0.9.24")
|
||||
|
@ -252,10 +252,10 @@ namespace
|
|||
{
|
||||
auto ms = MatchSpec::parse("foo=V0.9.24").value();
|
||||
REQUIRE(ms.name().str() == "foo");
|
||||
REQUIRE(ms.version().str() == "=0v0.9.24");
|
||||
REQUIRE(ms.version().str() == "=v0.9.24");
|
||||
REQUIRE(ms.build_string().is_explicitly_free());
|
||||
REQUIRE(ms.build_number().is_explicitly_free());
|
||||
REQUIRE(ms.str() == "foo=0v0.9.24");
|
||||
REQUIRE(ms.str() == "foo=v0.9.24");
|
||||
}
|
||||
|
||||
SECTION("numpy 1.7*")
|
||||
|
@ -396,7 +396,7 @@ namespace
|
|||
};
|
||||
auto ms = MatchSpec::parse(str).value();
|
||||
REQUIRE(ms.name().str() == "conda");
|
||||
REQUIRE(ms.version().str() == "==4.3.21.0post699+1dab973"); // Note the ``.0post``
|
||||
REQUIRE(ms.version().str() == "==4.3.21.post699+1dab973");
|
||||
REQUIRE(ms.build_string().str() == "py36h4a561cd_0");
|
||||
REQUIRE(ms.str() == str);
|
||||
}
|
||||
|
@ -673,11 +673,9 @@ namespace
|
|||
REQUIRE(ms.channel().value().str() == "conda-canary[linux-64]");
|
||||
REQUIRE(ms.platforms().value().get() == MatchSpec::platform_set{ "linux-64" });
|
||||
REQUIRE(ms.name().str() == "conda");
|
||||
REQUIRE(ms.version().str() == "==4.3.21.0post699+1dab973"); // Not ``.0post`` diff
|
||||
REQUIRE(ms.version().str() == "==4.3.21.post699+1dab973");
|
||||
REQUIRE(ms.build_string().str() == "py36h4a561cd_0");
|
||||
REQUIRE(
|
||||
ms.str() == "conda-canary[linux-64]::conda==4.3.21.0post699+1dab973=py36h4a561cd_0"
|
||||
);
|
||||
REQUIRE(ms.str() == "conda-canary[linux-64]::conda==4.3.21.post699+1dab973=py36h4a561cd_0");
|
||||
}
|
||||
|
||||
SECTION("libblas[build=^.*(accelerate|mkl)$]")
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
#include <fmt/format.h>
|
||||
|
||||
#include "mamba/specs/version.hpp"
|
||||
#include "mamba/util/string.hpp"
|
||||
|
||||
using namespace mamba::specs;
|
||||
|
||||
namespace
|
||||
{
|
||||
TEST_CASE("atom_comparison", "[mamba::specs][mamba::specs::Version]")
|
||||
TEST_CASE("VersionPartAtom", "[mamba::specs][mamba::specs::Version]")
|
||||
{
|
||||
// No literal
|
||||
REQUIRE(VersionPartAtom(1) == VersionPartAtom(1, ""));
|
||||
|
@ -37,20 +38,20 @@ namespace
|
|||
REQUIRE(VersionPartAtom(1, "a") >= VersionPartAtom(1, "dev"));
|
||||
|
||||
// clang-format off
|
||||
auto sorted_atoms = std::array{
|
||||
VersionPartAtom{ 1, "*" },
|
||||
VersionPartAtom{ 1, "dev" },
|
||||
VersionPartAtom{ 1, "_" },
|
||||
VersionPartAtom{ 1, "a" },
|
||||
VersionPartAtom{ 1, "alpha" },
|
||||
VersionPartAtom{ 1, "b" },
|
||||
VersionPartAtom{ 1, "beta" },
|
||||
VersionPartAtom{ 1, "c" },
|
||||
VersionPartAtom{ 1, "r" },
|
||||
VersionPartAtom{ 1, "rc" },
|
||||
VersionPartAtom{ 1, "" },
|
||||
VersionPartAtom{ 1, "post" },
|
||||
};
|
||||
auto const sorted_atoms = std::array{
|
||||
VersionPartAtom{ 1, "*" },
|
||||
VersionPartAtom{ 1, "dev" },
|
||||
VersionPartAtom{ 1, "_" },
|
||||
VersionPartAtom{ 1, "a" },
|
||||
VersionPartAtom{ 1, "alpha" },
|
||||
VersionPartAtom{ 1, "b" },
|
||||
VersionPartAtom{ 1, "beta" },
|
||||
VersionPartAtom{ 1, "c" },
|
||||
VersionPartAtom{ 1, "r" },
|
||||
VersionPartAtom{ 1, "rc" },
|
||||
VersionPartAtom{ 1, "" },
|
||||
VersionPartAtom{ 1, "post" },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// Strict ordering
|
||||
|
@ -59,18 +60,55 @@ namespace
|
|||
REQUIRE(std::adjacent_find(sorted_atoms.cbegin(), sorted_atoms.cend()) == sorted_atoms.cend());
|
||||
}
|
||||
|
||||
TEST_CASE("atom_format", "[mamba::specs][mamba::specs::Version]")
|
||||
TEST_CASE("VersionPartAtom::str", "[mamba::specs][mamba::specs::Version]")
|
||||
{
|
||||
REQUIRE(VersionPartAtom(1, "dev").str() == "1dev");
|
||||
REQUIRE(VersionPartAtom(2).str() == "2");
|
||||
}
|
||||
|
||||
TEST_CASE("version_comparison", "[mamba::specs][mamba::specs::Version]")
|
||||
TEST_CASE("VersionPart", "[mamba::specs][mamba::specs::Version]")
|
||||
{
|
||||
// clang-format off
|
||||
REQUIRE(VersionPart{{1, "dev"}} == VersionPart{{1, "dev"}});
|
||||
REQUIRE(VersionPart{{1, "dev"}} == VersionPart{{1, "dev"}, {0, ""}});
|
||||
REQUIRE(VersionPart{{1, "dev"}, {2, ""}} == VersionPart{{1, "dev"}, {2, ""}});
|
||||
REQUIRE(VersionPart({{0, "dev"}, {2, ""}}, true) == VersionPart{{0, "dev"}, {2, ""}});
|
||||
REQUIRE(VersionPart{{0, "dev"} } != VersionPart{{0, "dev"}, {2, ""}});
|
||||
|
||||
auto const sorted_parts = std::array{
|
||||
VersionPart{{0, ""}},
|
||||
VersionPart{{1, "dev"}, {0, "alpha"}},
|
||||
VersionPart{{1, "dev"}},
|
||||
VersionPart{{1, "dev"}, {1, "dev"}},
|
||||
VersionPart{{2, "dev"}, {1, "dev"}},
|
||||
VersionPart{{2, ""}},
|
||||
VersionPart{{2, ""}, {0, "post"}},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// Strict ordering
|
||||
REQUIRE(std::is_sorted(sorted_parts.cbegin(), sorted_parts.cend()));
|
||||
// None compare equal (given the is_sorted assumption)
|
||||
REQUIRE(std::adjacent_find(sorted_parts.cbegin(), sorted_parts.cend()) == sorted_parts.cend());
|
||||
}
|
||||
|
||||
TEST_CASE("VersionPart::str", "[mamba::specs][mamba::specs::Version]")
|
||||
{
|
||||
REQUIRE(VersionPart{ { 1, "dev" } }.str() == "1dev");
|
||||
REQUIRE(VersionPart{ { 1, "dev" }, { 2, "" } }.str() == "1dev2");
|
||||
REQUIRE(VersionPart{ { 1, "dev" }, { 2, "foo" }, { 33, "bar" } }.str() == "1dev2foo33bar");
|
||||
REQUIRE(VersionPart({ { 0, "dev" }, { 2, "" } }, false).str() == "0dev2");
|
||||
REQUIRE(VersionPart({ { 0, "dev" }, { 2, "" } }, true).str() == "dev2");
|
||||
REQUIRE(VersionPart({ { 0, "dev" } }, true).str() == "dev");
|
||||
REQUIRE(VersionPart({ { 0, "" } }, true).str() == "0");
|
||||
}
|
||||
|
||||
TEST_CASE("Version cmp", "[mamba::specs][mamba::specs::Version]")
|
||||
{
|
||||
auto v = Version(0, { { { 1, "post" } } });
|
||||
REQUIRE(v.version().size() == 1);
|
||||
REQUIRE(v.version().front().size() == 1);
|
||||
REQUIRE(v.version().front().front() == VersionPartAtom(1, "post"));
|
||||
REQUIRE(v.version().front().atoms.size() == 1);
|
||||
REQUIRE(v.version().front().atoms.front() == VersionPartAtom(1, "post"));
|
||||
|
||||
// Same empty 0!1post version
|
||||
REQUIRE(Version(0, { { { 1, "post" } } }) == Version(0, { { { 1, "post" } } }));
|
||||
|
@ -188,7 +226,7 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("compatible_with", "[mamba::specs][mamba::specs::Version]")
|
||||
TEST_CASE("Version compatible_with", "[mamba::specs][mamba::specs::Version]")
|
||||
{
|
||||
SECTION("positive")
|
||||
{
|
||||
|
@ -303,7 +341,7 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("version_format", "[mamba::specs][mamba::specs::Version]")
|
||||
TEST_CASE("Version::str", "[mamba::specs][mamba::specs::Version]")
|
||||
{
|
||||
SECTION("11a0post.3.4dev")
|
||||
{
|
||||
|
@ -357,65 +395,65 @@ namespace
|
|||
*
|
||||
* @see https://github.com/conda/conda/blob/main/tests/models/test_version.py
|
||||
*/
|
||||
TEST_CASE("Version parse", "[mamba::specs][mamba::specs::Version]")
|
||||
TEST_CASE("Version::parse", "[mamba::specs][mamba::specs::Version]")
|
||||
{
|
||||
// clang-format off
|
||||
auto sorted_version = std::vector<std::pair<std::string_view, Version>>{
|
||||
{"0.4", Version(0, {{{0}}, {{4}}})},
|
||||
{"0.4.0", Version(0, {{{0}}, {{4}}, {{0}}})},
|
||||
{"0.4.1a.vc11", Version(0, {{{0}}, {{4}}, {{1, "a"}}, {{0, "vc"}, {11}}})},
|
||||
{"0.4.1.rc", Version(0, {{{0}}, {{4}}, {{1}}, {{0, "rc"}}})},
|
||||
{"0.4.1.vc11", Version(0, {{{0}}, {{4}}, {{1}}, {{0, "vc"}, {11}}})},
|
||||
{"0.4.1", Version(0, {{{0}}, {{4}}, {{1}}})},
|
||||
{"0.5*", Version(0, {{{0}}, {{5, "*"}}})},
|
||||
{"0.5a1", Version(0, {{{0}}, {{5, "a"}, {1}}})},
|
||||
{"0.5b3", Version(0, {{{0}}, {{5, "b"}, {3}}})},
|
||||
{"0.5C1", Version(0, {{{0}}, {{5, "c"}, {1}}})},
|
||||
{"0.5z", Version(0, {{{0}}, {{5, "z"}}})},
|
||||
{"0.5za", Version(0, {{{0}}, {{5, "za"}}})},
|
||||
{"0.5", Version(0, {{{0}}, {{5}}})},
|
||||
{"0.5_5", Version(0, {{{0}}, {{5}}, {{5}}})},
|
||||
{"0.5-5", Version(0, {{{0}}, {{5}}, {{5}}})},
|
||||
{"0.9.6", Version(0, {{{0}}, {{9}}, {{6}}})},
|
||||
{"0.960923", Version(0, {{{0}}, {{960923}}})},
|
||||
{"1.0", Version(0, {{{1}}, {{0}}})},
|
||||
{"1.0.4a3", Version(0, {{{1}}, {{0}}, {{4, "a"}, {3}}})},
|
||||
{"1.0.4b1", Version(0, {{{1}}, {{0}}, {{4, "b"}, {1}}})},
|
||||
{"1.0.4", Version(0, {{{1}}, {{0}}, {{4}}})},
|
||||
{"1.1dev1", Version(0, {{{1}}, {{1, "dev"}, {1}}})},
|
||||
{"1.1_", Version(0, {{{1}}, {{1, "_"}}})},
|
||||
{"1.1a1", Version(0, {{{1}}, {{1, "a"}, {1}}})},
|
||||
{"1.1.dev1", Version(0, {{{1}}, {{1}}, {{0, "dev"}, {1}}})},
|
||||
{"1.1.a1", Version(0, {{{1}}, {{1}}, {{0, "a"}, {1}}})},
|
||||
{"1.1", Version(0, {{{1}}, {{1}}})},
|
||||
{"1.1.post1", Version(0, {{{1}}, {{1}}, {{0, "post"}, {1}}})},
|
||||
{"1.1.1dev1", Version(0, {{{1}}, {{1}}, {{1, "dev"}, {1}}})},
|
||||
{"1.1.1rc1", Version(0, {{{1}}, {{1}}, {{1, "rc"}, {1}}})},
|
||||
{"1.1.1", Version(0, {{{1}}, {{1}}, {{1}}})},
|
||||
{"1.1.1post1", Version(0, {{{1}}, {{1}}, {{1, "post"}, {1}}})},
|
||||
{"1.1post1", Version(0, {{{1}}, {{1, "post"}, {1}}})},
|
||||
{"2g6", Version(0, {{{2, "g"}, {6}}})},
|
||||
{"2.0b1pr0", Version(0, {{{2}}, {{0, "b"}, {1, "pr"}, {0}}})},
|
||||
{"2.2be.ta29", Version(0, {{{2}}, {{2, "be"}}, {{0, "ta"}, {29}}})},
|
||||
{"2.2be5ta29", Version(0, {{{2}}, {{2, "be"}, {5, "ta"}, {29}}})},
|
||||
{"2.2beta29", Version(0, {{{2}}, {{2, "beta"}, {29}}})},
|
||||
{"2.2.0.1", Version(0, {{{2}}, {{2}}, {{0}}, {{1}}})},
|
||||
{"3.1.1.6", Version(0, {{{3}}, {{1}}, {{1}}, {{6}}})},
|
||||
{"3.2.p.r0", Version(0, {{{3}}, {{2}}, {{0, "p"}}, {{0, "r"}, {0}}})},
|
||||
{"3.2.pr0", Version(0, {{{3}}, {{2}}, {{0, "pr"}, {0}}})},
|
||||
{"3.2.pr.1", Version(0, {{{3}}, {{2}}, {{0, "pr"}}, {{1}}})},
|
||||
{"5.5.kw", Version(0, {{{5}}, {{5}}, {{0, "kw"}}})},
|
||||
{"11g", Version(0, {{{11, "g"}}})},
|
||||
{"14.3.1", Version(0, {{{14}}, {{3}}, {{1}}})},
|
||||
{
|
||||
"14.3.1.post26.g9d75ca2",
|
||||
Version( 0, {{{14}}, {{3}}, {{1}}, {{0, "post"}, {26}}, {{0, "g"}, {9, "d"}, {75, "ca"}, {2}}})
|
||||
},
|
||||
{"1996.07.12", Version(0, {{{1996}}, {{7}}, {{12}}})},
|
||||
{"1!0.4.1", Version(1, {{{0}}, {{4}}, {{1}}})},
|
||||
{"1!3.1.1.6", Version(1, {{{3}}, {{1}}, {{1}}, {{6}}})},
|
||||
{"2!0.4.1", Version(2, {{{0}}, {{4}}, {{1}}})},
|
||||
};
|
||||
auto const sorted_version = std::vector<std::pair<std::string_view, Version>>{
|
||||
{"0.4", Version(0, {{{0}}, {{4}}})},
|
||||
{"0.4.0", Version(0, {{{0}}, {{4}}, {{0}}})},
|
||||
{"0.4.1a.vc11", Version(0, {{{0}}, {{4}}, {{1, "a"}}, {{0, "vc"}, {11}}})},
|
||||
{"0.4.1.rc", Version(0, {{{0}}, {{4}}, {{1}}, {{0, "rc"}}})},
|
||||
{"0.4.1.vc11", Version(0, {{{0}}, {{4}}, {{1}}, {{0, "vc"}, {11}}})},
|
||||
{"0.4.1", Version(0, {{{0}}, {{4}}, {{1}}})},
|
||||
{"0.5*", Version(0, {{{0}}, {{5, "*"}}})},
|
||||
{"0.5a1", Version(0, {{{0}}, {{5, "a"}, {1}}})},
|
||||
{"0.5b3", Version(0, {{{0}}, {{5, "b"}, {3}}})},
|
||||
{"0.5C1", Version(0, {{{0}}, {{5, "c"}, {1}}})},
|
||||
{"0.5z", Version(0, {{{0}}, {{5, "z"}}})},
|
||||
{"0.5za", Version(0, {{{0}}, {{5, "za"}}})},
|
||||
{"0.5", Version(0, {{{0}}, {{5}}})},
|
||||
{"0.5_5", Version(0, {{{0}}, {{5}}, {{5}}})},
|
||||
{"0.5-5", Version(0, {{{0}}, {{5}}, {{5}}})},
|
||||
{"0.9.6", Version(0, {{{0}}, {{9}}, {{6}}})},
|
||||
{"0.960923", Version(0, {{{0}}, {{960923}}})},
|
||||
{"1.0", Version(0, {{{1}}, {{0}}})},
|
||||
{"1.0.4a3", Version(0, {{{1}}, {{0}}, {{4, "a"}, {3}}})},
|
||||
{"1.0.4b1", Version(0, {{{1}}, {{0}}, {{4, "b"}, {1}}})},
|
||||
{"1.0.4", Version(0, {{{1}}, {{0}}, {{4}}})},
|
||||
{"1.1dev1", Version(0, {{{1}}, {{1, "dev"}, {1}}})},
|
||||
{"1.1_", Version(0, {{{1}}, {{1, "_"}}})},
|
||||
{"1.1a1", Version(0, {{{1}}, {{1, "a"}, {1}}})},
|
||||
{"1.1.dev1", Version(0, {{{1}}, {{1}}, {{0, "dev"}, {1}}})},
|
||||
{"1.1.a1", Version(0, {{{1}}, {{1}}, {{0, "a"}, {1}}})},
|
||||
{"1.1", Version(0, {{{1}}, {{1}}})},
|
||||
{"1.1.post1", Version(0, {{{1}}, {{1}}, {{0, "post"}, {1}}})},
|
||||
{"1.1.1dev1", Version(0, {{{1}}, {{1}}, {{1, "dev"}, {1}}})},
|
||||
{"1.1.1rc1", Version(0, {{{1}}, {{1}}, {{1, "rc"}, {1}}})},
|
||||
{"1.1.1", Version(0, {{{1}}, {{1}}, {{1}}})},
|
||||
{"1.1.1post1", Version(0, {{{1}}, {{1}}, {{1, "post"}, {1}}})},
|
||||
{"1.1post1", Version(0, {{{1}}, {{1, "post"}, {1}}})},
|
||||
{"2g6", Version(0, {{{2, "g"}, {6}}})},
|
||||
{"2.0b1pr0", Version(0, {{{2}}, {{0, "b"}, {1, "pr"}, {0}}})},
|
||||
{"2.2be.ta29", Version(0, {{{2}}, {{2, "be"}}, {{0, "ta"}, {29}}})},
|
||||
{"2.2be5ta29", Version(0, {{{2}}, {{2, "be"}, {5, "ta"}, {29}}})},
|
||||
{"2.2beta29", Version(0, {{{2}}, {{2, "beta"}, {29}}})},
|
||||
{"2.2.0.1", Version(0, {{{2}}, {{2}}, {{0}}, {{1}}})},
|
||||
{"3.1.1.6", Version(0, {{{3}}, {{1}}, {{1}}, {{6}}})},
|
||||
{"3.2.p.r0", Version(0, {{{3}}, {{2}}, {{0, "p"}}, {{0, "r"}, {0}}})},
|
||||
{"3.2.pr0", Version(0, {{{3}}, {{2}}, {{0, "pr"}, {0}}})},
|
||||
{"3.2.pr.1", Version(0, {{{3}}, {{2}}, {{0, "pr"}}, {{1}}})},
|
||||
{"5.5.kw", Version(0, {{{5}}, {{5}}, {{0, "kw"}}})},
|
||||
{"11g", Version(0, {{{11, "g"}}})},
|
||||
{"14.3.1", Version(0, {{{14}}, {{3}}, {{1}}})},
|
||||
{
|
||||
"14.3.1.post26.g9d75ca2",
|
||||
Version( 0, {{{14}}, {{3}}, {{1}}, {{0, "post"}, {26}}, {{0, "g"}, {9, "d"}, {75, "ca"}, {2}}})
|
||||
},
|
||||
{"1996.07.12", Version(0, {{{1996}}, {{7}}, {{12}}})},
|
||||
{"1!0.4.1", Version(1, {{{0}}, {{4}}, {{1}}})},
|
||||
{"1!3.1.1.6", Version(1, {{{3}}, {{1}}, {{1}}, {{6}}})},
|
||||
{"2!0.4.1", Version(2, {{{0}}, {{4}}, {{1}}})},
|
||||
};
|
||||
// clang-format on
|
||||
for (const auto& [raw, expected] : sorted_version)
|
||||
{
|
||||
|
@ -442,6 +480,11 @@ namespace
|
|||
REQUIRE(Version::parse("0.4.a1").value() == Version::parse("0.4.0a1"));
|
||||
REQUIRE(Version::parse("0.4.a1").value() != Version::parse("0.4.1a1"));
|
||||
|
||||
// Parse implicit zeros
|
||||
REQUIRE(Version::parse("0.4.a1").value().version()[2].implicit_leading_zero);
|
||||
REQUIRE(Version::parse("0.4.a1").value().str() == "0.4.a1");
|
||||
REQUIRE(Version::parse("g56ffd88f").value().str() == "g56ffd88f");
|
||||
|
||||
// These are valid versions with the special '*' ordering AND they are also used as such
|
||||
// with version globs in VersionSpec
|
||||
REQUIRE(Version::parse("*") == Version(0, { { { 0, "*" } } }));
|
||||
|
@ -456,7 +499,7 @@ namespace
|
|||
REQUIRE(Version::parse("1.*") == Version(0, { { { 1, "" } }, { { 0, "*" } } }));
|
||||
}
|
||||
|
||||
TEST_CASE("parse_invalid", "[mamba::specs][mamba::specs::Version]")
|
||||
TEST_CASE("Version::parse negative", "[mamba::specs][mamba::specs::Version]")
|
||||
{
|
||||
// Wrong epoch
|
||||
REQUIRE_FALSE(Version::parse("!1.1").has_value());
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "mamba/specs/unresolved_channel.hpp"
|
||||
#include "mamba/specs/version.hpp"
|
||||
#include "mamba/specs/version_spec.hpp"
|
||||
#include "mamba/version.hpp"
|
||||
|
||||
#include "bind_utils.hpp"
|
||||
#include "bindings.hpp"
|
||||
|
@ -27,8 +28,10 @@
|
|||
#include "flat_set_caster.hpp"
|
||||
#include "weakening_map_bind.hpp"
|
||||
|
||||
PYBIND11_MAKE_OPAQUE(mamba::specs::VersionPart);
|
||||
PYBIND11_MAKE_OPAQUE(mamba::specs::CommonVersion);
|
||||
using OldVersionPart = std::vector<mamba::specs::VersionPartAtom>;
|
||||
using OldCommonVersion = std::vector<OldVersionPart>;
|
||||
PYBIND11_MAKE_OPAQUE(OldVersionPart);
|
||||
PYBIND11_MAKE_OPAQUE(OldCommonVersion);
|
||||
|
||||
namespace mambapy
|
||||
{
|
||||
|
@ -529,11 +532,28 @@ namespace mambapy
|
|||
.def("__copy__", ©<VersionPartAtom>)
|
||||
.def("__deepcopy__", &deepcopy<VersionPartAtom>, py::arg("memo"));
|
||||
|
||||
// Type made opaque at the top of this file
|
||||
py::bind_vector<VersionPart>(m, "VersionPart");
|
||||
// TODO(3.0): Align the Python API of VersionPart (and thus break CommonVersion,
|
||||
// Version::version, Version::local), with the C++ one.
|
||||
static_assert(LIBMAMBA_VERSION_MAJOR < 3, "Take the major release opportunity to clean APIs.");
|
||||
|
||||
// Type made opaque at the top of this file
|
||||
py::bind_vector<CommonVersion>(m, "CommonVersion");
|
||||
py::bind_vector<OldVersionPart>(m, "VersionPart");
|
||||
|
||||
// Type made opaque at the top of this file
|
||||
py::bind_vector<OldCommonVersion>(m, "CommonVersion");
|
||||
|
||||
constexpr auto common_version_backport = [](const CommonVersion& version) -> OldCommonVersion
|
||||
{
|
||||
auto old = OldCommonVersion();
|
||||
old.reserve(version.size());
|
||||
std::transform(
|
||||
version.cbegin(),
|
||||
version.cend(),
|
||||
std::back_inserter(old),
|
||||
[](const auto& a) { return a.atoms; }
|
||||
);
|
||||
return old;
|
||||
};
|
||||
|
||||
py::class_<Version>(m, "Version")
|
||||
.def_readonly_static("epoch_delim", &Version::epoch_delim)
|
||||
|
@ -549,8 +569,14 @@ namespace mambapy
|
|||
py::arg("local") = CommonVersion()
|
||||
)
|
||||
.def_property_readonly("epoch", &Version::epoch)
|
||||
.def_property_readonly("version", &Version::version)
|
||||
.def_property_readonly("local", &Version::local)
|
||||
.def_property_readonly(
|
||||
"version",
|
||||
[=](const Version& self) { return common_version_backport(self.version()); }
|
||||
)
|
||||
.def_property_readonly(
|
||||
"local",
|
||||
[=](const Version& self) { return common_version_backport(self.local()); }
|
||||
)
|
||||
.def("starts_with", &Version::starts_with, py::arg("prefix"))
|
||||
.def("compatible_with", &Version::compatible_with, py::arg("older"), py::arg("level"))
|
||||
.def("__str__", [](const Version& v) { return v.str(); })
|
||||
|
|
|
@ -598,8 +598,10 @@ def test_VersionPart():
|
|||
VersionPartAtom = libmambapy.specs.VersionPartAtom
|
||||
VersionPart = libmambapy.specs.VersionPart
|
||||
|
||||
p = VersionPart([VersionPartAtom(1, "a"), VersionPartAtom(3)])
|
||||
assert len(p) == 2
|
||||
atoms = [VersionPartAtom(1, "a"), VersionPartAtom(3)]
|
||||
p = VersionPart(atoms)
|
||||
assert len(p) == len(atoms)
|
||||
assert p == p
|
||||
|
||||
|
||||
def test_CommonVersion():
|
||||
|
|
Loading…
Reference in New Issue