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

Solver improvements #3140

Merged
merged 9 commits into from
Jan 19, 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
1 change: 1 addition & 0 deletions libmamba/include/mamba/core/error_handling.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace mamba
satisfiablitity_error,
user_interrupted,
incorrect_usage,
invalid_spec
};

class mamba_error : public std::runtime_error
Expand Down
18 changes: 2 additions & 16 deletions libmamba/include/mamba/core/solver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,6 @@
#include "mamba/specs/match_spec.hpp"
#include "mamba/specs/package_info.hpp"

#define PY_MAMBA_NO_DEPS 0b0001
#define PY_MAMBA_ONLY_DEPS 0b0010
#define PY_MAMBA_FORCE_REINSTALL 0b0100

extern "C"
{
typedef struct s_Solver Solver;
}

namespace mamba::solv
{
class ObjQueue;
Expand All @@ -42,7 +33,7 @@ namespace mamba::solv
namespace mamba
{

struct MSolverProblem
struct SolverProblem
{
SolverRuleinfo type;
Id source_id;
Expand Down Expand Up @@ -78,12 +69,9 @@ namespace mamba

void add_global_job(int job_flag);
void add_jobs(const std::vector<std::string>& jobs, int job_flag);
void add_constraint(const std::string& job);
void add_pin(const std::string& pin);
void add_pins(const std::vector<std::string>& pins);

[[deprecated]] void py_set_postsolve_flags(const std::vector<std::pair<int, int>>& flags);

void set_flags(const Flags& flags); // TODO temporary Itf meant to be passed in ctor
[[nodiscard]] auto flags() const -> const Flags&;
[[deprecated]] void py_set_libsolv_flags(const std::vector<std::pair<int, int>>& flags);
Expand All @@ -94,7 +82,7 @@ namespace mamba

[[nodiscard]] std::string problems_to_str() const;
[[nodiscard]] std::vector<std::string> all_problems() const;
[[nodiscard]] std::vector<MSolverProblem> all_problems_structured() const;
[[nodiscard]] std::vector<SolverProblem> all_problems_structured() const;
[[nodiscard]] ProblemsGraph problems_graph() const;
[[nodiscard]] std::string all_problems_to_str() const;
std::ostream& explain_problems(std::ostream& out) const;
Expand All @@ -109,8 +97,6 @@ namespace mamba
[[nodiscard]] const std::vector<specs::MatchSpec>& neuter_specs() const;
[[nodiscard]] const std::vector<specs::MatchSpec>& pinned_specs() const;

operator const Solver*() const;
operator Solver*();
auto solver() -> solv::ObjSolver&;
auto solver() const -> const solv::ObjSolver&;

Expand Down
145 changes: 4 additions & 141 deletions libmamba/src/core/pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,148 +148,11 @@ namespace mamba
return solvables.as<std::vector>();
}

namespace
auto MPool::matchspec2id(const specs::MatchSpec& ms) -> ::Id
{
auto
channel_match(const std::vector<specs::Channel>& ms_channels, const specs::CondaURL& pkg_url)
-> specs::Channel::Match
{
auto match = specs::Channel::Match::No;
// More than one element means the channel spec was a custom_multi_channel
for (const auto& chan : ms_channels)
{
switch (chan.contains_package(pkg_url))
{
case specs::Channel::Match::Full:
return specs::Channel::Match::Full;
case specs::Channel::Match::InOtherPlatform:
// Keep looking for full matches
match = specs::Channel::Match::InOtherPlatform;
break;
case specs::Channel::Match::No:
// No overriding potential InOtherPlatform match
break;
}
}
return match;
}

/**
* Add function to handle matchspec while parsing is done by libsolv.
*/
auto add_channel_specific_matchspec(
ChannelContext& channel_context,
solv::ObjPool& pool,
const specs::MatchSpec& ms
) -> solv::DependencyId
{
assert(ms.channel().has_value());
// Poor man's ms repr to match waht the user provided
const std::string repr = fmt::format("{}::{}", *ms.channel(), ms.conda_build_form());

// Already added, return that id
if (const auto maybe_id = pool.find_string(repr))
{
return maybe_id.value();
}

// conda_build_form does **NOT** contain the channel info
const solv::DependencyId match = pool_conda_matchspec(
pool.raw(),
ms.conda_build_form().c_str()
);

auto ms_channels = channel_context.make_channel(*ms.channel());

solv::ObjQueue selected_pkgs = {};
auto other_subdir_match = std::string();
pool.for_each_whatprovides(
match,
[&](solv::ObjSolvableViewConst s)
{
if (s.installed())
{
// This will have the effect that channel-specific MatchSpec will always be
// reinstalled.
// This is not the intended behaviour but an historical artifact on which
// ``--force-reinstall`` currently rely.
return;
}

assert(ms.channel().has_value());
const auto match = channel_match(ms_channels, specs::CondaURL::parse(s.url()));
switch (match)
{
case (specs::Channel::Match::Full):
{
selected_pkgs.push_back(s.id());
break;
}
case (specs::Channel::Match::InOtherPlatform):
{
other_subdir_match = s.subdir();
break;
}
case (specs::Channel::Match::No):
{
break;
}
}
}
);

if (selected_pkgs.empty())
{
if (!other_subdir_match.empty())
{
const auto& filters = ms.channel()->platform_filters();
throw std::runtime_error(fmt::format(
R"(The package "{}" is not available for the specified platform{} ({}))"
R"( but is available on {}.)",
ms.str(),
filters.size() > 1 ? "s" : "",
fmt::join(filters, ", "),
other_subdir_match
));
}
else
{
throw std::runtime_error(fmt::format(
R"(The package "{}" is not found in any loaded channels.)"
R"( Try adding more channels or subdirs.)",
ms.str()
));
}
}

const solv::StringId repr_id = pool.add_string(repr);
// FRAGILE This get deleted when calling ``pool_createwhatprovides`` so care
// must be taken to do it before
// TODO investigate namespace providers
pool.add_to_whatprovides(repr_id, pool.add_to_whatprovides_data(selected_pkgs));
return repr_id;
}
}

::Id MPool::matchspec2id(const specs::MatchSpec& ms)
{
::Id id = 0;
if (!ms.channel().has_value())
{
id = pool_conda_matchspec(pool().raw(), ms.conda_build_form().c_str());
}
else
{
// Working around shortcomings of ``pool_conda_matchspec``
// The channels are not processed.
// TODO Fragile! Installing this matchspec will always trigger a reinstall
id = add_channel_specific_matchspec(channel_context(), pool(), ms);
}
if (id == 0)
{
throw std::runtime_error("libsolv error: could not create matchspec from string");
}
return id;
return solver::libsolv::pool_add_matchspec(pool(), ms, channel_context().params())
.or_else([](mamba_error&& error) { throw std::move(error); })
.value_or(0);
}

std::optional<specs::PackageInfo> MPool::id2pkginfo(Id solv_id) const
Expand Down
Loading
Loading