Skip to content

Commit

Permalink
Make MPool::matchspec2id properly process channels
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoinePrv committed Mar 31, 2023
1 parent d9a843c commit e8d6b3d
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 129 deletions.
3 changes: 2 additions & 1 deletion libmamba/include/mamba/core/match_spec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define MAMBA_CORE_MATCH_SPEC

#include <string>
#include <string_view>
#include <tuple>
#include <unordered_map>

Expand All @@ -18,7 +19,7 @@ namespace mamba
public:

MatchSpec() = default;
MatchSpec(const std::string& i_spec);
MatchSpec(std::string_view i_spec);

void parse();
std::string conda_build_form() const;
Expand Down
4 changes: 3 additions & 1 deletion libmamba/include/mamba/core/pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

namespace mamba
{
class MatchSpec;

/**
* Pool of solvable involved in resolving en environment.
*
Expand All @@ -38,7 +40,7 @@ namespace mamba
void create_whatprovides();

std::vector<Id> select_solvables(Id id, bool sorted = false) const;
Id matchspec2id(const std::string& ms);
Id matchspec2id(const MatchSpec& ms);

std::optional<PackageInfo> id2pkginfo(Id solv_id) const;
std::optional<std::string> dep2str(Id dep_id) const;
Expand Down
1 change: 0 additions & 1 deletion libmamba/include/mamba/core/solver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ namespace mamba

private:

void add_channel_specific_job(const MatchSpec& ms, int job_flag);
void add_reinstall_job(MatchSpec& ms, int job_flag);

std::vector<std::pair<int, int>> m_flags;
Expand Down
3 changes: 1 addition & 2 deletions libmamba/src/core/match_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ namespace mamba
return split_str;
}


MatchSpec::MatchSpec(const std::string& i_spec)
MatchSpec::MatchSpec(std::string_view i_spec)
: spec(i_spec)
{
parse();
Expand Down
82 changes: 79 additions & 3 deletions libmamba/src/core/pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ extern "C" // Incomplete header
#include <spdlog/spdlog.h>

#include "mamba/core/context.hpp"
#include "mamba/core/match_spec.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/core/util_string.hpp"
Expand Down Expand Up @@ -148,10 +149,85 @@ namespace mamba
return solvables.as<std::vector>();
}

Id MPool::matchspec2id(const std::string& ms)
namespace
{
Id id = pool_conda_matchspec(pool(), ms.c_str());
if (!id)
bool channel_match(Solvable* s, const Channel& needle)
{
MRepo* mrepo = reinterpret_cast<MRepo*>(s->repo->appdata);
const Channel* chan = mrepo->channel();

if (!chan)
{
return false;
}

if ((*chan) == needle)
{
return true;
}

auto& custom_multichannels = Context::instance().custom_multichannels;
auto x = custom_multichannels.find(needle.name());
if (x != custom_multichannels.end())
{
for (auto el : (x->second))
{
const Channel& inner = make_channel(el);
if ((*chan) == inner)
{
return true;
}
}
}

return false;
}

::Id add_channel_specific_matchspec(::Pool* pool, const MatchSpec& ms)
{
// Poor man's ms repr to match waht the user provided
std::string const repr = fmt::format("{}::{}", ms.channel, ms.conda_build_form());

// Already added, return that id
if (::Id repr_id = pool_str2id(pool, repr.c_str(), /* .create= */ false); repr_id != 0)
{
return repr_id;
}

solv::ObjQueue selected_pkgs;

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

const Channel& c = make_channel(ms.channel);
for (Id* wp = pool_whatprovides_ptr(pool, match); *wp; wp++)
{
if (channel_match(pool_id2solvable(pool, *wp), c))
{
selected_pkgs.push_back(*wp);
}
}
::Id const repr_id = pool_str2id(pool, repr.c_str(), /* .create= */ true);
::Id const offset = pool_queuetowhatprovides(pool, selected_pkgs.raw());
pool_set_whatprovides(pool, repr_id, offset);
return repr_id;
}
}

