Rename MPool into solver::libsolv::Database (#3180)

* Move only MPool

* Rename MPool > Database

* Move Database to solver::libsolv

* Add missing explicit

* Rename pool in function names

* Rename core/pool.hpp package_database_loader
This commit is contained in:
Antoine Prouvost 2024-02-08 10:41:11 -05:00 committed by GitHub
parent 67fd10a830
commit d20d176b86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 1039 additions and 957 deletions

View File

@ -183,9 +183,11 @@ set(
${LIBMAMBA_SOURCE_DIR}/solv-cpp/solvable.cpp
${LIBMAMBA_SOURCE_DIR}/solv-cpp/solver.cpp
${LIBMAMBA_SOURCE_DIR}/solv-cpp/transaction.cpp
# Solver interface
# Solver generic interface
${LIBMAMBA_SOURCE_DIR}/solver/helpers.cpp
${LIBMAMBA_SOURCE_DIR}/solver/problems_graph.cpp
# Solver libsolv implementation
${LIBMAMBA_SOURCE_DIR}/solver/libsolv/database.cpp
${LIBMAMBA_SOURCE_DIR}/solver/libsolv/helpers.cpp
${LIBMAMBA_SOURCE_DIR}/solver/libsolv/parameters.cpp
${LIBMAMBA_SOURCE_DIR}/solver/libsolv/repo_info.cpp
@ -212,6 +214,7 @@ set(
# Core API (low-level)
${LIBMAMBA_SOURCE_DIR}/core/singletons.cpp
${LIBMAMBA_SOURCE_DIR}/core/activation.cpp
${LIBMAMBA_SOURCE_DIR}/core/package_database_loader.cpp
${LIBMAMBA_SOURCE_DIR}/core/channel_context.cpp
${LIBMAMBA_SOURCE_DIR}/core/context.cpp
${LIBMAMBA_SOURCE_DIR}/core/download_progress_bar.cpp
@ -224,7 +227,6 @@ set(
${LIBMAMBA_SOURCE_DIR}/core/output.cpp
${LIBMAMBA_SOURCE_DIR}/core/package_handling.cpp
${LIBMAMBA_SOURCE_DIR}/core/package_cache.cpp
${LIBMAMBA_SOURCE_DIR}/core/pool.cpp
${LIBMAMBA_SOURCE_DIR}/core/prefix_data.cpp
${LIBMAMBA_SOURCE_DIR}/core/progress_bar.cpp
${LIBMAMBA_SOURCE_DIR}/core/progress_bar_impl.cpp
@ -313,10 +315,12 @@ set(
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/unresolved_channel.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/version.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/version_spec.hpp
# Solver Interface
# Solver generic interface
${LIBMAMBA_INCLUDE_DIR}/mamba/solver/problems_graph.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/solver/request.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/solver/solution.hpp
# Solver libsolv implementation
${LIBMAMBA_INCLUDE_DIR}/mamba/solver/libsolv/database.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/solver/libsolv/parameters.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/solver/libsolv/repo_info.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/solver/libsolv/solver.hpp
@ -341,6 +345,7 @@ set(
${LIBMAMBA_INCLUDE_DIR}/mamba/core/context.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/download_progress_bar.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/environments_manager.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/package_database_loader.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/error_handling.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/history.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/link.hpp
@ -351,7 +356,6 @@ set(
${LIBMAMBA_INCLUDE_DIR}/mamba/core/package_fetcher.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/package_handling.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/package_paths.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/pool.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/prefix_data.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/progress_bar.hpp
${LIBMAMBA_INCLUDE_DIR}/mamba/core/pinning.hpp

View File

@ -11,15 +11,18 @@
namespace mamba
{
namespace solver::libsolv
{
class Database;
}
class Context;
class ChannelContext;
class MPool;
class MultiPackageCache;
auto load_channels( //
Context& ctx,
ChannelContext& channel_context,
MPool& pool,
solver::libsolv::Database& pool,
MultiPackageCache& package_caches
) -> expected_t<void, mamba_aggregated_error>;
}

View File

@ -7,23 +7,33 @@
#ifndef MAMBA_API_INSTALL_HPP
#define MAMBA_API_INSTALL_HPP
#include <iosfwd>
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
#include <yaml-cpp/yaml.h>
#include "mamba/core/package_cache.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/fs/filesystem.hpp"
#include "mamba/solver/request.hpp"
#include "mamba/specs/package_info.hpp"
namespace mamba
{
class Context;
class ChannelContext;
class Configuration;
class PrefixData;
class MultiPackageCache;
namespace specs
{
class PackageInfo;
}
namespace solver::libsolv
{
class DataBase;
}
void install(Configuration& config);

View File

@ -13,6 +13,11 @@
namespace mamba
{
namespace solver::libsolv
{
class DataBase;
}
enum class QueryResultFormat
{
Json = 0,
@ -23,7 +28,7 @@ namespace mamba
};
[[nodiscard]] auto make_repoquery(
MPool& pool,
solver::libsolv::Database& pool,
QueryType type,
QueryResultFormat format,
const std::vector<std::string>& queries,

View File

@ -0,0 +1,39 @@
// Copyright (c) 2019, 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_CORE_PACKAGE_DATABASE_LOADER_HPP
#define MAMBA_CORE_PACKAGE_DATABASE_LOADER_HPP
#include "mamba/core/error_handling.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
#include "mamba/specs/channel.hpp"
namespace mamba
{
class Context;
class PrefixData;
class SubdirData;
namespace solver::libsolv
{
class Database;
}
void add_spdlog_logger_to_database(solver::libsolv::Database& db);
auto load_subdir_in_database( //
const Context& ctx,
solver::libsolv::Database& db,
const SubdirData& subdir
) -> expected_t<solver::libsolv::RepoInfo>;
auto load_installed_packages_in_database(
const Context& ctx,
solver::libsolv::Database& db,
const PrefixData& prefix
) -> solver::libsolv::RepoInfo;
}
#endif

View File

@ -1,278 +0,0 @@
// Copyright (c) 2019, 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_CORE_POOL_HPP
#define MAMBA_CORE_POOL_HPP
#include <functional>
#include <memory>
#include <optional>
#include "mamba/core/error_handling.hpp"
#include "mamba/solver/libsolv/parameters.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
#include "mamba/specs/channel.hpp"
#include "mamba/specs/package_info.hpp"
#include "mamba/util/loop_control.hpp"
namespace mamba
{
class Context;
class PrefixData;
class SubdirData;
namespace fs
{
class u8path;
}
namespace solv
{
class ObjPool;
}
namespace specs
{
class MatchSpec;
}
namespace solver::libsolv
{
class Solver;
class UnSolvable;
}
/**
* Pool of solvable involved in resolving en environment.
*
* The pool contains the solvable (packages) information required from the ``MSolver``.
* The pool can be reused by multiple solvers to solve differents requirements with the same
* ecosystem.
* Behaves like a ``std::shared_ptr``, meaning ressources are shared on copy.
*/
class MPool
{
public:
using logger_type = std::function<void(solver::libsolv::LogLevel, std::string_view)>;
MPool(specs::ChannelResolveParams channel_params);
~MPool();
[[nodiscard]] auto channel_params() const -> const specs::ChannelResolveParams&;
void set_logger(logger_type callback);
auto add_repo_from_repodata_json(
const fs::u8path& path,
std::string_view url,
solver::libsolv::PipAsPythonDependency add = solver::libsolv::PipAsPythonDependency::No,
solver::libsolv::UseOnlyTarBz2 only_tar = solver::libsolv::UseOnlyTarBz2::No,
solver::libsolv::RepodataParser parser = solver::libsolv::RepodataParser::Mamba
) -> expected_t<solver::libsolv::RepoInfo>;
auto add_repo_from_native_serialization(
const fs::u8path& path,
const solver::libsolv::RepodataOrigin& expected,
solver::libsolv::PipAsPythonDependency add = solver::libsolv::PipAsPythonDependency::No
) -> expected_t<solver::libsolv::RepoInfo>;
template <typename Iter>
auto add_repo_from_packages(
Iter first_package,
Iter last_package,
std::string_view name = "",
solver::libsolv::PipAsPythonDependency add = solver::libsolv::PipAsPythonDependency::No
) -> solver::libsolv::RepoInfo;
template <typename Range>
auto add_repo_from_packages(
const Range& packages,
std::string_view name = "",
solver::libsolv::PipAsPythonDependency add = solver::libsolv::PipAsPythonDependency::No
) -> solver::libsolv::RepoInfo;
auto native_serialize_repo(
const solver::libsolv::RepoInfo& repo,
const fs::u8path& path,
const solver::libsolv::RepodataOrigin& metadata
) -> expected_t<solver::libsolv::RepoInfo>;
[[nodiscard]] auto installed_repo() const -> std::optional<solver::libsolv::RepoInfo>;
void set_installed_repo(solver::libsolv::RepoInfo repo);
void
set_repo_priority(solver::libsolv::RepoInfo repo, solver::libsolv::Priorities priorities);
void remove_repo(solver::libsolv::RepoInfo repo);
template <typename Func>
void for_each_package_in_repo(solver::libsolv::RepoInfo repo, Func&&) const;
template <typename Func>
void for_each_package_matching(const specs::MatchSpec& ms, Func&&);
template <typename Func>
void for_each_package_depending_on(const specs::MatchSpec& ms, Func&&);
/** A wrapper struct to fine-grain controll who can access the raw repr of the Pool. */
class Impl
{
[[nodiscard]] static auto get(MPool& pool) -> solv::ObjPool&;
[[nodiscard]] static auto get(const MPool& pool) -> const solv::ObjPool&;
friend class solver::libsolv::Solver;
friend class solver::libsolv::UnSolvable;
};
private:
struct MPoolData;
/**
* Make MPool behave like a shared_ptr (with move and copy).
*
* The pool is passed to the ``MSolver`` for its lifetime but the pool can legitimely
* be reused with different solvers (in fact it is in ``conda-forge``'s ``regro-bot``
* and ``boa``).
* An alternative considered was to make ``MPool`` a move-only type, moving it in and out
* of ``MSolver`` (effectively borrowing).
* It was decided to make ``MPool`` share ressources for the following reasons.
* - Rvalue semantics would be unexpected in Python (and breaking ``conda-forge``);
* - Facilitate (potential) future investigation of parallel solves.
*/
std::shared_ptr<MPoolData> m_data;
friend class Impl;
auto pool() -> solv::ObjPool&;
[[nodiscard]] auto pool() const -> const solv::ObjPool&;
auto add_repo_from_packages_impl_pre(std::string_view name) -> solver::libsolv::RepoInfo;
void add_repo_from_packages_impl_loop(
const solver::libsolv::RepoInfo& repo,
const specs::PackageInfo& pkg
);
void add_repo_from_packages_impl_post(
const solver::libsolv::RepoInfo& repo,
solver::libsolv::PipAsPythonDependency add
);
enum class PackageId : int;
[[nodiscard]] auto package_id_to_package_info(PackageId id) const -> specs::PackageInfo;
[[nodiscard]] auto packages_in_repo(solver::libsolv::RepoInfo repo) const
-> std::vector<PackageId>;
[[nodiscard]] auto packages_matching_ids(const specs::MatchSpec& ms)
-> std::vector<PackageId>;
[[nodiscard]] auto packages_depending_on_ids(const specs::MatchSpec& ms)
-> std::vector<PackageId>;
};
// TODO machinery functions in separate files
void add_spdlog_logger_to_pool(MPool& pool);
auto load_subdir_in_pool(const Context& ctx, MPool& pool, const SubdirData& subdir)
-> expected_t<solver::libsolv::RepoInfo>;
auto load_installed_packages_in_pool(const Context& ctx, MPool& pool, const PrefixData& prefix)
-> solver::libsolv::RepoInfo;
/********************
* Implementation *
********************/
template <typename Iter>
auto MPool::add_repo_from_packages(
Iter first_package,
Iter last_package,
std::string_view name,
solver::libsolv::PipAsPythonDependency add
) -> solver::libsolv::RepoInfo
{
auto repo = add_repo_from_packages_impl_pre(name);
for (; first_package != last_package; ++first_package)
{
add_repo_from_packages_impl_loop(repo, *first_package);
}
add_repo_from_packages_impl_post(repo, add);
return repo;
}
template <typename Range>
auto MPool::add_repo_from_packages(
const Range& packages,
std::string_view name,
solver::libsolv::PipAsPythonDependency add
) -> solver::libsolv::RepoInfo
{
return add_repo_from_packages(packages.begin(), packages.end(), name, add);
}
// TODO(C++20): Use ranges::transform
template <typename Func>
void MPool::for_each_package_in_repo(solver::libsolv::RepoInfo repo, Func&& func) const
{
for (auto id : packages_in_repo(repo))
{
if constexpr (std::is_same_v<decltype(func(package_id_to_package_info(id))), util::LoopControl>)
{
if (func(package_id_to_package_info(id)) == util::LoopControl::Break)
{
break;
}
}
else
{
func(package_id_to_package_info(id));
}
}
}
// TODO(C++20): Use ranges::transform
template <typename Func>
void MPool::for_each_package_matching(const specs::MatchSpec& ms, Func&& func)
{
for (auto id : packages_matching_ids(ms))
{
if constexpr (std::is_same_v<decltype(func(package_id_to_package_info(id))), util::LoopControl>)
{
if (func(package_id_to_package_info(id)) == util::LoopControl::Break)
{
break;
}
}
else
{
func(package_id_to_package_info(id));
}
}
}
// TODO(C++20): Use ranges::transform
template <typename Func>
void MPool::for_each_package_depending_on(const specs::MatchSpec& ms, Func&& func)
{
for (auto id : packages_depending_on_ids(ms))
{
if constexpr (std::is_same_v<decltype(func(package_id_to_package_info(id))), util::LoopControl>)
{
if (func(package_id_to_package_info(id)) == util::LoopControl::Break)
{
break;
}
}
else
{
func(package_id_to_package_info(id));
}
}
}
}
#endif

View File

@ -14,12 +14,16 @@
#include <vector>
#include "mamba/core/context.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/specs/package_info.hpp"
#include "mamba/util/graph.hpp"
namespace mamba
{
namespace solver::libsolv
{
class Database;
}
enum class QueryType
{
Search,
@ -88,12 +92,14 @@ namespace mamba
{
public:
[[nodiscard]] static auto find(MPool& pool, const std::vector<std::string>& queries)
using Database = solver::libsolv::Database;
[[nodiscard]] static auto find(Database& db, const std::vector<std::string>& queries)
-> QueryResult;
[[nodiscard]] static auto whoneeds(MPool& pool, std::string query, bool tree) -> QueryResult;
[[nodiscard]] static auto whoneeds(Database& db, std::string query, bool tree) -> QueryResult;
[[nodiscard]] static auto depends(MPool& pool, std::string query, bool tree) -> QueryResult;
[[nodiscard]] static auto depends(Database& db, std::string query, bool tree) -> QueryResult;
};
/********************

View File

@ -24,7 +24,7 @@ namespace mamba
{
class Channel;
}
class MPool;
class Context;
class ChannelContext;
class DownloadMonitor;

View File

@ -13,10 +13,10 @@
#include "mamba/api/install.hpp"
#include "mamba/core/package_cache.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/core/prefix_data.hpp"
#include "mamba/core/transaction_context.hpp"
#include "mamba/fs/filesystem.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/solver/solution.hpp"
#include "mamba/specs/match_spec.hpp"
#include "mamba/specs/package_info.hpp"
@ -37,7 +37,7 @@ namespace mamba
MTransaction(
const Context& ctx,
MPool& pool,
solver::libsolv::Database& db,
std::vector<specs::PackageInfo> pkgs_to_remove,
std::vector<specs::PackageInfo> pkgs_to_install,
MultiPackageCache& caches
@ -45,7 +45,7 @@ namespace mamba
MTransaction(
const Context& ctx,
MPool& pool,
solver::libsolv::Database& db,
const solver::Request& request,
solver::Solution solution,
MultiPackageCache& caches
@ -54,7 +54,7 @@ namespace mamba
// Only use if the packages have been solved previously already.
MTransaction(
const Context& ctx,
MPool& pool,
solver::libsolv::Database& db,
std::vector<specs::PackageInfo> packages,
MultiPackageCache& caches
);
@ -93,7 +93,7 @@ namespace mamba
MTransaction create_explicit_transaction_from_urls(
const Context& ctx,
MPool& pool,
solver::libsolv::Database& db,
const std::vector<std::string>& urls,
MultiPackageCache& package_caches,
std::vector<detail::other_pkg_mgr_spec>& other_specs
@ -101,7 +101,7 @@ namespace mamba
MTransaction create_explicit_transaction_from_lockfile(
const Context& ctx,
MPool& pool,
solver::libsolv::Database& db,
const fs::u8path& env_lockfile_path,
const std::vector<std::string>& categories,
MultiPackageCache& package_caches,

View File

@ -0,0 +1,252 @@
// 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_SOLVER_LIBSOLV_DATABASE_HPP
#define MAMBA_SOLVER_LIBSOLV_DATABASE_HPP
#include <functional>
#include <memory>
#include <optional>
#include <string_view>
#include "mamba/core/error_handling.hpp"
#include "mamba/solver/libsolv/parameters.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
#include "mamba/specs/channel.hpp"
#include "mamba/specs/package_info.hpp"
#include "mamba/util/loop_control.hpp"
namespace mamba
{
namespace fs
{
class u8path;
}
namespace solv
{
class ObjPool;
}
namespace specs
{
class MatchSpec;
}
}
namespace mamba::solver::libsolv
{
class Solver;
class UnSolvable;
/**
* Database of solvable involved in resolving en environment.
*
* The database contains the solvable (packages) information required from the @ref Solver.
* The database can be reused by multiple solvers to solve differents requirements with the
* same ecosystem.
*/
class Database
{
public:
using logger_type = std::function<void(LogLevel, std::string_view)>;
explicit Database(specs::ChannelResolveParams channel_params);
Database(const Database&) = delete;
Database(Database&&);
~Database();
auto operator=(const Database&) -> Database& = delete;
auto operator=(Database&&) -> Database&;
[[nodiscard]] auto channel_params() const -> const specs::ChannelResolveParams&;
void set_logger(logger_type callback);
auto add_repo_from_repodata_json(
const fs::u8path& path,
std::string_view url,
PipAsPythonDependency add = PipAsPythonDependency::No,
UseOnlyTarBz2 only_tar = UseOnlyTarBz2::No,
RepodataParser parser = RepodataParser::Mamba
) -> expected_t<RepoInfo>;
auto add_repo_from_native_serialization(
const fs::u8path& path,
const RepodataOrigin& expected,
PipAsPythonDependency add = PipAsPythonDependency::No
) -> expected_t<RepoInfo>;
template <typename Iter>
auto add_repo_from_packages(
Iter first_package,
Iter last_package,
std::string_view name = "",
PipAsPythonDependency add = PipAsPythonDependency::No
) -> RepoInfo;
template <typename Range>
auto add_repo_from_packages(
const Range& packages,
std::string_view name = "",
PipAsPythonDependency add = PipAsPythonDependency::No
) -> RepoInfo;
auto
native_serialize_repo(const RepoInfo& repo, const fs::u8path& path, const RepodataOrigin& metadata)
-> expected_t<RepoInfo>;
[[nodiscard]] auto installed_repo() const -> std::optional<RepoInfo>;
void set_installed_repo(RepoInfo repo);
void set_repo_priority(RepoInfo repo, Priorities priorities);
void remove_repo(RepoInfo repo);
template <typename Func>
void for_each_package_in_repo(RepoInfo repo, Func&&) const;
template <typename Func>
void for_each_package_matching(const specs::MatchSpec& ms, Func&&);
template <typename Func>
void for_each_package_depending_on(const specs::MatchSpec& ms, Func&&);
/**
* An access control wrapper.
*
* This struct is to control who can access the underlying private representation
* of the ObjPool without giving them full friend access.
*/
class Impl
{
[[nodiscard]] static auto get(Database& pool) -> solv::ObjPool&;
[[nodiscard]] static auto get(const Database& pool) -> const solv::ObjPool&;
friend class Solver;
friend class UnSolvable;
};
private:
struct DatabaseImpl;
std::unique_ptr<DatabaseImpl> m_data;
friend class Impl;
auto pool() -> solv::ObjPool&;
[[nodiscard]] auto pool() const -> const solv::ObjPool&;
auto add_repo_from_packages_impl_pre(std::string_view name) -> RepoInfo;
void add_repo_from_packages_impl_loop(const RepoInfo& repo, const specs::PackageInfo& pkg);
void add_repo_from_packages_impl_post(const RepoInfo& repo, PipAsPythonDependency add);
enum class PackageId : int;
[[nodiscard]] auto package_id_to_package_info(PackageId id) const -> specs::PackageInfo;
[[nodiscard]] auto packages_in_repo(RepoInfo repo) const -> std::vector<PackageId>;
[[nodiscard]] auto packages_matching_ids(const specs::MatchSpec& ms)
-> std::vector<PackageId>;
[[nodiscard]] auto packages_depending_on_ids(const specs::MatchSpec& ms)
-> std::vector<PackageId>;
};
/********************
* Implementation *
********************/
template <typename Iter>
auto Database::add_repo_from_packages(
Iter first_package,
Iter last_package,
std::string_view name,
PipAsPythonDependency add
) -> RepoInfo
{
auto repo = add_repo_from_packages_impl_pre(name);
for (; first_package != last_package; ++first_package)
{
add_repo_from_packages_impl_loop(repo, *first_package);
}
add_repo_from_packages_impl_post(repo, add);
return repo;
}
template <typename Range>
auto
Database::add_repo_from_packages(const Range& packages, std::string_view name, PipAsPythonDependency add)
-> RepoInfo
{
return add_repo_from_packages(packages.begin(), packages.end(), name, add);
}
// TODO(C++20): Use ranges::transform
template <typename Func>
void Database::for_each_package_in_repo(RepoInfo repo, Func&& func) const
{
for (auto id : packages_in_repo(repo))
{
if constexpr (std::is_same_v<decltype(func(package_id_to_package_info(id))), util::LoopControl>)
{
if (func(package_id_to_package_info(id)) == util::LoopControl::Break)
{
break;
}
}
else
{
func(package_id_to_package_info(id));
}
}
}
// TODO(C++20): Use ranges::transform
template <typename Func>
void Database::for_each_package_matching(const specs::MatchSpec& ms, Func&& func)
{
for (auto id : packages_matching_ids(ms))
{
if constexpr (std::is_same_v<decltype(func(package_id_to_package_info(id))), util::LoopControl>)
{
if (func(package_id_to_package_info(id)) == util::LoopControl::Break)
{
break;
}
}
else
{
func(package_id_to_package_info(id));
}
}
}
// TODO(C++20): Use ranges::transform
template <typename Func>
void Database::for_each_package_depending_on(const specs::MatchSpec& ms, Func&& func)
{
for (auto id : packages_depending_on_ids(ms))
{
if constexpr (std::is_same_v<decltype(func(package_id_to_package_info(id))), util::LoopControl>)
{
if (func(package_id_to_package_info(id)) == util::LoopControl::Break)
{
break;
}
}
else
{
func(package_id_to_package_info(id));
}
}
}
}
#endif

View File

@ -17,24 +17,21 @@ extern "C"
using Repo = struct s_Repo;
}
namespace mamba
{
class MPool;
class MTransaction;
}
namespace mamba::solver::libsolv
{
class Database;
/**
* A libsolv repository descriptor.
*
* In libsolv, most of the data is help in the Pool, and repo are tightly coupled with them.
* In libsolv, most of the data is help in the @ref Database, and repo are tightly coupled
* with them.
* This repository class is a lightwight description of a repository returned when creating
* a new repository in the Pool.
* Some modifications to the repo are possible throught the Pool.
* @see MPool::add_repo_from_repodata_json
* @see MPool::add_repo_from_packages
* @see MPool::remove_repo
* a new repository in the @ref Database.
* Some modifications to the repo are possible throught the @ref Database.
* @see Database::add_repo_from_repodata_json
* @see Database::add_repo_from_packages
* @see Database::remove_repo
*/
class RepoInfo
{
@ -61,8 +58,7 @@ namespace mamba::solver::libsolv
explicit RepoInfo(::Repo* repo);
friend class ::mamba::MPool;
friend class ::mamba::MTransaction; // As long as MTransaction leaks libsolv impl
friend class Database;
friend auto operator==(RepoInfo lhs, RepoInfo rhs) -> bool;
};

View File

@ -14,18 +14,20 @@
namespace mamba::solver::libsolv
{
class Database;
class Solver
{
public:
using Outcome = std::variant<Solution, UnSolvable>;
[[nodiscard]] auto solve(MPool& pool, Request&& request) -> expected_t<Outcome>;
[[nodiscard]] auto solve(MPool& pool, const Request& request) -> expected_t<Outcome>;
[[nodiscard]] auto solve(Database& pool, Request&& request) -> expected_t<Outcome>;
[[nodiscard]] auto solve(Database& pool, const Request& request) -> expected_t<Outcome>;
private:
auto solve_impl(MPool& pool, const Request& request) -> expected_t<Outcome>;
auto solve_impl(Database& pool, const Request& request) -> expected_t<Outcome>;
};
}
#endif

View File

@ -16,7 +16,6 @@
namespace mamba
{
class MPool;
class Palette;
namespace solv
@ -28,6 +27,7 @@ namespace mamba
namespace mamba::solver::libsolv
{
class Solver;
class Database;
class UnSolvable
{
@ -39,21 +39,22 @@ namespace mamba::solver::libsolv
auto operator=(UnSolvable&&) -> UnSolvable&;
[[nodiscard]] auto problems(MPool& pool) const -> std::vector<std::string>;
[[nodiscard]] auto problems(Database& pool) const -> std::vector<std::string>;
[[nodiscard]] auto problems_to_str(MPool& pool) const -> std::string;
[[nodiscard]] auto problems_to_str(Database& pool) const -> std::string;
[[nodiscard]] auto all_problems_to_str(MPool& pool) const -> std::string;
[[nodiscard]] auto all_problems_to_str(Database& pool) const -> std::string;
[[nodiscard]] auto problems_graph(const MPool& pool) const -> ProblemsGraph;
[[nodiscard]] auto problems_graph(const Database& pool) const -> ProblemsGraph;
auto explain_problems_to( //
MPool& pool,
Database& pool,
std::ostream& out,
const Palette& palette
) const -> std::ostream&;
[[nodiscard]] auto explain_problems(MPool& pool, const Palette& palette) const -> std::string;
[[nodiscard]] auto explain_problems(Database& pool, const Palette& palette) const
-> std::string;
private:

View File

@ -24,13 +24,12 @@
#include "mamba/util/flat_set.hpp"
#include "mamba/util/graph.hpp"
namespace mamba
{
class MPool;
}
namespace mamba::solver
{
namespace libsolv
{
class Database;
}
template <typename T>
class conflict_map : private std::unordered_map<T, util::flat_set<T>>

View File

@ -8,9 +8,10 @@
#include "mamba/core/channel_context.hpp"
#include "mamba/core/download_progress_bar.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/core/package_database_loader.hpp"
#include "mamba/core/prefix_data.hpp"
#include "mamba/core/subdirdata.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
#include "mamba/specs/package_info.hpp"
@ -21,7 +22,7 @@ namespace mamba
auto create_repo_from_pkgs_dir(
const Context& ctx,
ChannelContext& channel_context,
MPool& pool,
solver::libsolv::Database& pool,
const fs::u8path& pkgs_dir
) -> solver::libsolv::RepoInfo
{
@ -45,7 +46,7 @@ namespace mamba
}
prefix_data.load_single_record(repodata_record_json);
}
return load_installed_packages_in_pool(ctx, pool, prefix_data);
return load_installed_packages_in_database(ctx, pool, prefix_data);
}
void create_subdirs(
@ -112,7 +113,7 @@ namespace mamba
auto load_channels_impl(
Context& ctx,
ChannelContext& channel_context,
MPool& pool,
solver::libsolv::Database& pool,
MultiPackageCache& package_caches,
bool is_retry
) -> expected_t<void, mamba_aggregated_error>
@ -231,7 +232,7 @@ namespace mamba
continue;
}
load_subdir_in_pool(ctx, pool, subdir)
load_subdir_in_database(ctx, pool, subdir)
.transform([&](solver::libsolv::RepoInfo&& repo)
{ pool.set_repo_priority(repo, priorities[i]); })
.or_else(
@ -276,9 +277,12 @@ namespace mamba
}
}
auto
load_channels(Context& ctx, ChannelContext& channel_context, MPool& pool, MultiPackageCache& package_caches)
-> expected_t<void, mamba_aggregated_error>
auto load_channels(
Context& ctx,
ChannelContext& channel_context,
solver::libsolv::Database& pool,
MultiPackageCache& package_caches
) -> expected_t<void, mamba_aggregated_error>
{
return load_channels_impl(ctx, channel_context, pool, package_caches, false);
}

View File

@ -22,6 +22,7 @@
#include "mamba/core/environments_manager.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/package_cache.hpp"
#include "mamba/core/package_database_loader.hpp"
#include "mamba/core/pinning.hpp"
#include "mamba/core/transaction.hpp"
#include "mamba/core/virtual_packages.hpp"
@ -530,8 +531,8 @@ namespace mamba
LOG_WARNING << "No 'channels' specified";
}
MPool pool{ channel_context.params() };
add_spdlog_logger_to_pool(pool);
solver::libsolv::Database pool{ channel_context.params() };
add_spdlog_logger_to_database(pool);
// functions implied in 'and_then' coding-styles must return the same type
// which limits this syntax
/*auto exp_prefix_data = load_channels(pool, package_caches)
@ -552,7 +553,7 @@ namespace mamba
}
PrefixData& prefix_data = exp_prefix_data.value();
load_installed_packages_in_pool(ctx, pool, prefix_data);
load_installed_packages_in_database(ctx, pool, prefix_data);
auto request = create_install_request(prefix_data, specs, freeze_installed);
@ -674,7 +675,7 @@ namespace mamba
namespace
{
// TransactionFunc: (MPool& pool, MultiPackageCache& package_caches) -> MTransaction
// TransactionFunc: (Database& pool, MultiPackageCache& package_caches) -> MTransaction
template <typename TransactionFunc>
void install_explicit_with_transaction(
Context& ctx,
@ -684,8 +685,8 @@ namespace mamba
bool remove_prefix_on_failure
)
{
MPool pool{ channel_context.params() };
add_spdlog_logger_to_pool(pool);
solver::libsolv::Database db{ channel_context.params() };
add_spdlog_logger_to_database(db);
auto exp_prefix_data = PrefixData::create(ctx.prefix_params.target_prefix, channel_context);
if (!exp_prefix_data)
@ -697,12 +698,12 @@ namespace mamba
MultiPackageCache pkg_caches(ctx.pkgs_dirs, ctx.validation_params);
load_installed_packages_in_pool(ctx, pool, prefix_data);
load_installed_packages_in_database(ctx, db, prefix_data);
std::vector<detail::other_pkg_mgr_spec> others;
// Note that the Transaction will gather the Solvables,
// so they must have been ready in the pool before this line
auto transaction = create_transaction(pool, pkg_caches, others);
auto transaction = create_transaction(db, pkg_caches, others);
std::vector<LockFile> lock_pkgs;
@ -754,8 +755,8 @@ namespace mamba
install_explicit_with_transaction(
ctx,
channel_context,
[&](auto& pool, auto& pkg_caches, auto& others)
{ return create_explicit_transaction_from_urls(ctx, pool, specs, pkg_caches, others); },
[&](auto& db, auto& pkg_caches, auto& others)
{ return create_explicit_transaction_from_urls(ctx, db, specs, pkg_caches, others); },
create_env,
remove_prefix_on_failure
);
@ -802,11 +803,11 @@ namespace mamba
install_explicit_with_transaction(
ctx,
channel_context,
[&](auto& pool, auto& pkg_caches, auto& others)
[&](auto& db, auto& pkg_caches, auto& others)
{
return create_explicit_transaction_from_lockfile(
ctx,
pool,
db,
file,
categories,
pkg_caches,

View File

@ -9,7 +9,7 @@
#include "mamba/core/channel_context.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/package_cache.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/core/package_database_loader.hpp"
#include "mamba/core/prefix_data.hpp"
#include "mamba/core/transaction.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
@ -127,9 +127,9 @@ namespace mamba
}
PrefixData& prefix_data = exp_prefix_data.value();
MPool pool{ channel_context.params() };
add_spdlog_logger_to_pool(pool);
load_installed_packages_in_pool(ctx, pool, prefix_data);
solver::libsolv::Database pool{ channel_context.params() };
add_spdlog_logger_to_database(pool);
load_installed_packages_in_database(ctx, pool, prefix_data);
const fs::u8path pkgs_dirs(ctx.prefix_params.root_prefix / "pkgs");
MultiPackageCache package_caches({ pkgs_dirs }, ctx.validation_params);

View File

@ -11,7 +11,9 @@
#include "mamba/api/repoquery.hpp"
#include "mamba/core/channel_context.hpp"
#include "mamba/core/package_cache.hpp"
#include "mamba/core/package_database_loader.hpp"
#include "mamba/core/prefix_data.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
#include "mamba/util/string.hpp"
@ -28,8 +30,8 @@ namespace mamba
config.load();
auto channel_context = ChannelContext::make_conda_compatible(ctx);
MPool pool{ channel_context.params() };
add_spdlog_logger_to_pool(pool);
solver::libsolv::Database db{ channel_context.params() };
add_spdlog_logger_to_database(db);
// bool installed = (type == QueryType::kDepends) || (type == QueryType::kWhoneeds);
MultiPackageCache package_caches(ctx.pkgs_dirs, ctx.validation_params);
@ -50,7 +52,7 @@ namespace mamba
}
PrefixData& prefix_data = exp_prefix_data.value();
load_installed_packages_in_pool(ctx, pool, prefix_data);
load_installed_packages_in_database(ctx, db, prefix_data);
if (format != QueryResultFormat::Json)
{
@ -65,18 +67,18 @@ namespace mamba
{
Console::stream() << "Getting repodata from channels..." << std::endl;
}
auto exp_load = load_channels(ctx, channel_context, pool, package_caches);
auto exp_load = load_channels(ctx, channel_context, db, package_caches);
if (!exp_load)
{
throw std::runtime_error(exp_load.error().what());
}
}
return pool;
return db;
}
}
auto make_repoquery(
MPool& pool,
solver::libsolv::Database& db,
QueryType type,
QueryResultFormat format,
const std::vector<std::string>& queries,
@ -87,7 +89,7 @@ namespace mamba
{
if (type == QueryType::Search)
{
auto res = Query::find(pool, queries);
auto res = Query::find(db, queries);
switch (format)
{
case QueryResultFormat::Json:
@ -108,7 +110,7 @@ namespace mamba
throw std::invalid_argument("Only one query supported for 'depends'.");
}
auto res = Query::depends(
pool,
db,
queries.front(),
/* tree= */ format == QueryResultFormat::Tree
|| format == QueryResultFormat::RecursiveTable
@ -135,7 +137,7 @@ namespace mamba
throw std::invalid_argument("Only one query supported for 'whoneeds'.");
}
auto res = Query::whoneeds(
pool,
db,
queries.front(),
/* tree= */ format == QueryResultFormat::Tree
|| format == QueryResultFormat::RecursiveTable
@ -177,9 +179,9 @@ namespace mamba
)
{
auto& ctx = config.context();
auto pool = repoquery_init(ctx, config, format, use_local);
auto db = repoquery_init(ctx, config, format, use_local);
return make_repoquery(
pool,
db,
type,
format,
queries,

View File

@ -10,9 +10,11 @@
#include "mamba/api/update.hpp"
#include "mamba/core/channel_context.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/package_database_loader.hpp"
#include "mamba/core/pinning.hpp"
#include "mamba/core/transaction.hpp"
#include "mamba/core/virtual_packages.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/solver/libsolv/solver.hpp"
#include "mamba/solver/request.hpp"
@ -106,12 +108,12 @@ namespace mamba
}
}
MPool pool{ channel_context.params() };
add_spdlog_logger_to_pool(pool);
solver::libsolv::Database db{ channel_context.params() };
add_spdlog_logger_to_database(db);
MultiPackageCache package_caches(ctx.pkgs_dirs, ctx.validation_params);
auto exp_loaded = load_channels(ctx, channel_context, pool, package_caches);
auto exp_loaded = load_channels(ctx, channel_context, db, package_caches);
if (!exp_loaded)
{
throw std::runtime_error(exp_loaded.error().what());
@ -131,7 +133,7 @@ namespace mamba
prefix_pkgs.push_back(it.first);
}
load_installed_packages_in_pool(ctx, pool, prefix_data);
load_installed_packages_in_database(ctx, db, prefix_data);
auto request = create_update_request(
prefix_data,
@ -157,13 +159,13 @@ namespace mamba
// Console stream prints on destrucion
}
auto outcome = solver::libsolv::Solver().solve(pool, request).value();
auto outcome = solver::libsolv::Solver().solve(db, request).value();
if (auto* unsolvable = std::get_if<solver::libsolv::UnSolvable>(&outcome))
{
if (ctx.output_params.json)
{
Console::instance().json_write({ { "success", false },
{ "solver_problems", unsolvable->problems(pool) } });
{ "solver_problems", unsolvable->problems(db) } });
}
throw mamba_error(
"Could not solve for environment specs",
@ -174,7 +176,7 @@ namespace mamba
Console::instance().json_write({ { "success", true } });
auto transaction = MTransaction(
ctx,
pool,
db,
request,
std::get<solver::Solution>(outcome),
package_caches

View File

@ -0,0 +1,149 @@
// Copyright (c) 2019, 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.
#include <string_view>
#include <fmt/format.h>
#include <solv/evr.h>
#include <solv/selection.h>
#include <solv/solver.h>
#include <spdlog/spdlog.h>
#include "mamba/core/channel_context.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/package_database_loader.hpp"
#include "mamba/core/prefix_data.hpp"
#include "mamba/core/subdirdata.hpp"
#include "mamba/core/virtual_packages.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
#include "mamba/util/build.hpp"
#include "mamba/util/string.hpp"
#include "solver/libsolv/helpers.hpp"
namespace mamba
{
void add_spdlog_logger_to_database(solver::libsolv::Database& db)
{
db.set_logger(
[logger = spdlog::get("libsolv")](solver::libsolv::LogLevel level, std::string_view msg)
{
switch (level)
{
case (solver::libsolv::LogLevel::Fatal):
logger->critical(msg);
break;
case (solver::libsolv::LogLevel::Error):
logger->error(msg);
break;
case (solver::libsolv::LogLevel::Warning):
logger->warn(msg);
break;
case (solver::libsolv::LogLevel::Debug):
logger->debug(msg);
break;
}
}
);
}
auto
load_subdir_in_database(const Context& ctx, solver::libsolv::Database& db, const SubdirData& subdir)
-> expected_t<solver::libsolv::RepoInfo>
{
const auto expected_cache_origin = solver::libsolv::RepodataOrigin{
/* .url= */ util::rsplit(subdir.metadata().url(), "/", 1).front(),
/* .etag= */ subdir.metadata().etag(),
/* .mod= */ subdir.metadata().last_modified(),
};
const auto add_pip = static_cast<solver::libsolv::PipAsPythonDependency>(
ctx.add_pip_as_python_dependency
);
const auto json_parser = ctx.experimental_repodata_parsing
? solver::libsolv::RepodataParser::Mamba
: solver::libsolv::RepodataParser::Libsolv;
// Solv files are too slow on Windows.
if (!util::on_win)
{
auto maybe_repo = subdir.valid_solv_cache().and_then(
[&](fs::u8path&& solv_file) {
return db.add_repo_from_native_serialization(
solv_file,
expected_cache_origin,
add_pip
);
}
);
if (maybe_repo)
{
return maybe_repo;
}
}
return subdir.valid_json_cache()
.and_then(
[&](fs::u8path&& repodata_json)
{
LOG_INFO << "Trying to load repo from json file " << repodata_json;
return db.add_repo_from_repodata_json(
repodata_json,
util::rsplit(subdir.metadata().url(), "/", 1).front(),
add_pip,
static_cast<solver::libsolv::UseOnlyTarBz2>(ctx.use_only_tar_bz2),
json_parser
);
}
)
.transform(
[&](solver::libsolv::RepoInfo&& repo) -> solver::libsolv::RepoInfo
{
if (!util::on_win)
{
db.native_serialize_repo(repo, subdir.writable_solv_cache(), expected_cache_origin)
.or_else(
[&](const auto& err)
{
LOG_WARNING << R"(Fail to write native serialization to file ")"
<< subdir.writable_solv_cache() << R"(" for repo ")"
<< subdir.name() << ": " << err.what();
;
}
);
}
return std::move(repo);
}
);
}
auto load_installed_packages_in_database(
const Context& ctx,
solver::libsolv::Database& db,
const PrefixData& prefix
) -> solver::libsolv::RepoInfo
{
// TODO(C++20): We could do a PrefixData range that returns packages without storing thems.
auto pkgs = prefix.sorted_records();
// TODO(C++20): We only need a range that concatenate both
for (auto&& pkg : get_virtual_packages(ctx))
{
pkgs.push_back(std::move(pkg));
}
// Not adding Pip dependency since it might needlessly make the installed/active environment
// broken if pip is not already installed (debatable).
auto repo = db.add_repo_from_packages(
pkgs,
"installed",
solver::libsolv::PipAsPythonDependency::No
);
db.set_installed_repo(repo);
return repo;
}
}

View File

@ -1,464 +0,0 @@
// Copyright (c) 2019, 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.
#include <exception>
#include <iostream>
#include <limits>
#include <string_view>
#include <fmt/format.h>
#include <solv/evr.h>
#include <solv/selection.h>
#include <solv/solver.h>
#include <spdlog/spdlog.h>
#include "mamba/core/channel_context.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/core/prefix_data.hpp"
#include "mamba/core/subdirdata.hpp"
#include "mamba/core/virtual_packages.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
#include "mamba/specs/match_spec.hpp"
#include "mamba/util/build.hpp"
#include "mamba/util/random.hpp"
#include "mamba/util/string.hpp"
#include "solv-cpp/pool.hpp"
#include "solv-cpp/queue.hpp"
#include "solver/libsolv/helpers.hpp"
namespace mamba
{
struct MPool::MPoolData
{
MPoolData(specs::ChannelResolveParams p_channel_params)
: channel_params(std::move(p_channel_params))
{
}
specs::ChannelResolveParams channel_params;
solv::ObjPool pool = {};
};
MPool::MPool(specs::ChannelResolveParams channel_params)
: m_data(std::make_unique<MPoolData>(std::move(channel_params)))
{
pool().set_disttype(DISTTYPE_CONDA);
// Ensure that debug logging never goes to stdout as to not interfere json output
pool().raw()->debugmask |= SOLV_DEBUG_TO_STDERR;
::pool_setdebuglevel(pool().raw(), -1); // Off
}
MPool::~MPool() = default;
auto MPool::pool() -> solv::ObjPool&
{
return m_data->pool;
}
auto MPool::pool() const -> const solv::ObjPool&
{
return m_data->pool;
}
auto MPool::Impl::get(MPool& pool) -> solv::ObjPool&
{
return pool.pool();
}
auto MPool::Impl::get(const MPool& pool) -> const solv::ObjPool&
{
return pool.pool();
}
auto MPool::channel_params() const -> const specs::ChannelResolveParams&
{
return m_data->channel_params;
}
namespace
{
auto libsolv_to_log_level(int type) -> solver::libsolv::LogLevel
{
if (type & SOLV_FATAL)
{
return solver::libsolv::LogLevel::Fatal;
}
if (type & SOLV_ERROR)
{
return solver::libsolv::LogLevel::Error;
}
if (type & SOLV_WARN)
{
return solver::libsolv::LogLevel::Warning;
}
return solver::libsolv::LogLevel::Debug;
}
}
void MPool::set_logger(logger_type callback)
{
::pool_setdebuglevel(pool().raw(), std::numeric_limits<int>::max()); // All
pool().set_debug_callback(
[logger = std::move(callback)](::Pool*, int type, std::string_view msg) noexcept
{
try
{
logger(libsolv_to_log_level(type), msg);
}
catch (std::exception const& e)
{
std::cerr << "Developer error: error in libsolv logging function: \n"
<< e.what();
}
}
);
}
auto MPool::add_repo_from_repodata_json(
const fs::u8path& path,
std::string_view url,
solver::libsolv::PipAsPythonDependency add,
solver::libsolv::UseOnlyTarBz2 only_tar,
solver::libsolv::RepodataParser parser
) -> expected_t<solver::libsolv::RepoInfo>
{
const auto use_only_tar_bz2 = static_cast<bool>(only_tar);
if (!fs::exists(path))
{
return make_unexpected(
fmt::format(R"(File "{}" does not exist)", path),
mamba_error_code::repodata_not_loaded
);
}
auto repo = pool().add_repo(url).second;
repo.set_url(std::string(url));
auto make_repo = [&]() -> expected_t<solv::ObjRepoView>
{
if (parser == solver::libsolv::RepodataParser::Mamba)
{
return solver::libsolv::mamba_read_json(
pool(),
repo,
path,
std::string(url),
use_only_tar_bz2
);
}
return solver::libsolv::libsolv_read_json(repo, path, use_only_tar_bz2)
.transform(
[&url](solv::ObjRepoView p_repo)
{
solver::libsolv::set_solvables_url(p_repo, std::string(url));
return p_repo;
}
);
};
return make_repo()
.transform(
[&](solv::ObjRepoView p_repo) -> solver::libsolv::RepoInfo
{
if (add == solver::libsolv::PipAsPythonDependency::Yes)
{
solver::libsolv::add_pip_as_python_dependency(pool(), p_repo);
}
p_repo.internalize();
return solver::libsolv::RepoInfo{ p_repo.raw() };
}
)
.or_else([&](const auto&) { pool().remove_repo(repo.id(), /* reuse_ids= */ true); });
}
auto MPool::add_repo_from_native_serialization(
const fs::u8path& path,
const solver::libsolv::RepodataOrigin& expected,
solver::libsolv::PipAsPythonDependency add
) -> expected_t<solver::libsolv::RepoInfo>
{
auto repo = pool().add_repo(expected.url).second;
return solver::libsolv::read_solv(pool(), repo, path, expected, static_cast<bool>(add))
.transform(
[&](solv::ObjRepoView p_repo) -> solver::libsolv::RepoInfo
{
p_repo.set_url(expected.url);
solver::libsolv::set_solvables_url(p_repo, expected.url);
if (add == solver::libsolv::PipAsPythonDependency::Yes)
{
solver::libsolv::add_pip_as_python_dependency(pool(), p_repo);
}
p_repo.internalize();
return solver::libsolv::RepoInfo(p_repo.raw());
}
)
.or_else([&](const auto&) { pool().remove_repo(repo.id(), /* reuse_ids= */ true); });
}
auto MPool::add_repo_from_packages_impl_pre(std::string_view name) -> solver::libsolv::RepoInfo
{
if (name.empty())
{
return solver::libsolv::RepoInfo(
pool().add_repo(util::generate_random_alphanumeric_string(20)).second.raw()
);
}
return solver::libsolv::RepoInfo(pool().add_repo(name).second.raw());
}
void MPool::add_repo_from_packages_impl_loop(
const solver::libsolv::RepoInfo& repo,
const specs::PackageInfo& pkg
)
{
auto s_repo = solv::ObjRepoView(*repo.m_ptr);
auto [id, solv] = s_repo.add_solvable();
solver::libsolv::set_solvable(pool(), solv, pkg);
}
void MPool::add_repo_from_packages_impl_post(
const solver::libsolv::RepoInfo& repo,
solver::libsolv::PipAsPythonDependency add
)
{
auto s_repo = solv::ObjRepoView(*repo.m_ptr);
if (add == solver::libsolv::PipAsPythonDependency::Yes)
{
solver::libsolv::add_pip_as_python_dependency(pool(), s_repo);
}
s_repo.internalize();
}
auto MPool::native_serialize_repo(
const solver::libsolv::RepoInfo& repo,
const fs::u8path& path,
const solver::libsolv::RepodataOrigin& metadata
) -> expected_t<solver::libsolv::RepoInfo>
{
assert(repo.m_ptr != nullptr);
return solver::libsolv::write_solv(solv::ObjRepoView(*repo.m_ptr), path, metadata)
.transform([](solv::ObjRepoView solv_repo)
{ return solver::libsolv::RepoInfo(solv_repo.raw()); });
}
void MPool::remove_repo(solver::libsolv::RepoInfo repo)
{
pool().remove_repo(repo.id(), /* reuse_ids= */ true);
}
auto MPool::installed_repo() const -> std::optional<solver::libsolv::RepoInfo>
{
if (auto repo = pool().installed_repo())
{
// Safe because the Repo does not modify its internals
return solver::libsolv::RepoInfo(const_cast<::Repo*>(repo->raw()));
}
return {};
}
void MPool::set_installed_repo(solver::libsolv::RepoInfo repo)
{
pool().set_installed_repo(repo.id());
}
void
MPool::set_repo_priority(solver::libsolv::RepoInfo repo, solver::libsolv::Priorities priorities)
{
// NOTE: The Pool is not involved directly in this operations, but since it is needed
// in so many repo operations, this setter was put here to keep the Repo class
// immutable.
static_assert(std::is_same_v<decltype(repo.m_ptr->priority), solver::libsolv::Priorities::value_type>);
repo.m_ptr->priority = priorities.priority;
repo.m_ptr->subpriority = priorities.subpriority;
}
auto MPool::package_id_to_package_info(PackageId id) const -> specs::PackageInfo
{
static_assert(std::is_same_v<std::underlying_type_t<PackageId>, solv::SolvableId>);
const auto solv = pool().get_solvable(static_cast<solv::SolvableId>(id));
assert(solv.has_value()); // Safe because the ID is coming from libsolv
return { solver::libsolv::make_package_info(pool(), solv.value()) };
}
auto MPool::packages_in_repo(solver::libsolv::RepoInfo repo) const -> std::vector<PackageId>
{
// TODO maybe we could use a span here depending on libsolv layout
auto solv_repo = solv::ObjRepoViewConst(*repo.m_ptr);
auto out = std::vector<PackageId>();
out.reserve(solv_repo.solvable_count());
solv_repo.for_each_solvable_id([&](auto id) { out.push_back(static_cast<PackageId>(id)); });
return out;
}
namespace
{
auto matchspec2id(
solv::ObjPool& pool,
const specs::ChannelResolveParams& channel_params,
const specs::MatchSpec& ms
) -> solv::DependencyId
{
return solver::libsolv::pool_add_matchspec(pool, ms, channel_params)
.or_else([](mamba_error&& error) { throw std::move(error); })
.value_or(0);
}
}
auto MPool::packages_matching_ids(const specs::MatchSpec& ms) -> std::vector<PackageId>
{
static_assert(std::is_same_v<std::underlying_type_t<PackageId>, solv::SolvableId>);
pool().ensure_whatprovides();
const auto ms_id = matchspec2id(pool(), channel_params(), ms);
auto solvables = pool().select_solvables({ SOLVER_SOLVABLE_PROVIDES, ms_id });
auto out = std::vector<PackageId>(solvables.size());
std::transform(
solvables.begin(),
solvables.end(),
out.begin(),
[](auto id) { return static_cast<PackageId>(id); }
);
return out;
}
auto MPool::packages_depending_on_ids(const specs::MatchSpec& ms) -> std::vector<PackageId>
{
static_assert(std::is_same_v<std::underlying_type_t<PackageId>, solv::SolvableId>);
pool().ensure_whatprovides();
const auto ms_id = matchspec2id(pool(), channel_params(), ms);
auto solvables = pool().what_matches_dep(SOLVABLE_REQUIRES, ms_id);
auto out = std::vector<PackageId>(solvables.size());
std::transform(
solvables.begin(),
solvables.end(),
out.begin(),
[](auto id) { return static_cast<PackageId>(id); }
);
return out;
}
// TODO machinery functions in separate files
void add_spdlog_logger_to_pool(MPool& pool)
{
pool.set_logger(
[logger = spdlog::get("libsolv")](solver::libsolv::LogLevel level, std::string_view msg)
{
switch (level)
{
case (solver::libsolv::LogLevel::Fatal):
logger->critical(msg);
break;
case (solver::libsolv::LogLevel::Error):
logger->error(msg);
break;
case (solver::libsolv::LogLevel::Warning):
logger->warn(msg);
break;
case (solver::libsolv::LogLevel::Debug):
logger->debug(msg);
break;
}
}
);
}
auto load_subdir_in_pool(const Context& ctx, MPool& pool, const SubdirData& subdir)
-> expected_t<solver::libsolv::RepoInfo>
{
const auto expected_cache_origin = solver::libsolv::RepodataOrigin{
/* .url= */ util::rsplit(subdir.metadata().url(), "/", 1).front(),
/* .etag= */ subdir.metadata().etag(),
/* .mod= */ subdir.metadata().last_modified(),
};
const auto add_pip = static_cast<solver::libsolv::PipAsPythonDependency>(
ctx.add_pip_as_python_dependency
);
const auto json_parser = ctx.experimental_repodata_parsing
? solver::libsolv::RepodataParser::Mamba
: solver::libsolv::RepodataParser::Libsolv;
// Solv files are too slow on Windows.
if (!util::on_win)
{
auto maybe_repo = subdir.valid_solv_cache().and_then(
[&](fs::u8path&& solv_file) {
return pool.add_repo_from_native_serialization(
solv_file,
expected_cache_origin,
add_pip
);
}
);
if (maybe_repo)
{
return maybe_repo;
}
}
return subdir.valid_json_cache()
.and_then(
[&](fs::u8path&& repodata_json)
{
LOG_INFO << "Trying to load repo from json file " << repodata_json;
return pool.add_repo_from_repodata_json(
repodata_json,
util::rsplit(subdir.metadata().url(), "/", 1).front(),
add_pip,
static_cast<solver::libsolv::UseOnlyTarBz2>(ctx.use_only_tar_bz2),
json_parser
);
}
)
.transform(
[&](solver::libsolv::RepoInfo&& repo) -> solver::libsolv::RepoInfo
{
if (!util::on_win)
{
pool.native_serialize_repo(repo, subdir.writable_solv_cache(), expected_cache_origin)
.or_else(
[&](const auto& err)
{
LOG_WARNING << R"(Fail to write native serialization to file ")"
<< subdir.writable_solv_cache() << R"(" for repo ")"
<< subdir.name() << ": " << err.what();
;
}
);
}
return std::move(repo);
}
);
}
auto load_installed_packages_in_pool(const Context& ctx, MPool& pool, const PrefixData& prefix)
-> solver::libsolv::RepoInfo
{
// TODO(C++20): We could do a PrefixData range that returns packages without storing thems.
auto pkgs = prefix.sorted_records();
// TODO(C++20): We only need a range that concatenate both
for (auto&& pkg : get_virtual_packages(ctx))
{
pkgs.push_back(std::move(pkg));
}
// Not adding Pip dependency since it might needlessly make the installed/active environment
// broken if pip is not already installed (debatable).
auto repo = pool.add_repo_from_packages(
pkgs,
"installed",
solver::libsolv::PipAsPythonDependency::No
);
pool.set_installed_repo(repo);
return repo;
}
}

View File

@ -18,6 +18,7 @@
#include "mamba/core/context.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/query.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/specs/conda_url.hpp"
#include "mamba/specs/package_info.hpp"
#include "mamba/util/string.hpp"
@ -72,11 +73,11 @@ namespace mamba
}
};
auto pool_latest_package(MPool& pool, specs::MatchSpec spec)
auto database_latest_package(solver::libsolv::Database& db, specs::MatchSpec spec)
-> std::optional<specs::PackageInfo>
{
auto out = std::optional<specs::PackageInfo>();
pool.for_each_package_matching(
db.for_each_package_matching(
spec,
[&](auto pkg)
{
@ -96,7 +97,7 @@ namespace mamba
using DepGraph = typename QueryResult::dependency_graph;
using node_id = typename QueryResult::dependency_graph::node_id;
PoolWalker(MPool& pool);
PoolWalker(solver::libsolv::Database& db);
void walk(specs::PackageInfo pkg, std::size_t max_depth);
void walk(specs::PackageInfo pkg);
@ -113,14 +114,14 @@ namespace mamba
DepGraph m_graph;
VisitedMap m_visited;
NotFoundMap m_not_found;
MPool& m_pool;
solver::libsolv::Database& m_database;
void walk_impl(node_id id, std::size_t max_depth);
void reverse_walk_impl(node_id id);
};
PoolWalker::PoolWalker(MPool& pool)
: m_pool(pool)
PoolWalker::PoolWalker(solver::libsolv::Database& db)
: m_database(db)
{
}
@ -148,7 +149,7 @@ namespace mamba
// as taking any package matching a dependency recursively.
// Package dependencies can appear mulitple time, further reducing its valid set.
// To do this properly, we should instanciate a solver and resolve the spec.
if (auto child = pool_latest_package(m_pool, specs::MatchSpec::parse(dep)))
if (auto child = database_latest_package(m_database, specs::MatchSpec::parse(dep)))
{
if (auto it = m_visited.find(&(*child)); it != m_visited.cend())
{
@ -185,7 +186,7 @@ namespace mamba
void PoolWalker::reverse_walk_impl(node_id id)
{
m_pool.for_each_package_depending_on(
m_database.for_each_package_depending_on(
specs::MatchSpec::parse(m_graph.node(id).name),
[&](specs::PackageInfo pkg)
{
@ -210,12 +211,12 @@ namespace mamba
}
}
auto Query::find(MPool& mpool, const std::vector<std::string>& queries) -> QueryResult
auto Query::find(Database& db, const std::vector<std::string>& queries) -> QueryResult
{
QueryResult::dependency_graph g;
for (const auto& query : queries)
{
mpool.for_each_package_matching(
db.for_each_package_matching(
specs::MatchSpec::parse(query),
[&](specs::PackageInfo&& pkg) { g.add_node(std::move(pkg)); }
);
@ -228,13 +229,13 @@ namespace mamba
};
}
auto Query::whoneeds(MPool& mpool, std::string query, bool tree) -> QueryResult
auto Query::whoneeds(Database& db, std::string query, bool tree) -> QueryResult
{
if (tree)
{
if (auto pkg = pool_latest_package(mpool, specs::MatchSpec::parse(query)))
if (auto pkg = database_latest_package(db, specs::MatchSpec::parse(query)))
{
auto walker = PoolWalker(mpool);
auto walker = PoolWalker(db);
walker.reverse_walk(std::move(pkg).value());
return { QueryType::WhoNeeds, std::move(query), std::move(walker).graph() };
}
@ -242,7 +243,7 @@ namespace mamba
else
{
QueryResult::dependency_graph g;
mpool.for_each_package_depending_on(
db.for_each_package_depending_on(
specs::MatchSpec::parse(query),
[&](specs::PackageInfo&& pkg) { g.add_node(std::move(pkg)); }
);
@ -251,11 +252,11 @@ namespace mamba
return { QueryType::WhoNeeds, std::move(query), QueryResult::dependency_graph() };
}
auto Query::depends(MPool& mpool, std::string query, bool tree) -> QueryResult
auto Query::depends(Database& db, std::string query, bool tree) -> QueryResult
{
if (auto pkg = pool_latest_package(mpool, specs::MatchSpec::parse(query)))
if (auto pkg = database_latest_package(db, specs::MatchSpec::parse(query)))
{
auto walker = PoolWalker(mpool);
auto walker = PoolWalker(db);
if (tree)
{
walker.walk(std::move(pkg).value());

View File

@ -24,9 +24,9 @@
#include "mamba/core/link.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/package_fetcher.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/core/thread_utils.hpp"
#include "mamba/core/transaction.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/specs/match_spec.hpp"
#include "mamba/util/variant_cmp.hpp"
@ -47,10 +47,10 @@ namespace mamba
}
// TODO duplicated function, consider moving it to Pool
auto pool_has_package(MPool& pool, const specs::MatchSpec& spec) -> bool
auto database_has_package(solver::libsolv::Database& db, const specs::MatchSpec& spec) -> bool
{
bool found = false;
pool.for_each_package_matching(
db.for_each_package_matching(
spec,
[&](const auto&)
{
@ -76,13 +76,14 @@ namespace mamba
return out;
}
auto installed_python(const MPool& pool) -> std::optional<specs::PackageInfo>
auto installed_python(const solver::libsolv::Database& db)
-> std::optional<specs::PackageInfo>
{
// TODO combine Repo and MatchSpec search API in Pool
auto out = std::optional<specs::PackageInfo>();
if (auto repo = pool.installed_repo())
if (auto repo = db.installed_repo())
{
pool.for_each_package_in_repo(
db.for_each_package_in_repo(
*repo,
[&](specs::PackageInfo&& pkg)
{
@ -98,7 +99,8 @@ namespace mamba
return out;
}
auto find_python_version(const solver::Solution& solution, const MPool& pool)
auto
find_python_version(const solver::Solution& solution, const solver::libsolv::Database& db)
-> std::pair<std::string, std::string>
{
// We need to find the python version that will be there after this
@ -108,7 +110,7 @@ namespace mamba
// version but keeping the current one.
// Could also be written in term of PrefixData.
std::string installed_py_ver = {};
if (auto pkg = installed_python(pool))
if (auto pkg = installed_python(db))
{
installed_py_ver = pkg->version;
LOG_INFO << "Found python in installed packages " << installed_py_ver;
@ -132,7 +134,7 @@ namespace mamba
MTransaction::MTransaction(
const Context& ctx,
MPool& pool,
solver::libsolv::Database& db,
std::vector<specs::PackageInfo> pkgs_to_remove,
std::vector<specs::PackageInfo> pkgs_to_install,
MultiPackageCache& caches
@ -143,7 +145,7 @@ namespace mamba
for (const auto& pkg : pkgs_to_remove)
{
auto spec = explicit_spec(pkg);
if (!pool_has_package(pool, spec))
if (!database_has_package(db, spec))
{
not_found << "\n - " << spec.str();
}
@ -203,14 +205,14 @@ namespace mamba
ctx,
ctx.prefix_params.target_prefix,
ctx.prefix_params.relocate_prefix,
find_python_version(m_solution, pool),
find_python_version(m_solution, db),
specs_to_install
);
}
MTransaction::MTransaction(
const Context& ctx,
MPool& pool,
solver::libsolv::Database& db,
const solver::Request& request,
solver::Solution solution,
MultiPackageCache& caches
@ -257,7 +259,7 @@ namespace mamba
ctx,
ctx.prefix_params.target_prefix,
ctx.prefix_params.relocate_prefix,
find_python_version(m_solution, pool),
find_python_version(m_solution, db),
std::move(requested_specs)
);
@ -273,7 +275,7 @@ namespace mamba
MTransaction::MTransaction(
const Context& ctx,
MPool& pool,
solver::libsolv::Database& db,
std::vector<specs::PackageInfo> packages,
MultiPackageCache& caches
)
@ -307,7 +309,7 @@ namespace mamba
ctx,
ctx.prefix_params.target_prefix,
ctx.prefix_params.relocate_prefix,
find_python_version(m_solution, pool),
find_python_version(m_solution, db),
std::move(specs_to_install)
);
}
@ -1112,7 +1114,7 @@ namespace mamba
}
MTransaction
create_explicit_transaction_from_urls(const Context& ctx, MPool& pool, const std::vector<std::string>& urls, MultiPackageCache& package_caches, std::vector<detail::other_pkg_mgr_spec>&)
create_explicit_transaction_from_urls(const Context& ctx, solver::libsolv::Database& db, const std::vector<std::string>& urls, MultiPackageCache& package_caches, std::vector<detail::other_pkg_mgr_spec>&)
{
std::vector<specs::PackageInfo> specs_to_install = {};
specs_to_install.reserve(urls.size());
@ -1122,12 +1124,12 @@ namespace mamba
std::back_insert_iterator(specs_to_install),
[&](const auto& u) { return specs::PackageInfo::from_url(u); }
);
return MTransaction(ctx, pool, {}, specs_to_install, package_caches);
return MTransaction(ctx, db, {}, specs_to_install, package_caches);
}
MTransaction create_explicit_transaction_from_lockfile(
const Context& ctx,
MPool& pool,
solver::libsolv::Database& db,
const fs::u8path& env_lockfile_path,
const std::vector<std::string>& categories,
MultiPackageCache& package_caches,
@ -1191,7 +1193,7 @@ namespace mamba
);
}
return MTransaction{ ctx, pool, std::move(conda_packages), package_caches };
return MTransaction{ ctx, db, std::move(conda_packages), package_caches };
}
} // namespace mamba

View File

@ -0,0 +1,331 @@
// 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.
#include <exception>
#include <iostream>
#include <limits>
#include <string_view>
#include <fmt/format.h>
#include <solv/evr.h>
#include <solv/selection.h>
#include <solv/solver.h>
#include <spdlog/spdlog.h>
#include "mamba/fs/filesystem.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
#include "mamba/specs/match_spec.hpp"
#include "mamba/util/random.hpp"
#include "solv-cpp/pool.hpp"
#include "solv-cpp/queue.hpp"
#include "solver/libsolv/helpers.hpp"
namespace mamba::solver::libsolv
{
struct Database::DatabaseImpl
{
DatabaseImpl(specs::ChannelResolveParams p_channel_params)
: channel_params(std::move(p_channel_params))
{
}
specs::ChannelResolveParams channel_params;
solv::ObjPool pool = {};
};
Database::Database(specs::ChannelResolveParams channel_params)
: m_data(std::make_unique<DatabaseImpl>(std::move(channel_params)))
{
pool().set_disttype(DISTTYPE_CONDA);
// Ensure that debug logging never goes to stdout as to not interfere json output
pool().raw()->debugmask |= SOLV_DEBUG_TO_STDERR;
::pool_setdebuglevel(pool().raw(), -1); // Off
}
Database::~Database() = default;
Database::Database(Database&&) = default;
auto Database::operator=(Database&&) -> Database& = default;
auto Database::pool() -> solv::ObjPool&
{
return m_data->pool;
}
auto Database::pool() const -> const solv::ObjPool&
{
return m_data->pool;
}
auto Database::Impl::get(Database& pool) -> solv::ObjPool&
{
return pool.pool();
}
auto Database::Impl::get(const Database& pool) -> const solv::ObjPool&
{
return pool.pool();
}
auto Database::channel_params() const -> const specs::ChannelResolveParams&
{
return m_data->channel_params;
}
namespace
{
auto libsolv_to_log_level(int type) -> LogLevel
{
if (type & SOLV_FATAL)
{
return LogLevel::Fatal;
}
if (type & SOLV_ERROR)
{
return LogLevel::Error;
}
if (type & SOLV_WARN)
{
return LogLevel::Warning;
}
return LogLevel::Debug;
}
}
void Database::set_logger(logger_type callback)
{
::pool_setdebuglevel(pool().raw(), std::numeric_limits<int>::max()); // All
pool().set_debug_callback(
[logger = std::move(callback)](::Pool*, int type, std::string_view msg) noexcept
{
try
{
logger(libsolv_to_log_level(type), msg);
}
catch (std::exception const& e)
{
std::cerr << "Developer error: error in libsolv logging function: \n"
<< e.what();
}
}
);
}
auto Database::add_repo_from_repodata_json(
const fs::u8path& path,
std::string_view url,
PipAsPythonDependency add,
UseOnlyTarBz2 only_tar,
RepodataParser parser
) -> expected_t<RepoInfo>
{
const auto use_only_tar_bz2 = static_cast<bool>(only_tar);
if (!fs::exists(path))
{
return make_unexpected(
fmt::format(R"(File "{}" does not exist)", path),
mamba_error_code::repodata_not_loaded
);
}
auto repo = pool().add_repo(url).second;
repo.set_url(std::string(url));
auto make_repo = [&]() -> expected_t<solv::ObjRepoView>
{
if (parser == RepodataParser::Mamba)
{
return mamba_read_json(pool(), repo, path, std::string(url), use_only_tar_bz2);
}
return libsolv_read_json(repo, path, use_only_tar_bz2)
.transform(
[&url](solv::ObjRepoView p_repo)
{
set_solvables_url(p_repo, std::string(url));
return p_repo;
}
);
};
return make_repo()
.transform(
[&](solv::ObjRepoView p_repo) -> RepoInfo
{
if (add == PipAsPythonDependency::Yes)
{
add_pip_as_python_dependency(pool(), p_repo);
}
p_repo.internalize();
return RepoInfo{ p_repo.raw() };
}
)
.or_else([&](const auto&) { pool().remove_repo(repo.id(), /* reuse_ids= */ true); });
}
auto Database::add_repo_from_native_serialization(
const fs::u8path& path,
const RepodataOrigin& expected,
PipAsPythonDependency add
) -> expected_t<RepoInfo>
{
auto repo = pool().add_repo(expected.url).second;
return read_solv(pool(), repo, path, expected, static_cast<bool>(add))
.transform(
[&](solv::ObjRepoView p_repo) -> RepoInfo
{
p_repo.set_url(expected.url);
set_solvables_url(p_repo, expected.url);
if (add == PipAsPythonDependency::Yes)
{
add_pip_as_python_dependency(pool(), p_repo);
}
p_repo.internalize();
return RepoInfo(p_repo.raw());
}
)
.or_else([&](const auto&) { pool().remove_repo(repo.id(), /* reuse_ids= */ true); });
}
auto Database::add_repo_from_packages_impl_pre(std::string_view name) -> RepoInfo
{
if (name.empty())
{
return RepoInfo(
pool().add_repo(util::generate_random_alphanumeric_string(20)).second.raw()
);
}
return RepoInfo(pool().add_repo(name).second.raw());
}
void
Database::add_repo_from_packages_impl_loop(const RepoInfo& repo, const specs::PackageInfo& pkg)
{
auto s_repo = solv::ObjRepoView(*repo.m_ptr);
auto [id, solv] = s_repo.add_solvable();
set_solvable(pool(), solv, pkg);
}
void Database::add_repo_from_packages_impl_post(const RepoInfo& repo, PipAsPythonDependency add)
{
auto s_repo = solv::ObjRepoView(*repo.m_ptr);
if (add == PipAsPythonDependency::Yes)
{
add_pip_as_python_dependency(pool(), s_repo);
}
s_repo.internalize();
}
auto Database::native_serialize_repo(
const RepoInfo& repo,
const fs::u8path& path,
const RepodataOrigin& metadata
) -> expected_t<RepoInfo>
{
assert(repo.m_ptr != nullptr);
return write_solv(solv::ObjRepoView(*repo.m_ptr), path, metadata)
.transform([](solv::ObjRepoView solv_repo) { return RepoInfo(solv_repo.raw()); });
}
void Database::remove_repo(RepoInfo repo)
{
pool().remove_repo(repo.id(), /* reuse_ids= */ true);
}
auto Database::installed_repo() const -> std::optional<RepoInfo>
{
if (auto repo = pool().installed_repo())
{
// Safe because the Repo does not modify its internals
return RepoInfo(const_cast<::Repo*>(repo->raw()));
}
return {};
}
void Database::set_installed_repo(RepoInfo repo)
{
pool().set_installed_repo(repo.id());
}
void Database::set_repo_priority(RepoInfo repo, Priorities priorities)
{
// NOTE: The Pool is not involved directly in this operations, but since it is needed
// in so many repo operations, this setter was put here to keep the Repo class
// immutable.
static_assert(std::is_same_v<decltype(repo.m_ptr->priority), Priorities::value_type>);
repo.m_ptr->priority = priorities.priority;
repo.m_ptr->subpriority = priorities.subpriority;
}
auto Database::package_id_to_package_info(PackageId id) const -> specs::PackageInfo
{
static_assert(std::is_same_v<std::underlying_type_t<PackageId>, solv::SolvableId>);
const auto solv = pool().get_solvable(static_cast<solv::SolvableId>(id));
assert(solv.has_value()); // Safe because the ID is coming from libsolv
return { make_package_info(pool(), solv.value()) };
}
auto Database::packages_in_repo(RepoInfo repo) const -> std::vector<PackageId>
{
// TODO maybe we could use a span here depending on libsolv layout
auto solv_repo = solv::ObjRepoViewConst(*repo.m_ptr);
auto out = std::vector<PackageId>();
out.reserve(solv_repo.solvable_count());
solv_repo.for_each_solvable_id([&](auto id) { out.push_back(static_cast<PackageId>(id)); });
return out;
}
namespace
{
auto matchspec2id(
solv::ObjPool& pool,
const specs::ChannelResolveParams& channel_params,
const specs::MatchSpec& ms
) -> solv::DependencyId
{
return pool_add_matchspec(pool, ms, channel_params)
.or_else([](mamba_error&& error) { throw std::move(error); })
.value_or(0);
}
}
auto Database::packages_matching_ids(const specs::MatchSpec& ms) -> std::vector<PackageId>
{
static_assert(std::is_same_v<std::underlying_type_t<PackageId>, solv::SolvableId>);
pool().ensure_whatprovides();
const auto ms_id = matchspec2id(pool(), channel_params(), ms);
auto solvables = pool().select_solvables({ SOLVER_SOLVABLE_PROVIDES, ms_id });
auto out = std::vector<PackageId>(solvables.size());
std::transform(
solvables.begin(),
solvables.end(),
out.begin(),
[](auto id) { return static_cast<PackageId>(id); }
);
return out;
}
auto Database::packages_depending_on_ids(const specs::MatchSpec& ms) -> std::vector<PackageId>
{
static_assert(std::is_same_v<std::underlying_type_t<PackageId>, solv::SolvableId>);
pool().ensure_whatprovides();
const auto ms_id = matchspec2id(pool(), channel_params(), ms);
auto solvables = pool().what_matches_dep(SOLVABLE_REQUIRES, ms_id);
auto out = std::vector<PackageId>(solvables.size());
std::transform(
solvables.begin(),
solvables.end(),
out.begin(),
[](auto id) { return static_cast<PackageId>(id); }
);
return out;
}
}

View File

@ -6,9 +6,8 @@
#include <solv/solver.h>
#include "mamba/core/channel_context.hpp"
#include "mamba/core/error_handling.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/solver/libsolv/solver.hpp"
#include "mamba/util/variant_cmp.hpp"
#include "solv-cpp/solver.hpp"
@ -51,9 +50,9 @@ namespace mamba::solver::libsolv
}
}
auto Solver::solve_impl(MPool& mpool, const Request& request) -> expected_t<Outcome>
auto Solver::solve_impl(Database& mpool, const Request& request) -> expected_t<Outcome>
{
auto& pool = MPool::Impl::get(mpool);
auto& pool = Database::Impl::get(mpool);
const auto& chan_params = mpool.channel_params();
const auto& flags = request.flags;
@ -87,7 +86,7 @@ namespace mamba::solver::libsolv
);
}
auto Solver::solve(MPool& mpool, Request&& request) -> expected_t<Outcome>
auto Solver::solve(Database& mpool, Request&& request) -> expected_t<Outcome>
{
if (request.flags.order_request)
{
@ -96,7 +95,7 @@ namespace mamba::solver::libsolv
return solve_impl(mpool, request);
}
auto Solver::solve(MPool& mpool, const Request& request) -> expected_t<Outcome>
auto Solver::solve(Database& mpool, const Request& request) -> expected_t<Outcome>
{
if (request.flags.order_request)
{

View File

@ -13,7 +13,7 @@
#include "mamba/core/output.hpp"
#include "mamba/core/palette.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/solver/libsolv/unsolvable.hpp"
#include "mamba/specs/match_spec.hpp"
#include "mamba/specs/package_info.hpp"
@ -41,9 +41,9 @@ namespace mamba::solver::libsolv
return *m_solver;
}
auto UnSolvable::problems(MPool& mpool) const -> std::vector<std::string>
auto UnSolvable::problems(Database& mpool) const -> std::vector<std::string>
{
auto& pool = MPool::Impl::get(mpool);
auto& pool = Database::Impl::get(mpool);
std::vector<std::string> problems;
solver().for_each_problem_id([&](solv::ProblemId pb)
{ problems.emplace_back(solver().problem_to_string(pool, pb)); }
@ -51,9 +51,9 @@ namespace mamba::solver::libsolv
return problems;
}
auto UnSolvable::problems_to_str(MPool& mpool) const -> std::string
auto UnSolvable::problems_to_str(Database& mpool) const -> std::string
{
auto& pool = MPool::Impl::get(mpool);
auto& pool = Database::Impl::get(mpool);
std::stringstream problems;
problems << "Encountered problems while solving:\n";
solver().for_each_problem_id(
@ -63,9 +63,9 @@ namespace mamba::solver::libsolv
return problems.str();
}
auto UnSolvable::all_problems_to_str(MPool& mpool) const -> std::string
auto UnSolvable::all_problems_to_str(Database& mpool) const -> std::string
{
auto& pool = MPool::Impl::get(mpool);
auto& pool = Database::Impl::get(mpool);
std::stringstream problems;
solver().for_each_problem_id(
[&](solv::ProblemId pb)
@ -467,13 +467,14 @@ namespace mamba::solver::libsolv
}
}
auto UnSolvable::problems_graph(const MPool& pool) const -> ProblemsGraph
auto UnSolvable::problems_graph(const Database& pool) const -> ProblemsGraph
{
assert(m_solver != nullptr);
return ProblemsGraphCreator(MPool::Impl::get(pool), *m_solver).problem_graph();
return ProblemsGraphCreator(Database::Impl::get(pool), *m_solver).problem_graph();
}
auto UnSolvable::explain_problems_to(MPool& pool, std::ostream& out, const Palette& palette) const
auto
UnSolvable::explain_problems_to(Database& pool, std::ostream& out, const Palette& palette) const
-> std::ostream&
{
out << "Could not solve for environment specs\n";
@ -491,7 +492,7 @@ namespace mamba::solver::libsolv
return out;
}
auto UnSolvable::explain_problems(MPool& pool, const Palette& palette) const -> std::string
auto UnSolvable::explain_problems(Database& pool, const Palette& palette) const -> std::string
{
std::stringstream ss;

View File

@ -10,7 +10,9 @@
#include "mamba/core/channel_context.hpp"
#include "mamba/core/env_lockfile.hpp"
#include "mamba/core/fsutil.hpp"
#include "mamba/core/package_database_loader.hpp"
#include "mamba/core/transaction.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mambatests.hpp"
@ -126,8 +128,8 @@ namespace mamba
const fs::u8path lockfile_path{ mambatests::test_data_dir
/ "env_lockfile/good_multiple_categories-lock.yaml" };
auto channel_context = ChannelContext::make_conda_compatible(mambatests::context());
MPool pool{ channel_context.params() };
add_spdlog_logger_to_pool(pool);
solver::libsolv::Database db{ channel_context.params() };
add_spdlog_logger_to_database(db);
mamba::MultiPackageCache pkg_cache({ "/tmp/" }, ctx.validation_params);
ctx.platform = "linux-64";
@ -138,7 +140,7 @@ namespace mamba
std::vector<detail::other_pkg_mgr_spec> other_specs;
auto transaction = create_explicit_transaction_from_lockfile(
ctx,
pool,
db,
lockfile_path,
categories,
pkg_cache,

View File

@ -14,11 +14,12 @@
#include <nlohmann/json.hpp>
#include "mamba/core/channel_context.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/core/package_database_loader.hpp"
#include "mamba/core/prefix_data.hpp"
#include "mamba/core/subdirdata.hpp"
#include "mamba/core/util.hpp"
#include "mamba/fs/filesystem.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
#include "mamba/solver/libsolv/solver.hpp"
#include "mamba/solver/libsolv/unsolvable.hpp"
@ -97,26 +98,26 @@ namespace
}
/**
* Create a solver and a pool of a conflict.
* Create a solver and a database of a conflict.
*
* The underlying packages do not exist, we are onl interested in the conflict.
*/
template <typename PkgRange>
auto create_pkgs_pool(ChannelContext& channel_context, const PkgRange& packages)
auto create_pkgs_database(ChannelContext& channel_context, const PkgRange& packages)
{
MPool pool{ channel_context.params() };
pool.add_repo_from_packages(packages);
return pool;
solver::libsolv::Database db{ channel_context.params() };
db.add_repo_from_packages(packages);
return db;
}
}
TEST_CASE("Test create_pool utility")
TEST_CASE("Test create_pkgs_database utility")
{
auto& ctx = mambatests::context();
auto channel_context = ChannelContext::make_conda_compatible(ctx);
auto pool = create_pkgs_pool(channel_context, std::array{ mkpkg("foo", "0.1.0", {}) });
auto db = create_pkgs_database(channel_context, std::array{ mkpkg("foo", "0.1.0", {}) });
auto request = Request{ {}, { Request::Install{ "foo"_ms } } };
const auto outcome = solver::libsolv::Solver().solve(pool, request).value();
const auto outcome = solver::libsolv::Solver().solve(db, request).value();
REQUIRE(std::holds_alternative<solver::Solution>(outcome));
}
@ -124,12 +125,12 @@ TEST_CASE("Test empty specs")
{
auto& ctx = mambatests::context();
auto channel_context = ChannelContext::make_conda_compatible(ctx);
auto pool = create_pkgs_pool(
auto db = create_pkgs_database(
channel_context,
std::array{ mkpkg("foo", "0.1.0", {}), mkpkg("", "", {}) }
);
auto request = Request{ {}, { Request::Install{ "foo"_ms } } };
const auto outcome = solver::libsolv::Solver().solve(pool, request).value();
const auto outcome = solver::libsolv::Solver().solve(db, request).value();
REQUIRE(std::holds_alternative<solver::Solution>(outcome));
}
@ -138,7 +139,7 @@ namespace
auto create_basic_conflict(Context&, ChannelContext& channel_context)
{
return std::pair(
create_pkgs_pool(
create_pkgs_database(
channel_context,
std::array{
mkpkg("A", "0.1.0"),
@ -159,7 +160,7 @@ namespace
auto create_pubgrub(Context&, ChannelContext& channel_context)
{
return std::pair(
create_pkgs_pool(
create_pkgs_database(
channel_context,
std::array{
mkpkg("menu", "1.5.0", { "dropdown=2.*" }),
@ -241,7 +242,7 @@ namespace
packages.push_back(mkpkg("dropdown", "2.9.0", { "libicons>10.0" }));
}
return std::pair(
create_pkgs_pool(channel_context, packages),
create_pkgs_database(channel_context, packages),
Request{
{},
{
@ -287,7 +288,7 @@ namespace
auto load_channels(
Context& ctx,
ChannelContext& channel_context,
MPool& pool,
solver::libsolv::Database& db,
MultiPackageCache& cache,
std::vector<std::string>&& channels
)
@ -317,14 +318,14 @@ namespace
for (auto& sub_dir : sub_dirs)
{
auto repo = load_subdir_in_pool(ctx, pool, sub_dir);
auto repo = load_subdir_in_database(ctx, db, sub_dir);
}
}
/**
* Create a solver and a pool of a conflict from conda-forge packages.
* Create a solver and a database of a conflict from conda-forge packages.
*/
auto create_conda_forge_pool(
auto create_conda_forge_database(
Context& ctx,
ChannelContext& channel_context,
const std::vector<specs::PackageInfo>& virtual_packages = { mkpkg("__glibc", "2.17.0") },
@ -338,9 +339,9 @@ namespace
auto prefix_data = PrefixData::create(tmp_dir.path() / "prefix", channel_context).value();
prefix_data.add_packages(virtual_packages);
auto pool = MPool{ channel_context.params() };
auto db = solver::libsolv::Database{ channel_context.params() };
load_installed_packages_in_pool(ctx, pool, prefix_data);
load_installed_packages_in_database(ctx, db, prefix_data);
auto cache = MultiPackageCache({ tmp_dir.path() / "cache" }, ctx.validation_params);
create_cache_dir(cache.first_writable_path());
@ -350,13 +351,13 @@ namespace
load_channels(
ctx,
channel_context,
pool,
db,
cache,
make_platform_channels(std::move(channels), platforms)
);
ctx.graphics_params.no_progress_bars = prev_progress_bars_value;
return pool;
return db;
}
}
@ -364,9 +365,9 @@ TEST_CASE("Test create_conda_forge utility")
{
auto& ctx = mambatests::context();
auto channel_context = ChannelContext::make_conda_compatible(ctx);
auto pool = create_conda_forge_pool(ctx, channel_context);
auto db = create_conda_forge_database(ctx, channel_context);
auto request = Request{ {}, { Request::Install{ "xtensor>=0.7"_ms } } };
const auto outcome = solver::libsolv::Solver().solve(pool, request).value();
const auto outcome = solver::libsolv::Solver().solve(db, request).value();
REQUIRE(std::holds_alternative<solver::Solution>(outcome));
}
@ -375,7 +376,7 @@ namespace
auto create_pytorch_cpu(Context& ctx, ChannelContext& channel_context)
{
return std::pair(
create_conda_forge_pool(ctx, channel_context),
create_conda_forge_database(ctx, channel_context),
Request{
{},
{
@ -389,7 +390,7 @@ namespace
auto create_pytorch_cuda(Context& ctx, ChannelContext& channel_context)
{
return std::pair(
create_conda_forge_pool(
create_conda_forge_database(
ctx,
channel_context,
{ mkpkg("__glibc", "2.17.0"), mkpkg("__cuda", "10.2.0") }
@ -407,7 +408,7 @@ namespace
auto create_cudatoolkit(Context& ctx, ChannelContext& channel_context)
{
return std::pair(
create_conda_forge_pool(
create_conda_forge_database(
ctx,
channel_context,
{ mkpkg("__glibc", "2.17.0"), mkpkg("__cuda", "11.1") }
@ -428,7 +429,7 @@ namespace
auto create_jpeg9b(Context& ctx, ChannelContext& channel_context)
{
return std::pair(
create_conda_forge_pool(ctx, channel_context),
create_conda_forge_database(ctx, channel_context),
Request{
{},
{
@ -442,7 +443,7 @@ namespace
auto create_r_base(Context& ctx, ChannelContext& channel_context)
{
return std::pair(
create_conda_forge_pool(ctx, channel_context),
create_conda_forge_database(ctx, channel_context),
Request{
{},
{
@ -459,7 +460,7 @@ namespace
auto create_scip(Context& ctx, ChannelContext& channel_context)
{
return std::pair(
create_conda_forge_pool(ctx, channel_context),
create_conda_forge_database(ctx, channel_context),
Request{
{},
{
@ -473,7 +474,7 @@ namespace
auto create_double_python(Context& ctx, ChannelContext& channel_context)
{
return std::pair(
create_conda_forge_pool(ctx, channel_context),
create_conda_forge_database(ctx, channel_context),
Request{
{},
{
@ -487,7 +488,7 @@ namespace
auto create_numba(Context& ctx, ChannelContext& channel_context)
{
return std::pair(
create_conda_forge_pool(ctx, channel_context),
create_conda_forge_database(ctx, channel_context),
Request{
{},
{
@ -583,11 +584,11 @@ TEST_CASE("Create problem graph")
// Somehow the capture does not work directly on ``name``
std::string_view name_copy = name;
CAPTURE(name_copy);
auto [pool, request] = factory(ctx, channel_context);
auto outcome = solver::libsolv::Solver().solve(pool, request).value();
auto [db, request] = factory(ctx, channel_context);
auto outcome = solver::libsolv::Solver().solve(db, request).value();
// REQUIRE(std::holds_alternative<solver::libsolv::UnSolvable>(outcome));
auto& unsolvable = std::get<solver::libsolv::UnSolvable>(outcome);
const auto pbs_init = unsolvable.problems_graph(pool);
const auto pbs_init = unsolvable.problems_graph(db);
const auto& graph_init = pbs_init.graph();
REQUIRE_GE(graph_init.number_of_nodes(), 1);

View File

@ -23,14 +23,15 @@
#include "mamba/core/download_progress_bar.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/package_database_loader.hpp"
#include "mamba/core/package_handling.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/core/prefix_data.hpp"
#include "mamba/core/query.hpp"
#include "mamba/core/subdirdata.hpp"
#include "mamba/core/transaction.hpp"
#include "mamba/core/util_os.hpp"
#include "mamba/core/virtual_packages.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
#include "mamba/solver/problems_graph.hpp"
#include "mamba/validation/tools.hpp"
@ -379,12 +380,16 @@ bind_submodule_impl(pybind11::module_ m)
py::add_ostream_redirect(m, "ostream_redirect");
py::class_<MPool>(m, "Pool")
py::class_<solver::libsolv::Database>(m, "Pool")
.def(py::init<specs::ChannelResolveParams>(), py::arg("channel_params"))
.def("set_logger", &MPool::set_logger, py::call_guard<py::gil_scoped_acquire>())
.def(
"set_logger",
&solver::libsolv::Database::set_logger,
py::call_guard<py::gil_scoped_acquire>()
)
.def(
"add_repo_from_repodata_json",
&MPool::add_repo_from_repodata_json,
&solver::libsolv::Database::add_repo_from_repodata_json,
py::arg("path"),
py::arg("url"),
py::arg("add_pip_as_python_dependency") = solver::libsolv::PipAsPythonDependency::No,
@ -393,14 +398,14 @@ bind_submodule_impl(pybind11::module_ m)
)
.def(
"add_repo_from_native_serialization",
&MPool::add_repo_from_native_serialization,
&solver::libsolv::Database::add_repo_from_native_serialization,
py::arg("path"),
py::arg("expected"),
py::arg("add_pip_as_python_dependency") = solver::libsolv::PipAsPythonDependency::No
)
.def(
"add_repo_from_packages",
[](MPool& pool,
[](solver::libsolv::Database& db,
py::iterable packages,
std::string_view name,
solver::libsolv::PipAsPythonDependency add)
@ -411,7 +416,7 @@ bind_submodule_impl(pybind11::module_ m)
{
pkg_infos.push_back(pkg.cast<specs::PackageInfo>());
}
return pool.add_repo_from_packages(pkg_infos, name, add);
return db.add_repo_from_packages(pkg_infos, name, add);
},
py::arg("packages"),
py::arg("name") = "",
@ -419,17 +424,22 @@ bind_submodule_impl(pybind11::module_ m)
)
.def(
"native_serialize_repo",
&MPool::native_serialize_repo,
&solver::libsolv::Database::native_serialize_repo,
py::arg("repo"),
py::arg("path"),
py::arg("metadata")
)
.def("set_installed_repo", &MPool::set_installed_repo, py::arg("repo"))
.def("set_repo_priority", &MPool::set_repo_priority, py::arg("repo"), py::arg("priorities"));
.def("set_installed_repo", &solver::libsolv::Database::set_installed_repo, py::arg("repo"))
.def(
"set_repo_priority",
&solver::libsolv::Database::set_repo_priority,
py::arg("repo"),
py::arg("priorities")
);
m.def(
"load_subdir_in_pool",
&load_subdir_in_pool,
&load_subdir_in_database,
py::arg("context"),
py::arg("pool"),
py::arg("subdir")
@ -437,7 +447,7 @@ bind_submodule_impl(pybind11::module_ m)
m.def(
"load_installed_packages_in_pool",
&load_installed_packages_in_pool,
&load_installed_packages_in_database,
py::arg("context"),
py::arg("pool"),
py::arg("prefix_data")
@ -457,7 +467,7 @@ bind_submodule_impl(pybind11::module_ m)
.def_property_readonly("first_writable_path", &MultiPackageCache::first_writable_path);
py::class_<MTransaction>(m, "Transaction")
.def(py::init<const Context&, MPool&, const solver::Request&, solver::Solution, MultiPackageCache&>(
.def(py::init<const Context&, solver::libsolv::Database&, const solver::Request&, solver::Solution, MultiPackageCache&>(
))
.def("to_conda", &MTransaction::to_conda)
.def("log_json", &MTransaction::log_json)
@ -522,10 +532,10 @@ bind_submodule_impl(pybind11::module_ m)
py::class_<SubdirData>(m, "SubdirData")
.def(
"create_repo",
[](SubdirData& subdir, MPool& pool) -> solver::libsolv::RepoInfo
[](SubdirData& subdir, solver::libsolv::Database& db) -> solver::libsolv::RepoInfo
{
deprecated("Use `load_subdir_in_pool` instead", "2.0");
return extract(load_subdir_in_pool(mambapy::singletons.context(), pool, subdir));
return extract(load_subdir_in_database(mambapy::singletons.context(), db, subdir));
}
)
.def("loaded", &SubdirData::is_loaded)

View File

@ -8,7 +8,7 @@
#include <pybind11/pybind11.h>
#include "mamba/core/palette.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/solver/libsolv/database.hpp"
#include "mamba/solver/libsolv/parameters.hpp"
#include "mamba/solver/libsolv/repo_info.hpp"
#include "mamba/solver/libsolv/solver.hpp"
@ -125,8 +125,8 @@ namespace mambapy
.def(py::init())
.def(
"solve",
[](Solver& self, MPool& pool, const solver::Request& request)
{ return self.solve(pool, request); }
[](Solver& self, Database& db, const solver::Request& request)
{ return self.solve(db, request); }
)
.def("add_jobs", solver_job_v2_migrator)
.def("add_global_job", solver_job_v2_migrator)

View File

@ -31,7 +31,7 @@
using namespace mamba;
MPool
Database
load_pool(
const std::vector<std::string>& channels,
MultiPackageCache& package_caches,
@ -40,7 +40,7 @@ load_pool(
)
{
ctx.channels = channels;
mamba::MPool pool{ ctx, channel_context };
mamba::Database pool{ ctx, channel_context };
auto exp_load = load_channels(ctx, pool, package_caches, false);
if (!exp_load)
{
@ -59,7 +59,7 @@ handle_solve_request(
{
struct cache
{
std::optional<mamba::MPool> pool;
std::optional<mamba::Database> pool;
std::chrono::time_point<std::chrono::system_clock> last_update;
};

View File

@ -13,6 +13,7 @@
#include "mamba/api/update.hpp"
#include "mamba/core/channel_context.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/package_database_loader.hpp"
#include "mamba/core/transaction.hpp"
#include "mamba/core/util_os.hpp"
#include "mamba/util/build.hpp"
@ -28,10 +29,10 @@ using namespace mamba; // NOLINT(build/namespaces)
namespace
{
auto pool_has_package(MPool& pool, specs::MatchSpec spec) -> bool
auto database_has_package(solver::libsolv::Database& database, specs::MatchSpec spec) -> bool
{
bool found = false;
pool.for_each_package_matching(
database.for_each_package_matching(
spec,
[&](const auto&)
{
@ -42,10 +43,11 @@ namespace
return found;
};
auto pool_latest_package(MPool& pool, specs::MatchSpec spec) -> std::optional<specs::PackageInfo>
auto database_latest_package(solver::libsolv::Database& db, specs::MatchSpec spec)
-> std::optional<specs::PackageInfo>
{
auto out = std::optional<specs::PackageInfo>();
pool.for_each_package_matching(
db.for_each_package_matching(
spec,
[&](auto pkg)
{
@ -72,12 +74,12 @@ update_self(Configuration& config, const std::optional<std::string>& version)
auto channel_context = ChannelContext::make_conda_compatible(ctx);
MPool pool{ channel_context.params() };
add_spdlog_logger_to_pool(pool);
solver::libsolv::Database db{ channel_context.params() };
add_spdlog_logger_to_database(db);
mamba::MultiPackageCache package_caches(ctx.pkgs_dirs, ctx.validation_params);
auto exp_loaded = load_channels(ctx, channel_context, pool, package_caches);
auto exp_loaded = load_channels(ctx, channel_context, db, package_caches);
if (!exp_loaded)
{
throw exp_loaded.error();
@ -88,11 +90,11 @@ update_self(Configuration& config, const std::optional<std::string>& version)
: fmt::format("micromamba>{}", umamba::version())
);
auto latest_micromamba = pool_latest_package(pool, matchspec);
auto latest_micromamba = database_latest_package(db, matchspec);
if (!latest_micromamba.has_value())
{
if (pool_has_package(pool, specs::MatchSpec::parse("micromamba")))
if (database_has_package(db, specs::MatchSpec::parse("micromamba")))
{
Console::instance().print(
fmt::format("\nYour micromamba version ({}) is already up to date.", umamba::version())
@ -120,7 +122,7 @@ update_self(Configuration& config, const std::optional<std::string>& version)
);
ctx.download_only = true;
MTransaction t(ctx, pool, { latest_micromamba.value() }, package_caches);
MTransaction t(ctx, db, { latest_micromamba.value() }, package_caches);
auto exp_prefix_data = PrefixData::create(ctx.prefix_params.root_prefix, channel_context);
if (!exp_prefix_data)
{

View File

@ -756,7 +756,7 @@ def test_channel_nodefaults(tmp_home, tmp_root_prefix, tmp_path):
def test_pin_applicable(tmp_home, tmp_root_prefix, tmp_path):
pin_name = "xtensor"
pin_max_version = "0.20"
# We add the channel to test a fragile behavior of ``MPool``
# We add the channel to test a fragile behavior of ``Database``
spec_name = "conda-forge::xtensor"
rc_file = tmp_path / "rc.yaml"