mirror of https://github.com/mamba-org/mamba.git
Use custom function to properly parse matchspec (#2433)
Make MPool::matchspec2id properly process channels
This commit is contained in:
parent
e5451c94f9
commit
0345b9d7f8
|
@ -8,6 +8,7 @@
|
|||
#define MAMBA_CORE_MATCH_SPEC
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
namespace mamba
|
||||
{
|
||||
class MatchSpec;
|
||||
|
||||
/**
|
||||
* Pool of solvable involved in resolving en environment.
|
||||
*
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
m_jobs->push_back(SOLVER_INSTALL | SOLVER_SOLVABLE_PROVIDES, job_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);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_channel_specific_job(ms, job_flag);
|
||||
}
|
||||
|
||||
continue;
|
||||
m_jobs->push_back(job_flag | SOLVER_SOLVABLE_PROVIDES, job_id);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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: ...
|
||||
|
|
|
@ -140,12 +140,22 @@ PYBIND11_MODULE(bindings, m)
|
|||
|
||||
py::add_ostream_redirect(m, "ostream_redirect");
|
||||
|
||||
py::class_<MatchSpec>(m, "MatchSpec")
|
||||
.def(py::init<>())
|
||||
.def(py::init<const std::string&>())
|
||||
.def("conda_build_form", &MatchSpec::conda_build_form);
|
||||
|
||||
py::class_<MPool>(m, "Pool")
|
||||
.def(py::init<>())
|
||||
.def("set_debuglevel", &MPool::set_debuglevel)
|
||||
.def("create_whatprovides", &MPool::create_whatprovides)
|
||||
.def("select_solvables", &MPool::select_solvables, py::arg("id"), py::arg("sorted") = false)
|
||||
.def("matchspec2id", &MPool::matchspec2id, py::arg("ms"))
|
||||
.def(
|
||||
"matchspec2id",
|
||||
[](MPool& self, std::string_view ms) { return self.matchspec2id({ ms }); },
|
||||
py::arg("ms")
|
||||
)
|
||||
.def("id2pkginfo", &MPool::id2pkginfo, py::arg("id"));
|
||||
|
||||
py::class_<MultiPackageCache>(m, "MultiPackageCache")
|
||||
|
@ -260,11 +270,6 @@ PYBIND11_MODULE(bindings, m)
|
|||
.def_readwrite("description", &MSolverProblem::description)
|
||||
.def("__str__", [](const MSolverProblem& self) { return self.description; });
|
||||
|
||||
py::class_<MatchSpec>(m, "MatchSpec")
|
||||
.def(py::init<>())
|
||||
.def(py::init<const std::string&>())
|
||||
.def("conda_build_form", &MatchSpec::conda_build_form);
|
||||
|
||||
using PbGraph = ProblemsGraph;
|
||||
auto pyPbGraph = py::class_<PbGraph>(m, "ProblemsGraph");
|
||||
|
||||
|
|
|
@ -44,11 +44,11 @@ update_self(const std::optional<std::string>& version)
|
|||
std::string matchspec = version ? fmt::format("micromamba={}", version.value())
|
||||
: fmt::format("micromamba>{}", umamba::version());
|
||||
|
||||
auto solvable_ids = pool.select_solvables(pool.matchspec2id(matchspec), true);
|
||||
auto solvable_ids = pool.select_solvables(pool.matchspec2id({ matchspec }), true);
|
||||
|
||||
if (solvable_ids.empty())
|
||||
{
|
||||
if (pool.select_solvables(pool.matchspec2id("micromamba")).empty())
|
||||
if (pool.select_solvables(pool.matchspec2id({ "micromamba" })).empty())
|
||||
{
|
||||
throw mamba::mamba_error(
|
||||
"No micromamba found in the loaded channels. Add 'conda-forge' to your config file.",
|
||||
|
|
Loading…
Reference in New Issue