::Id MPool::matchspec2id(const MatchSpec& ms)
{
::Id id = 0;
if (ms.channel.empty())
{
id = pool_conda_matchspec(pool(), ms.conda_build_form().c_str());
}
else
{
// Working around shortcomings of ``pool_conda_matchspec``
// The channels are not processed.
id = add_channel_specific_matchspec(pool(), ms);
}
if (id == 0)
{
throw std::runtime_error("libsolv error: could not create matchspec from string");
}
Expand Down
9 changes: 6 additions & 3 deletions libmamba/src/core/satisfiability_error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,10 @@ namespace mamba
problem.target_id,
PackageNode{ std::move(target).value() }
);
node_id cons_id = add_solvable(problem.dep_id, ConstraintNode{ dep.value() });
node_id cons_id = add_solvable(
problem.dep_id,
ConstraintNode{ { dep.value() } }
);
MatchSpec edge(dep.value());
m_graph.add_edge(src_id, cons_id, std::move(edge));
add_conflict(cons_id, tgt_id);
Expand Down Expand Up @@ -225,7 +228,7 @@ namespace mamba
MatchSpec edge(dep.value());
node_id dep_id = add_solvable(
problem.dep_id,
UnresolvedDependencyNode{ std::move(dep).value() }
UnresolvedDependencyNode{ { std::move(dep).value() } }
);
m_graph.add_edge(m_root_node, dep_id, std::move(edge));
break;
Expand All @@ -248,7 +251,7 @@ namespace mamba
);
node_id dep_id = add_solvable(
problem.dep_id,
UnresolvedDependencyNode{ std::move(dep).value() }
UnresolvedDependencyNode{ { std::move(dep).value() } }
);
m_graph.add_edge(src_id, dep_id, std::move(edge));
break;
Expand Down
127 changes: 16 additions & 111 deletions libmamba/src/core/solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@
#include <fmt/ostream.h>
#include <solv/pool.h>
#include <solv/solver.h>
extern "C" // Incomplete header
{
#include <solv/conda.h>
}

#include "mamba/core/channel.hpp"
#include "mamba/core/context.hpp"
Expand Down Expand Up @@ -212,74 +208,11 @@ namespace mamba

MSolver::~MSolver() = default;

inline bool channel_match(Solvable* s, const Channel& needle)
{
MRepo* mrepo = reinterpret_cast<MRepo*>(s->repo->appdata);
const Channel* chan = mrepo->channel();

if (!chan)
{
return false;
}

if ((*chan) == needle)
{
return true;
}

auto& custom_multichannels = Context::instance().custom_multichannels;
auto x = custom_multichannels.find(needle.name());
if (x != custom_multichannels.end())
{
for (auto el : (x->second))
{
const Channel& inner = make_channel(el);
if ((*chan) == inner)
{
return true;
}
}
}

return false;
}

void MSolver::add_global_job(int job_flag)
{
m_jobs->push_back(job_flag, 0);
}

void MSolver::add_channel_specific_job(const MatchSpec& ms, int job_flag)
{
Pool* pool = m_pool;
solv::ObjQueue selected_pkgs;

// conda_build_form does **NOT** contain the channel info
Id match = pool_conda_matchspec(pool, ms.conda_build_form().c_str());

const Channel& c = make_channel(ms.channel);
for (Id* wp = pool_whatprovides_ptr(pool, match); *wp; wp++)
{
if (channel_match(pool_id2solvable(pool, *wp), c))
{
selected_pkgs.push_back(*wp);
}
}
if (selected_pkgs.size() == 0)
{
LOG_ERROR << "Selected channel specific (or force-reinstall) job, but "
"package is not available from channel. Solve job will fail.";
}
Id offset = pool_queuetowhatprovides(pool, selected_pkgs.raw());
// Poor man's ms repr to match waht the user provided
std::string const repr = fmt::format("{}::{}", ms.channel, ms.conda_build_form());
Id repr_id = pool_str2id(pool, repr.c_str(), 1);
// We add a new entry into the whatprovides to reflect the channel specific job
pool_set_whatprovides(pool, repr_id, offset);
// We ask to install that new entry
m_jobs->push_back(job_flag, repr_id);
}

void MSolver::add_reinstall_job(MatchSpec& ms, int job_flag)
{
Pool* const pool = m_pool;
Expand Down Expand Up @@ -335,12 +268,15 @@ namespace mamba
);
LOG_INFO << "Reinstall " << modified_spec.conda_build_form() << " from channel "
<< selected_channel;
return add_channel_specific_job(modified_spec, job_flag);
m_jobs->push_back(
job_flag | SOLVER_SOLVABLE_PROVIDES,
m_pool.matchspec2id(modified_spec)
);
return;
}
}
}
Id inst_id = pool_conda_matchspec(m_pool, ms.conda_build_form().c_str());
m_jobs->push_back(job_flag | SOLVER_SOLVABLE_PROVIDES, inst_id);
m_jobs->push_back(job_flag | SOLVER_SOLVABLE_PROVIDES, m_pool.matchspec2id(ms));
}

