Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BuildNumberSpec #3098

Merged
merged 5 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libmamba/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ set(
# Implementation of version and matching specs
${LIBMAMBA_SOURCE_DIR}/specs/archive.cpp
${LIBMAMBA_SOURCE_DIR}/specs/authentication_info.cpp
${LIBMAMBA_SOURCE_DIR}/specs/build_number_spec.cpp
${LIBMAMBA_SOURCE_DIR}/specs/channel.cpp
${LIBMAMBA_SOURCE_DIR}/specs/channel_spec.cpp
${LIBMAMBA_SOURCE_DIR}/specs/conda_url.cpp
Expand Down Expand Up @@ -285,6 +286,7 @@ set(
# Implementation of version and matching specs
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/archive.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/authentication_info.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/build_number_spec.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/channel.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/channel_spec.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/conda_url.hpp
Expand Down
156 changes: 156 additions & 0 deletions libmamba/include/mamba/specs/build_number_spec.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// 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_BUILD_NUMBER_SPEC_HPP
#define MAMBA_SPECS_BUILD_NUMBER_SPEC_HPP

#include <array>
#include <functional>
#include <string_view>
#include <variant>

#include <fmt/format.h>

namespace mamba::specs
{
/**
* A stateful unary boolean function on the integer space.
*/
class BuildNumberPredicate
{
public:

using BuildNumber = int;

[[nodiscard]] static auto make_free() -> BuildNumberPredicate;
[[nodiscard]] static auto make_equal_to(BuildNumber ver) -> BuildNumberPredicate;
[[nodiscard]] static auto make_not_equal_to(BuildNumber ver) -> BuildNumberPredicate;
[[nodiscard]] static auto make_greater(BuildNumber ver) -> BuildNumberPredicate;
[[nodiscard]] static auto make_greater_equal(BuildNumber ver) -> BuildNumberPredicate;
[[nodiscard]] static auto make_less(BuildNumber ver) -> BuildNumberPredicate;
[[nodiscard]] static auto make_less_equal(BuildNumber ver) -> BuildNumberPredicate;

/** Construct an free interval. */
BuildNumberPredicate() = default;

/**
* True if the predicate contains the given build_number.
*/
[[nodiscard]] auto contains(const BuildNumber& point) const -> bool;

[[nodiscard]] auto str() const -> std::string;

private:

struct free_interval
{
auto operator()(const BuildNumber&, const BuildNumber&) const -> bool;
};

/**
* Operator to compare with the stored build_number.
*/
using BinaryOperator = std::variant<
free_interval,
std::equal_to<BuildNumber>,
std::not_equal_to<BuildNumber>,
std::greater<BuildNumber>,
std::greater_equal<BuildNumber>,
std::less<BuildNumber>,
std::less_equal<BuildNumber>>;

BuildNumber m_build_number = {};
BinaryOperator m_operator = free_interval{};

BuildNumberPredicate(BuildNumber ver, BinaryOperator op);

friend auto equal(free_interval, free_interval) -> bool;
friend auto operator==(const BuildNumberPredicate& lhs, const BuildNumberPredicate& rhs)
-> bool;
friend class ::fmt::formatter<BuildNumberPredicate>;
};

auto operator==(const BuildNumberPredicate& lhs, const BuildNumberPredicate& rhs) -> bool;
auto operator!=(const BuildNumberPredicate& lhs, const BuildNumberPredicate& rhs) -> bool;

/**
* Match a build number with a predicate.
*
* Conda does not implement expression for build numbers but they could be added similarily
* to @ref VersionSpec.
*/
class BuildNumberSpec
{
public:

using BuildNumber = typename BuildNumberPredicate::BuildNumber;

static constexpr std::string_view prefered_free_str = "=*";
static constexpr std::array<std::string_view, 4> all_free_strs = { "", "*", "=*", "==*" };
static constexpr std::string_view equal_str = "=";
static constexpr std::string_view not_equal_str = "!=";
static constexpr std::string_view greater_str = ">";
static constexpr std::string_view greater_equal_str = ">=";
static constexpr std::string_view less_str = "<";
static constexpr std::string_view less_equal_str = "<=";

[[nodiscard]] static auto parse(std::string_view str) -> BuildNumberSpec;

/** Construct BuildNumberSpec that match all versions. */
BuildNumberSpec();

explicit BuildNumberSpec(BuildNumberPredicate predicate) noexcept;

/**
* Returns wether the BuildNumberSpec is unconstrained.
*/
[[nodiscard]] auto is_explicitly_free() const -> bool;

/**
* A string representation of the build number spec.
*
* May not always be the same as the parsed string (due to reconstruction) but reparsing
* this string will give the same build number spec.
*/
[[nodiscard]] auto str() const -> std::string;

/**
* True if the set described by the BuildNumberSpec contains the given version.
*/
[[nodiscard]] auto contains(BuildNumber point) const -> bool;

private:

BuildNumberPredicate m_predicate;

friend class ::fmt::formatter<BuildNumberSpec>;
};

namespace build_number_spec_literals
{
auto operator""_bs(const char* str, std::size_t len) -> BuildNumberSpec;
}
}

template <>
struct fmt::formatter<mamba::specs::BuildNumberPredicate>
{
auto parse(format_parse_context& ctx) -> decltype(ctx.begin());

auto format(const ::mamba::specs::BuildNumberPredicate& pred, format_context& ctx)
-> decltype(ctx.out());
};

template <>
struct fmt::formatter<mamba::specs::BuildNumberSpec>
{
auto parse(format_parse_context& ctx) -> decltype(ctx.begin());

auto format(const ::mamba::specs::BuildNumberSpec& spec, format_context& ctx)
-> decltype(ctx.out());
};

#endif
7 changes: 4 additions & 3 deletions libmamba/include/mamba/specs/match_spec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <tuple>
#include <unordered_map>

#include "mamba/specs/build_number_spec.hpp"
#include "mamba/specs/channel_spec.hpp"
#include "mamba/specs/glob_spec.hpp"
#include "mamba/specs/version_spec.hpp"
Expand Down Expand Up @@ -45,8 +46,8 @@ namespace mamba::specs
[[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);
[[nodiscard]] auto build_number() const -> const BuildNumberSpec&;
void set_build_number(BuildNumberSpec num);

[[nodiscard]] auto build_string() const -> const BuildStringSpec&;
void set_build_string(BuildStringSpec bs);
Expand Down Expand Up @@ -76,7 +77,7 @@ namespace mamba::specs
NameSpec m_name;
BuildStringSpec m_build_string;
std::string m_name_space;
std::string m_build_number;
BuildNumberSpec m_build_number;
// TODO can put inside channel spec
std::string m_filename;
std::string m_url;
Expand Down
20 changes: 18 additions & 2 deletions libmamba/src/core/satisfiability_error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,22 @@ namespace mamba
}
}

template <typename T>
auto invoke_build_number(T&& e) -> decltype(auto)
{
using TT = std::remove_cv_t<std::remove_reference_t<T>>;
using Num = decltype(std::invoke(&TT::build_number, std::forward<T>(e)));
Num num = std::invoke(&TT::build_number, std::forward<T>(e));
if constexpr (std::is_same_v<std::decay_t<decltype(num)>, specs::BuildNumberSpec>)
{
return std::forward<Num>(num).str();
}
else
{
return num;
}
}

template <typename T>
auto invoke_build_string(T&& e) -> decltype(auto)
{
Expand Down Expand Up @@ -594,12 +610,12 @@ namespace mamba
using Attrs = std::tuple<
decltype(invoke_name(x)),
decltype(invoke_version(x)),
decltype(std::invoke(&T::build_number, x)),
decltype(invoke_build_number(x)),
decltype(invoke_build_string(x))>;
return Attrs(
invoke_name(x),
invoke_version(x),
std::invoke(&T::build_number, x),
invoke_build_number(x),
invoke_build_string(x)
);
};
Expand Down
Loading
Loading