mirror of https://github.com/mamba-org/mamba.git
parent
a182b1d453
commit
551540ba0a
|
@ -4,6 +4,7 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -12,11 +13,30 @@
|
|||
|
||||
namespace mamba
|
||||
{
|
||||
bool repoquery(
|
||||
enum class QueryResultFormat
|
||||
{
|
||||
Json = 0,
|
||||
Tree = 1,
|
||||
Table = 2,
|
||||
Pretty = 3,
|
||||
RecursiveTable = 4,
|
||||
};
|
||||
|
||||
[[nodiscard]] auto make_repoquery(
|
||||
MPool& pool,
|
||||
QueryType type,
|
||||
QueryResultFormat format,
|
||||
const std::vector<std::string>& queries,
|
||||
bool show_all_builds,
|
||||
const Context::GraphicsParams& graphics_params,
|
||||
std::ostream& out
|
||||
) -> bool;
|
||||
|
||||
[[nodiscard]] auto repoquery(
|
||||
Configuration& config,
|
||||
QueryType type,
|
||||
QueryResultFormat format,
|
||||
bool use_local,
|
||||
const std::vector<std::string>& query
|
||||
);
|
||||
) -> bool;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef MAMBA_CORE_QUERY_HPP
|
||||
#define MAMBA_CORE_QUERY_HPP
|
||||
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
@ -17,39 +18,8 @@
|
|||
#include "mamba/specs/package_info.hpp"
|
||||
#include "mamba/util/graph.hpp"
|
||||
|
||||
typedef struct s_Solvable Solvable;
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
using GraphicsParams = Context::GraphicsParams;
|
||||
|
||||
void print_dep_graph(
|
||||
std::ostream& out,
|
||||
Solvable* s,
|
||||
const std::string& solv_str,
|
||||
int level,
|
||||
int max_level,
|
||||
bool last,
|
||||
const std::string& prefix
|
||||
);
|
||||
|
||||
class query_result;
|
||||
|
||||
class Query
|
||||
{
|
||||
public:
|
||||
|
||||
Query(MPool& pool);
|
||||
|
||||
query_result find(const std::vector<std::string>& queries) const;
|
||||
query_result whoneeds(const std::string& query, bool tree) const;
|
||||
query_result depends(const std::string& query, bool tree) const;
|
||||
|
||||
private:
|
||||
|
||||
std::reference_wrapper<MPool> m_pool;
|
||||
};
|
||||
|
||||
enum class QueryType
|
||||
{
|
||||
Search,
|
||||
|
@ -58,47 +28,46 @@ namespace mamba
|
|||
};
|
||||
|
||||
constexpr auto enum_name(QueryType t) -> std::string_view;
|
||||
auto QueryType_from_name(std::string_view name) -> QueryType;
|
||||
|
||||
enum class QueryResultFormat
|
||||
{
|
||||
Json = 0,
|
||||
Tree = 1,
|
||||
Table = 2,
|
||||
Pretty = 3,
|
||||
RecursiveTable = 4,
|
||||
};
|
||||
auto query_type_parse(std::string_view name) -> QueryType;
|
||||
|
||||
class query_result
|
||||
class QueryResult
|
||||
{
|
||||
public:
|
||||
|
||||
using GraphicsParams = Context::GraphicsParams;
|
||||
using dependency_graph = util::DiGraph<specs::PackageInfo>;
|
||||
|
||||
query_result(QueryType type, const std::string& query, dependency_graph&& dep_graph);
|
||||
QueryResult(QueryType type, std::string query, dependency_graph dep_graph);
|
||||
QueryResult(const QueryResult&) = default;
|
||||
QueryResult(QueryResult&&) = default;
|
||||
|
||||
~query_result() = default;
|
||||
~QueryResult() = default;
|
||||
|
||||
query_result(const query_result&) = default;
|
||||
query_result& operator=(const query_result&) = default;
|
||||
query_result(query_result&&) = default;
|
||||
query_result& operator=(query_result&&) = default;
|
||||
auto operator=(const QueryResult&) -> QueryResult& = default;
|
||||
auto operator=(QueryResult&&) -> QueryResult& = default;
|
||||
|
||||
QueryType query_type() const;
|
||||
const std::string& query() const;
|
||||
[[nodiscard]] auto type() const -> QueryType;
|
||||
[[nodiscard]] auto query() const -> const std::string&;
|
||||
[[nodiscard]] auto empty() const -> bool;
|
||||
|
||||
query_result& sort(std::string_view field);
|
||||
query_result& groupby(std::string_view field);
|
||||
query_result& reset();
|
||||
auto sort(std::string_view field) -> QueryResult&;
|
||||
|
||||
std::ostream& table(std::ostream&) const;
|
||||
std::ostream& table(std::ostream&, const std::vector<std::string_view>& fmt) const;
|
||||
std::ostream& tree(std::ostream&, const GraphicsParams& graphics) const;
|
||||
nlohmann::json json() const;
|
||||
auto groupby(std::string_view field) -> QueryResult&;
|
||||
|
||||
std::ostream& pretty(std::ostream&, const Context::OutputParams& outputParams) const;
|
||||
auto reset() -> QueryResult&;
|
||||
|
||||
bool empty() const;
|
||||
auto table(std::ostream&) const -> std::ostream&;
|
||||
auto table(std::ostream&, const std::vector<std::string_view>& fmt) const -> std::ostream&;
|
||||
[[nodiscard]] auto table_to_str() const -> std::string;
|
||||
|
||||
auto tree(std::ostream&, const GraphicsParams& graphics) const -> std::ostream&;
|
||||
[[nodiscard]] auto tree_to_str(const GraphicsParams& graphics) const -> std::string;
|
||||
|
||||
[[nodiscard]] auto json() const -> nlohmann::json;
|
||||
|
||||
auto pretty(std::ostream&, bool show_all_builds) const -> std::ostream&;
|
||||
[[nodiscard]] auto pretty_to_str(bool show_all_builds) const -> std::string;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -107,7 +76,6 @@ namespace mamba
|
|||
using ordered_package_list = std::map<std::string, package_id_list>;
|
||||
|
||||
void reset_pkg_view_list();
|
||||
std::string get_package_repr(const specs::PackageInfo& pkg) const;
|
||||
|
||||
QueryType m_type;
|
||||
std::string m_query;
|
||||
|
@ -116,6 +84,20 @@ namespace mamba
|
|||
ordered_package_list m_ordered_pkg_id_list = {};
|
||||
};
|
||||
|
||||
class Query
|
||||
{
|
||||
public:
|
||||
|
||||
[[nodiscard]] static auto find(MPool& pool, const std::vector<std::string>& queries)
|
||||
-> QueryResult;
|
||||
|
||||
[[nodiscard]] static auto whoneeds(MPool& pool, const std::string& query, bool tree)
|
||||
-> QueryResult;
|
||||
|
||||
[[nodiscard]] static auto depends(MPool& pool, const std::string& query, bool tree)
|
||||
-> QueryResult;
|
||||
};
|
||||
|
||||
/********************
|
||||
* Implementation *
|
||||
********************/
|
||||
|
@ -133,7 +115,5 @@ namespace mamba
|
|||
}
|
||||
throw std::invalid_argument("Invalid enum value");
|
||||
}
|
||||
|
||||
} // namespace mamba
|
||||
|
||||
#endif // MAMBA_QUERY_HPP
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -72,36 +72,34 @@ namespace mamba
|
|||
throw std::runtime_error(exp_load.error().what());
|
||||
}
|
||||
}
|
||||
pool.create_whatprovides();
|
||||
return pool;
|
||||
}
|
||||
}
|
||||
|
||||
bool repoquery(
|
||||
Configuration& config,
|
||||
auto make_repoquery(
|
||||
MPool& pool,
|
||||
QueryType type,
|
||||
QueryResultFormat format,
|
||||
bool use_local,
|
||||
const std::vector<std::string>& queries
|
||||
)
|
||||
const std::vector<std::string>& queries,
|
||||
bool show_all_builds,
|
||||
const Context::GraphicsParams& graphics_params,
|
||||
std::ostream& out
|
||||
) -> bool
|
||||
{
|
||||
auto& ctx = config.context();
|
||||
auto pool = repoquery_init(ctx, config, format, use_local);
|
||||
Query q(pool);
|
||||
|
||||
|
||||
if (type == QueryType::Search)
|
||||
{
|
||||
auto res = q.find(queries);
|
||||
auto res = Query::find(pool, queries);
|
||||
switch (format)
|
||||
{
|
||||
case QueryResultFormat::Json:
|
||||
std::cout << res.groupby("name").json().dump(4);
|
||||
out << res.groupby("name").json().dump(4);
|
||||
break;
|
||||
case QueryResultFormat::Pretty:
|
||||
res.pretty(std::cout, ctx.output_params);
|
||||
res.pretty(out, show_all_builds);
|
||||
break;
|
||||
default:
|
||||
res.groupby("name").table(std::cout);
|
||||
res.groupby("name").table(out);
|
||||
}
|
||||
return !res.empty();
|
||||
}
|
||||
|
@ -111,22 +109,24 @@ namespace mamba
|
|||
{
|
||||
throw std::invalid_argument("Only one query supported for 'depends'.");
|
||||
}
|
||||
auto res = q.depends(
|
||||
auto res = Query::depends(
|
||||
pool,
|
||||
queries.front(),
|
||||
format == QueryResultFormat::Tree || format == QueryResultFormat::RecursiveTable
|
||||
/* tree= */ format == QueryResultFormat::Tree
|
||||
|| format == QueryResultFormat::RecursiveTable
|
||||
);
|
||||
switch (format)
|
||||
{
|
||||
case QueryResultFormat::Tree:
|
||||
case QueryResultFormat::Pretty:
|
||||
res.tree(std::cout, config.context().graphics_params);
|
||||
res.tree(out, graphics_params);
|
||||
break;
|
||||
case QueryResultFormat::Json:
|
||||
std::cout << res.json().dump(4);
|
||||
out << res.json().dump(4);
|
||||
break;
|
||||
case QueryResultFormat::Table:
|
||||
case QueryResultFormat::RecursiveTable:
|
||||
res.sort("name").table(std::cout);
|
||||
res.sort("name").table(out);
|
||||
}
|
||||
return !res.empty();
|
||||
}
|
||||
|
@ -136,23 +136,25 @@ namespace mamba
|
|||
{
|
||||
throw std::invalid_argument("Only one query supported for 'whoneeds'.");
|
||||
}
|
||||
auto res = q.whoneeds(
|
||||
auto res = Query::whoneeds(
|
||||
pool,
|
||||
queries.front(),
|
||||
format == QueryResultFormat::Tree || format == QueryResultFormat::RecursiveTable
|
||||
/* tree= */ format == QueryResultFormat::Tree
|
||||
|| format == QueryResultFormat::RecursiveTable
|
||||
);
|
||||
switch (format)
|
||||
{
|
||||
case QueryResultFormat::Tree:
|
||||
case QueryResultFormat::Pretty:
|
||||
res.tree(std::cout, config.context().graphics_params);
|
||||
res.tree(out, graphics_params);
|
||||
break;
|
||||
case QueryResultFormat::Json:
|
||||
std::cout << res.json().dump(4);
|
||||
out << res.json().dump(4);
|
||||
break;
|
||||
case QueryResultFormat::Table:
|
||||
case QueryResultFormat::RecursiveTable:
|
||||
res.sort("name").table(
|
||||
std::cout,
|
||||
out,
|
||||
{ "Name",
|
||||
"Version",
|
||||
"Build",
|
||||
|
@ -165,5 +167,28 @@ namespace mamba
|
|||
}
|
||||
return !res.empty();
|
||||
}
|
||||
throw std::invalid_argument("Invalid QueryType");
|
||||
}
|
||||
|
||||
bool repoquery(
|
||||
Configuration& config,
|
||||
QueryType type,
|
||||
QueryResultFormat format,
|
||||
bool use_local,
|
||||
const std::vector<std::string>& queries
|
||||
)
|
||||
{
|
||||
auto& ctx = config.context();
|
||||
auto pool = repoquery_init(ctx, config, format, use_local);
|
||||
return make_repoquery(
|
||||
pool,
|
||||
type,
|
||||
format,
|
||||
queries,
|
||||
ctx.output_params.verbosity > 0,
|
||||
ctx.graphics_params,
|
||||
std::cout
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,10 +36,16 @@ namespace mamba
|
|||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
auto get_package_repr(const specs::PackageInfo& pkg) -> std::string
|
||||
{
|
||||
return pkg.version.empty() ? pkg.name : fmt::format("{}[{}]", pkg.name, pkg.version);
|
||||
}
|
||||
|
||||
void walk_graph(
|
||||
MPool pool,
|
||||
query_result::dependency_graph& dep_graph,
|
||||
query_result::dependency_graph::node_id parent,
|
||||
QueryResult::dependency_graph& dep_graph,
|
||||
QueryResult::dependency_graph::node_id parent,
|
||||
Solvable* s,
|
||||
std::map<Solvable*, size_t>& visited,
|
||||
std::map<std::string, size_t>& not_found,
|
||||
|
@ -115,8 +121,8 @@ namespace mamba
|
|||
|
||||
void reverse_walk_graph(
|
||||
MPool& pool,
|
||||
query_result::dependency_graph& dep_graph,
|
||||
query_result::dependency_graph::node_id parent,
|
||||
QueryResult::dependency_graph& dep_graph,
|
||||
QueryResult::dependency_graph::node_id parent,
|
||||
Solvable* s,
|
||||
std::map<Solvable*, size_t>& visited
|
||||
)
|
||||
|
@ -157,15 +163,8 @@ namespace mamba
|
|||
* Query implementation *
|
||||
************************/
|
||||
|
||||
Query::Query(MPool& pool)
|
||||
: m_pool(pool)
|
||||
{
|
||||
m_pool.get().create_whatprovides();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* Prints metadata for a given package.
|
||||
*/
|
||||
|
@ -354,13 +353,13 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
query_result Query::find(const std::vector<std::string>& queries) const
|
||||
auto Query::find(MPool& mpool, const std::vector<std::string>& queries) -> QueryResult
|
||||
{
|
||||
solv::ObjQueue job, solvables;
|
||||
|
||||
for (const auto& query : queries)
|
||||
{
|
||||
const Id id = pool_conda_matchspec(m_pool.get(), query.c_str());
|
||||
const Id id = pool_conda_matchspec(mpool, query.c_str());
|
||||
if (!id)
|
||||
{
|
||||
throw std::runtime_error("Could not generate query for " + query);
|
||||
|
@ -368,10 +367,10 @@ namespace mamba
|
|||
job.push_back(SOLVER_SOLVABLE_PROVIDES, id);
|
||||
}
|
||||
|
||||
selection_solvables(m_pool.get(), job.raw(), solvables.raw());
|
||||
query_result::dependency_graph g;
|
||||
selection_solvables(mpool, job.raw(), solvables.raw());
|
||||
QueryResult::dependency_graph g;
|
||||
|
||||
Pool* pool = m_pool.get();
|
||||
Pool* pool = mpool;
|
||||
std::sort(
|
||||
solvables.begin(),
|
||||
solvables.end(),
|
||||
|
@ -387,80 +386,78 @@ namespace mamba
|
|||
|
||||
for (auto& el : solvables)
|
||||
{
|
||||
auto pkg_info = m_pool.get().id2pkginfo(el);
|
||||
auto pkg_info = mpool.id2pkginfo(el);
|
||||
assert(pkg_info.has_value());
|
||||
g.add_node(std::move(pkg_info).value());
|
||||
}
|
||||
|
||||
return query_result(
|
||||
QueryType::Search,
|
||||
fmt::format("{}", fmt::join(queries, " ")), // Yes this is disgusting
|
||||
std::move(g)
|
||||
);
|
||||
return { QueryType::Search,
|
||||
fmt::format("{}", fmt::join(queries, " ")), // Yes this is disgusting
|
||||
std::move(g) };
|
||||
}
|
||||
|
||||
query_result Query::whoneeds(const std::string& query, bool tree) const
|
||||
auto Query::whoneeds(MPool& mpool, const std::string& query, bool tree) -> QueryResult
|
||||
{
|
||||
const Id id = pool_conda_matchspec(m_pool.get(), query.c_str());
|
||||
const Id id = pool_conda_matchspec(mpool, query.c_str());
|
||||
if (!id)
|
||||
{
|
||||
throw std::runtime_error("Could not generate query for " + query);
|
||||
}
|
||||
|
||||
solv::ObjQueue job = { SOLVER_SOLVABLE_PROVIDES, id };
|
||||
query_result::dependency_graph g;
|
||||
QueryResult::dependency_graph g;
|
||||
|
||||
if (tree)
|
||||
{
|
||||
solv::ObjQueue solvables = {};
|
||||
selection_solvables(m_pool.get(), job.raw(), solvables.raw());
|
||||
selection_solvables(mpool, job.raw(), solvables.raw());
|
||||
if (!solvables.empty())
|
||||
{
|
||||
auto pkg_info = m_pool.get().id2pkginfo(solvables.front());
|
||||
auto pkg_info = mpool.id2pkginfo(solvables.front());
|
||||
assert(pkg_info.has_value());
|
||||
const auto node_id = g.add_node(std::move(pkg_info).value());
|
||||
Solvable* const latest = pool_id2solvable(m_pool.get(), solvables.front());
|
||||
Solvable* const latest = pool_id2solvable(mpool, solvables.front());
|
||||
std::map<Solvable*, size_t> visited = { { latest, node_id } };
|
||||
reverse_walk_graph(m_pool, g, node_id, latest, visited);
|
||||
reverse_walk_graph(mpool, g, node_id, latest, visited);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
solv::ObjQueue solvables = {};
|
||||
pool_whatmatchesdep(m_pool.get(), SOLVABLE_REQUIRES, id, solvables.raw(), -1);
|
||||
pool_whatmatchesdep(mpool, SOLVABLE_REQUIRES, id, solvables.raw(), -1);
|
||||
for (auto& el : solvables)
|
||||
{
|
||||
auto pkg_info = m_pool.get().id2pkginfo(el);
|
||||
auto pkg_info = mpool.id2pkginfo(el);
|
||||
assert(pkg_info.has_value());
|
||||
g.add_node(std::move(pkg_info).value());
|
||||
}
|
||||
}
|
||||
return query_result(QueryType::WhoNeeds, query, std::move(g));
|
||||
return { QueryType::WhoNeeds, query, std::move(g) };
|
||||
}
|
||||
|
||||
query_result Query::depends(const std::string& query, bool tree) const
|
||||
auto Query::depends(MPool& mpool, const std::string& query, bool tree) -> QueryResult
|
||||
{
|
||||
solv::ObjQueue job, solvables;
|
||||
|
||||
const Id id = pool_conda_matchspec(m_pool.get(), query.c_str());
|
||||
const Id id = pool_conda_matchspec(mpool, query.c_str());
|
||||
if (!id)
|
||||
{
|
||||
throw std::runtime_error("Could not generate query for " + query);
|
||||
}
|
||||
job.push_back(SOLVER_SOLVABLE_PROVIDES, id);
|
||||
|
||||
query_result::dependency_graph g;
|
||||
selection_solvables(m_pool.get(), job.raw(), solvables.raw());
|
||||
QueryResult::dependency_graph g;
|
||||
selection_solvables(mpool, job.raw(), solvables.raw());
|
||||
|
||||
int depth = tree ? -1 : 1;
|
||||
|
||||
auto find_latest_in_non_empty = [&](solv::ObjQueue& lsolvables) -> Solvable*
|
||||
{
|
||||
::Solvable* latest = pool_id2solvable(m_pool.get(), lsolvables.front());
|
||||
::Solvable* latest = pool_id2solvable(mpool, lsolvables.front());
|
||||
for (Id const solv : solvables)
|
||||
{
|
||||
Solvable* s = pool_id2solvable(m_pool.get(), solv);
|
||||
if (pool_evrcmp(m_pool.get(), s->evr, latest->evr, 0) > 0)
|
||||
Solvable* s = pool_id2solvable(mpool, solv);
|
||||
if (pool_evrcmp(mpool, s->evr, latest->evr, 0) > 0)
|
||||
{
|
||||
latest = s;
|
||||
}
|
||||
|
@ -471,23 +468,23 @@ namespace mamba
|
|||
if (!solvables.empty())
|
||||
{
|
||||
::Solvable* const latest = find_latest_in_non_empty(solvables);
|
||||
auto pkg_info = m_pool.get().id2pkginfo(pool_solvable2id(m_pool.get(), latest));
|
||||
auto pkg_info = mpool.id2pkginfo(pool_solvable2id(mpool, latest));
|
||||
assert(pkg_info.has_value());
|
||||
const auto node_id = g.add_node(std::move(pkg_info).value());
|
||||
|
||||
std::map<Solvable*, size_t> visited = { { latest, node_id } };
|
||||
std::map<std::string, size_t> not_found;
|
||||
walk_graph(m_pool, g, node_id, latest, visited, not_found, depth);
|
||||
walk_graph(mpool, g, node_id, latest, visited, not_found, depth);
|
||||
}
|
||||
|
||||
return query_result(QueryType::Depends, query, std::move(g));
|
||||
return { QueryType::Depends, query, std::move(g) };
|
||||
}
|
||||
|
||||
/******************************
|
||||
* QueryType implementation *
|
||||
******************************/
|
||||
|
||||
auto QueryType_from_name(std::string_view name) -> QueryType
|
||||
auto query_type_parse(std::string_view name) -> QueryType
|
||||
{
|
||||
auto l_name = util::to_lower(name);
|
||||
if (l_name == "search")
|
||||
|
@ -509,25 +506,25 @@ namespace mamba
|
|||
* query_result implementation *
|
||||
*******************************/
|
||||
|
||||
query_result::query_result(QueryType type, const std::string& query, dependency_graph&& dep_graph)
|
||||
QueryResult::QueryResult(QueryType type, std::string query, dependency_graph dep_graph)
|
||||
: m_type(type)
|
||||
, m_query(query)
|
||||
, m_query(std::move(query))
|
||||
, m_dep_graph(std::move(dep_graph))
|
||||
{
|
||||
reset_pkg_view_list();
|
||||
}
|
||||
|
||||
QueryType query_result::query_type() const
|
||||
auto QueryResult::type() const -> QueryType
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
const std::string& query_result::query() const
|
||||
auto QueryResult::query() const -> const std::string&
|
||||
{
|
||||
return m_query;
|
||||
}
|
||||
|
||||
query_result& query_result::sort(std::string_view field)
|
||||
auto QueryResult::sort(std::string_view field) -> QueryResult&
|
||||
{
|
||||
auto compare_ids = [&](node_id lhs, node_id rhs)
|
||||
{ return m_dep_graph.node(lhs).field(field) < m_dep_graph.node(rhs).field(field); };
|
||||
|
@ -547,7 +544,7 @@ namespace mamba
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_result& query_result::groupby(std::string_view field)
|
||||
auto QueryResult::groupby(std::string_view field) -> QueryResult&
|
||||
{
|
||||
if (m_ordered_pkg_id_list.empty())
|
||||
{
|
||||
|
@ -572,14 +569,14 @@ namespace mamba
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_result& query_result::reset()
|
||||
auto QueryResult::reset() -> QueryResult&
|
||||
{
|
||||
reset_pkg_view_list();
|
||||
m_ordered_pkg_id_list.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::ostream& query_result::table(std::ostream& out) const
|
||||
auto QueryResult::table(std::ostream& out) const -> std::ostream&
|
||||
{
|
||||
return table(
|
||||
out,
|
||||
|
@ -593,6 +590,13 @@ namespace mamba
|
|||
);
|
||||
}
|
||||
|
||||
auto QueryResult::table_to_str() const -> std::string
|
||||
{
|
||||
auto ss = std::stringstream();
|
||||
table(ss);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
/** Remove potential subdir from channel name (not url!). */
|
||||
|
@ -609,8 +613,8 @@ namespace mamba
|
|||
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
query_result::table(std::ostream& out, const std::vector<std::string_view>& columns) const
|
||||
auto QueryResult::table(std::ostream& out, const std::vector<std::string_view>& columns) const
|
||||
-> std::ostream&
|
||||
{
|
||||
if (m_pkg_id_list.empty())
|
||||
{
|
||||
|
@ -626,9 +630,9 @@ namespace mamba
|
|||
|| col == printers::alignmentMarker(printers::alignment::left))
|
||||
{
|
||||
// If an alignment marker is passed, we remove the column name.
|
||||
headers.push_back("");
|
||||
cmds.push_back("");
|
||||
args.push_back("");
|
||||
headers.emplace_back("");
|
||||
cmds.emplace_back("");
|
||||
args.emplace_back("");
|
||||
// We only check for the right alignment marker, as left alignment is set the
|
||||
// default.
|
||||
if (col == printers::alignmentMarker(printers::alignment::right))
|
||||
|
@ -639,14 +643,14 @@ namespace mamba
|
|||
}
|
||||
else if (col.find_first_of(":") == col.npos)
|
||||
{
|
||||
headers.push_back(col);
|
||||
headers.emplace_back(col);
|
||||
cmds.push_back(col);
|
||||
args.push_back("");
|
||||
args.emplace_back("");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto sfmt = util::split(col, ":", 1);
|
||||
headers.push_back(sfmt[0]);
|
||||
headers.emplace_back(sfmt[0]);
|
||||
cmds.push_back(sfmt[0]);
|
||||
args.push_back(sfmt[1]);
|
||||
}
|
||||
|
@ -663,33 +667,33 @@ namespace mamba
|
|||
const auto& cmd = cmds[i];
|
||||
if (cmd == "Name")
|
||||
{
|
||||
row.push_back(pkg.name);
|
||||
row.emplace_back(pkg.name);
|
||||
}
|
||||
else if (cmd == "Version")
|
||||
{
|
||||
row.push_back(pkg.version);
|
||||
row.emplace_back(pkg.version);
|
||||
}
|
||||
else if (cmd == "Build")
|
||||
{
|
||||
row.push_back(pkg.build_string);
|
||||
row.emplace_back(pkg.build_string);
|
||||
if (builds.size() > 1)
|
||||
{
|
||||
row.push_back("(+");
|
||||
row.push_back(fmt::format("{} builds)", builds.size() - 1));
|
||||
row.emplace_back("(+");
|
||||
row.emplace_back(fmt::format("{} builds)", builds.size() - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
row.push_back("");
|
||||
row.push_back("");
|
||||
row.emplace_back("");
|
||||
row.emplace_back("");
|
||||
}
|
||||
}
|
||||
else if (cmd == "Channel")
|
||||
{
|
||||
row.push_back(cut_subdir(cut_repo_name(pkg.channel)));
|
||||
row.emplace_back(cut_subdir(cut_repo_name(pkg.channel)));
|
||||
}
|
||||
else if (cmd == "Subdir")
|
||||
{
|
||||
row.push_back(get_subdir(pkg.channel));
|
||||
row.emplace_back(get_subdir(pkg.channel));
|
||||
}
|
||||
else if (cmd == "Depends")
|
||||
{
|
||||
|
@ -702,7 +706,7 @@ namespace mamba
|
|||
break;
|
||||
}
|
||||
}
|
||||
row.push_back(depends_qualifier);
|
||||
row.emplace_back(depends_qualifier);
|
||||
}
|
||||
}
|
||||
return row;
|
||||
|
@ -754,7 +758,7 @@ namespace mamba
|
|||
{
|
||||
public:
|
||||
|
||||
using graph_type = query_result::dependency_graph;
|
||||
using graph_type = QueryResult::dependency_graph;
|
||||
using node_id = graph_type::node_id;
|
||||
|
||||
explicit graph_printer(std::ostream& out, GraphicsParams graphics)
|
||||
|
@ -770,15 +774,15 @@ namespace mamba
|
|||
m_out << get_package_repr(g.node(node)) << '\n';
|
||||
if (node == 0u)
|
||||
{
|
||||
m_prefix_stack.push_back(" ");
|
||||
m_prefix_stack.emplace_back(" ");
|
||||
}
|
||||
else if (is_on_last_stack(node))
|
||||
{
|
||||
m_prefix_stack.push_back(" ");
|
||||
m_prefix_stack.emplace_back(" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_prefix_stack.push_back("│ ");
|
||||
m_prefix_stack.emplace_back("│ ");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -820,7 +824,7 @@ namespace mamba
|
|||
|
||||
private:
|
||||
|
||||
bool is_on_last_stack(node_id node) const
|
||||
[[nodiscard]] auto is_on_last_stack(node_id node) const -> bool
|
||||
{
|
||||
return !m_last_stack.empty() && m_last_stack.top() == node;
|
||||
}
|
||||
|
@ -837,7 +841,7 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
std::string get_package_repr(const specs::PackageInfo& pkg) const
|
||||
[[nodiscard]] auto get_package_repr(const specs::PackageInfo& pkg) const -> std::string
|
||||
{
|
||||
return pkg.version.empty() ? pkg.name : pkg.name + '[' + pkg.version + ']';
|
||||
}
|
||||
|
@ -849,7 +853,7 @@ namespace mamba
|
|||
const GraphicsParams m_graphics;
|
||||
};
|
||||
|
||||
std::ostream& query_result::tree(std::ostream& out, const GraphicsParams& graphics) const
|
||||
auto QueryResult::tree(std::ostream& out, const GraphicsParams& graphics) const -> std::ostream&
|
||||
{
|
||||
bool use_graph = (m_dep_graph.number_of_nodes() > 0) && !m_dep_graph.successors(0).empty();
|
||||
if (use_graph)
|
||||
|
@ -870,7 +874,14 @@ namespace mamba
|
|||
return out;
|
||||
}
|
||||
|
||||
nlohmann::json query_result::json() const
|
||||
auto QueryResult::tree_to_str(const Context::GraphicsParams& params) const -> std::string
|
||||
{
|
||||
auto ss = std::stringstream();
|
||||
tree(ss, params);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
auto QueryResult::json() const -> nlohmann::json
|
||||
{
|
||||
nlohmann::json j;
|
||||
std::string query_type = std::string(util::to_lower(enum_name(m_type)));
|
||||
|
@ -881,9 +892,9 @@ namespace mamba
|
|||
j["result"] = { { "msg", msg }, { "status", "OK" } };
|
||||
|
||||
j["result"]["pkgs"] = nlohmann::json::array();
|
||||
for (size_t i = 0; i < m_pkg_id_list.size(); ++i)
|
||||
for (auto id : m_pkg_id_list)
|
||||
{
|
||||
nlohmann::json pkg_info_json = m_dep_graph.node(m_pkg_id_list[i]);
|
||||
nlohmann::json pkg_info_json = m_dep_graph.node(id);
|
||||
// We want the cannonical channel name here.
|
||||
// We do not know what is in the `channel` field so we need to make sure.
|
||||
// This is most likely legacy and should be updated on the next major release.
|
||||
|
@ -915,8 +926,7 @@ namespace mamba
|
|||
return j;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
query_result::pretty(std::ostream& out, const Context::OutputParams& outputParams) const
|
||||
auto QueryResult::pretty(std::ostream& out, bool show_all_builds) const -> std::ostream&
|
||||
{
|
||||
if (m_pkg_id_list.empty())
|
||||
{
|
||||
|
@ -931,34 +941,35 @@ namespace mamba
|
|||
packages[package.name].push_back(package);
|
||||
}
|
||||
|
||||
auto out = Console::stream();
|
||||
for (const auto& entry : packages)
|
||||
{
|
||||
print_solvable(
|
||||
out,
|
||||
entry.second[0],
|
||||
std::vector(entry.second.begin() + 1, entry.second.end()),
|
||||
outputParams.verbosity > 0
|
||||
show_all_builds
|
||||
);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool query_result::empty() const
|
||||
auto QueryResult::pretty_to_str(bool show_all_builds) const -> std::string
|
||||
{
|
||||
auto ss = std::stringstream();
|
||||
pretty(ss, show_all_builds);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
auto QueryResult::empty() const -> bool
|
||||
{
|
||||
return m_dep_graph.empty();
|
||||
}
|
||||
|
||||
void query_result::reset_pkg_view_list()
|
||||
void QueryResult::reset_pkg_view_list()
|
||||
{
|
||||
m_pkg_id_list.clear();
|
||||
m_pkg_id_list.reserve(m_dep_graph.number_of_nodes());
|
||||
m_dep_graph.for_each_node_id([&](node_id id) { m_pkg_id_list.push_back(id); });
|
||||
}
|
||||
|
||||
std::string query_result::get_package_repr(const specs::PackageInfo& pkg) const
|
||||
{
|
||||
return pkg.version.empty() ? pkg.name : fmt::format("{}[{}]", pkg.name, pkg.version);
|
||||
}
|
||||
} // namespace mamba
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "mamba/api/clean.hpp"
|
||||
#include "mamba/api/configuration.hpp"
|
||||
#include "mamba/api/repoquery.hpp"
|
||||
#include "mamba/core/channel_context.hpp"
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/download_progress_bar.hpp"
|
||||
|
@ -39,21 +40,10 @@
|
|||
#include "bindings.hpp"
|
||||
#include "expected_caster.hpp"
|
||||
#include "flat_set_caster.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
namespace query
|
||||
{
|
||||
enum RESULT_FORMAT
|
||||
{
|
||||
JSON = 0,
|
||||
TREE = 1,
|
||||
TABLE = 2,
|
||||
PRETTY = 3,
|
||||
RECURSIVETABLE = 4,
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
deprecated(std::string_view message, std::string_view since_version = "1.5")
|
||||
{
|
||||
|
@ -499,126 +489,47 @@ bind_submodule_impl(pybind11::module_ m)
|
|||
)
|
||||
.def("get_requested_specs_map", &History::get_requested_specs_map);
|
||||
|
||||
/*py::class_<Query>(m, "Query")
|
||||
.def(py::init<MPool&>())
|
||||
.def("find", &Query::find)
|
||||
.def("whoneeds", &Query::whoneeds)
|
||||
.def("depends", &Query::depends)
|
||||
;*/
|
||||
py::enum_<QueryType>(m, "QueryType")
|
||||
.value("Search", QueryType::Search)
|
||||
.value("Depends", QueryType::Depends)
|
||||
.value("WhoNeeds", QueryType::WhoNeeds)
|
||||
.def(py::init(&mambapy::enum_from_str<QueryType>))
|
||||
.def_static("parse", &query_type_parse);
|
||||
py::implicitly_convertible<py::str, QueryType>();
|
||||
|
||||
py::enum_<query::RESULT_FORMAT>(m, "QueryFormat")
|
||||
.value("JSON", query::RESULT_FORMAT::JSON)
|
||||
.value("TREE", query::RESULT_FORMAT::TREE)
|
||||
.value("TABLE", query::RESULT_FORMAT::TABLE)
|
||||
.value("PRETTY", query::RESULT_FORMAT::PRETTY)
|
||||
.value("RECURSIVETABLE", query::RESULT_FORMAT::RECURSIVETABLE);
|
||||
py::enum_<QueryResultFormat>(m, "QueryResultFormat")
|
||||
.value("Json", QueryResultFormat::Json)
|
||||
.value("Tree", QueryResultFormat::Tree)
|
||||
.value("Table", QueryResultFormat::Table)
|
||||
.value("Pretty", QueryResultFormat::Pretty)
|
||||
.value("RecursiveTable", QueryResultFormat::RecursiveTable)
|
||||
.def(py::init(&mambapy::enum_from_str<QueryResultFormat>));
|
||||
py::implicitly_convertible<py::str, QueryType>();
|
||||
|
||||
auto queries_find = [](const Query& q,
|
||||
const std::vector<std::string>& queries,
|
||||
const query::RESULT_FORMAT format) -> std::string
|
||||
{
|
||||
query_result res = q.find(queries);
|
||||
std::stringstream res_stream;
|
||||
switch (format)
|
||||
{
|
||||
case query::JSON:
|
||||
res_stream << res.groupby("name").json().dump(4);
|
||||
break;
|
||||
case query::TREE:
|
||||
case query::TABLE:
|
||||
case query::RECURSIVETABLE:
|
||||
res.groupby("name").table(res_stream);
|
||||
break;
|
||||
case query::PRETTY:
|
||||
res.groupby("name").pretty(res_stream, mambapy::singletons.context().output_params);
|
||||
}
|
||||
if (res.empty() && format != query::JSON)
|
||||
{
|
||||
res_stream << fmt::format("{}", fmt::join(queries, " "))
|
||||
<< " may not be installed. Try specifying a channel with '-c,--channel' option\n";
|
||||
}
|
||||
return res_stream.str();
|
||||
};
|
||||
|
||||
py::class_<Query>(m, "Query")
|
||||
.def(py::init<MPool&>())
|
||||
py::class_<QueryResult>(m, "QueryResult")
|
||||
.def_property_readonly("type", &QueryResult::type)
|
||||
.def_property_readonly("query", &QueryResult::query)
|
||||
.def("sort", &QueryResult::sort, py::return_value_policy::reference)
|
||||
.def("groupby", &QueryResult::groupby, py::return_value_policy::reference)
|
||||
.def("reset", &QueryResult::reset, py::return_value_policy::reference)
|
||||
.def("table", &QueryResult::table_to_str)
|
||||
.def("tree", &QueryResult::tree_to_str)
|
||||
.def("pretty", &QueryResult::pretty_to_str, py::arg("show_all_builds") = true)
|
||||
.def("json", [](const QueryResult& query) { return query.json().dump(); })
|
||||
.def(
|
||||
"find",
|
||||
[queries_find](const Query& q, const std::string& query, const query::RESULT_FORMAT format)
|
||||
-> std::string { return queries_find(q, { query }, format); }
|
||||
)
|
||||
.def("find", queries_find)
|
||||
.def(
|
||||
"whoneeds",
|
||||
[](const Query& q, const std::string& query, const query::RESULT_FORMAT format) -> std::string
|
||||
"to_dict",
|
||||
[](const QueryResult& query)
|
||||
{
|
||||
// QueryResult res = q.whoneeds(query, tree);
|
||||
std::stringstream res_stream;
|
||||
query_result res = q.whoneeds(query, (format == query::TREE));
|
||||
switch (format)
|
||||
{
|
||||
case query::TREE:
|
||||
case query::PRETTY:
|
||||
res.tree(res_stream, mambapy::singletons.context().graphics_params);
|
||||
break;
|
||||
case query::JSON:
|
||||
res_stream << res.json().dump(4);
|
||||
break;
|
||||
case query::TABLE:
|
||||
case query::RECURSIVETABLE:
|
||||
res.table(
|
||||
res_stream,
|
||||
{ "Name",
|
||||
"Version",
|
||||
"Build",
|
||||
printers::alignmentMarker(printers::alignment::left),
|
||||
printers::alignmentMarker(printers::alignment::right),
|
||||
util::concat("Depends:", query),
|
||||
"Channel",
|
||||
"Subdir" }
|
||||
);
|
||||
}
|
||||
if (res.empty() && format != query::JSON)
|
||||
{
|
||||
res_stream << query
|
||||
<< " may not be installed. Try giving a channel with '-c,--channel' option for remote repoquery\n";
|
||||
}
|
||||
return res_stream.str();
|
||||
}
|
||||
)
|
||||
.def(
|
||||
"depends",
|
||||
[](const Query& q, const std::string& query, const query::RESULT_FORMAT format) -> std::string
|
||||
{
|
||||
query_result res = q.depends(
|
||||
query,
|
||||
(format == query::TREE || format == query::RECURSIVETABLE)
|
||||
);
|
||||
std::stringstream res_stream;
|
||||
switch (format)
|
||||
{
|
||||
case query::TREE:
|
||||
case query::PRETTY:
|
||||
res.tree(res_stream, mambapy::singletons.context().graphics_params);
|
||||
break;
|
||||
case query::JSON:
|
||||
res_stream << res.json().dump(4);
|
||||
break;
|
||||
case query::TABLE:
|
||||
case query::RECURSIVETABLE:
|
||||
// res.table(res_stream, {"Name", "Version", "Build", concat("Depends:",
|
||||
// query), "Channel"});
|
||||
res.table(res_stream);
|
||||
}
|
||||
if (res.empty() && format != query::JSON)
|
||||
{
|
||||
res_stream << query
|
||||
<< " may not be installed. Try giving a channel with '-c,--channel' option for remote repoquery\n";
|
||||
}
|
||||
return res_stream.str();
|
||||
auto json_module = pybind11::module_::import("json");
|
||||
return json_module.attr("loads")(query.json().dump());
|
||||
}
|
||||
);
|
||||
|
||||
py::class_<Query>(m, "Query")
|
||||
.def_static("find", &Query::find)
|
||||
.def_static("whoneeds", &Query::whoneeds)
|
||||
.def_static("depends", &Query::depends);
|
||||
|
||||
py::class_<SubdirData>(m, "SubdirData")
|
||||
.def(
|
||||
"create_repo",
|
||||
|
|
Loading…
Reference in New Issue