void MSolver::add_jobs(const std::vector<std::string>& jobs, int job_flag)
Expand All @@ -363,56 +299,34 @@ namespace mamba
m_neuter_specs.emplace_back(job); // not used for the moment
}

::Id const job_id = m_pool.matchspec2id(ms);

// This is checking if SOLVER_ERASE and SOLVER_INSTALL are set
// which are the flags for SOLVER_UPDATE
if (((job_flag & SOLVER_UPDATE) ^ SOLVER_UPDATE) == 0)
if ((job_flag & SOLVER_UPDATE) == SOLVER_UPDATE)
{
// ignoring update specs here for now
if (!ms.is_simple())
{
Id inst_id = pool_conda_matchspec(m_pool, ms.conda_build_form().c_str());
m_jobs->push_back(SOLVER_INSTALL | SOLVER_SOLVABLE_PROVIDES, inst_id);
}
if (ms.channel.empty())
{
Id update_id = pool_conda_matchspec(m_pool, ms.name.c_str());
m_jobs->push_back(job_flag | SOLVER_SOLVABLE_PROVIDES, update_id);
m_jobs->push_back(SOLVER_INSTALL | SOLVER_SOLVABLE_PROVIDES, job_id);
}
else
{
add_channel_specific_job(ms, job_flag);
}

continue;
}

if (!ms.channel.empty())
{
if (job_type == SOLVER_ERASE)
{
throw std::runtime_error("Cannot remove channel-specific spec '" + job + "'");
}
add_channel_specific_job(ms, job_flag);
m_jobs->push_back(job_flag | SOLVER_SOLVABLE_PROVIDES, job_id);
}
else if (job_flag & SOLVER_INSTALL && force_reinstall)
else if ((job_flag & SOLVER_INSTALL) && force_reinstall)
{
add_reinstall_job(ms, job_flag);
}
else
{
// Todo remove double parsing?
LOG_INFO << "Adding job: " << ms.conda_build_form();
Id inst_id = pool_conda_matchspec(m_pool, ms.conda_build_form().c_str());
m_jobs->push_back(job_flag | SOLVER_SOLVABLE_PROVIDES, inst_id);
LOG_INFO << "Adding job: " << ms.str();
m_jobs->push_back(job_flag | SOLVER_SOLVABLE_PROVIDES, job_id);
}
}
}

void MSolver::add_constraint(const std::string& job)
{
MatchSpec ms(job);
Id inst_id = pool_conda_matchspec(m_pool, ms.conda_build_form().c_str());
m_jobs->push_back(SOLVER_INSTALL | SOLVER_SOLVABLE_PROVIDES, inst_id);
m_jobs->push_back(SOLVER_INSTALL | SOLVER_SOLVABLE_PROVIDES, m_pool.matchspec2id({ job }));
}

void MSolver::add_pin(const std::string& pin)
Expand Down Expand Up @@ -445,20 +359,11 @@ namespace mamba
// }
// }

Id match = pool_conda_matchspec(pool, ms.conda_build_form().c_str());

Id match = m_pool.matchspec2id(ms);
std::set<Id> matching_solvables;
const Channel& c = make_channel(ms.channel);

for (Id* wp = pool_whatprovides_ptr(pool, match); *wp; wp++)
{
if (!ms.channel.empty())
{
if (!channel_match(pool_id2solvable(pool, *wp), c))
{
continue;
}
}
matching_solvables.insert(*wp);
}

Expand Down
3 changes: 3 additions & 0 deletions libmambapy/libmambapy/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,9 @@ class Pool:
def __init__(self) -> None: ...
def create_whatprovides(self) -> None: ...
def id2pkginfo(self, id: int) -> typing.Optional[PackageInfo]: ...
@typing.overload
def matchspec2id(self, ms: MatchSpec) -> int: ...
@typing.overload
def matchspec2id(self, ms: str) -> int: ...
def select_solvables(self, id: int, sorted: bool = False) -> typing.List[int]: ...
def set_debuglevel(self) -> None: ...
Expand Down
Loading

0 comments on commit e8d6b3d

Please sign in to comment.