mirror of https://github.com/mamba-org/mamba.git
implement reverse dependency walker and tree printing
This commit is contained in:
parent
289672dc94
commit
b29a53f64a
|
@ -9,19 +9,17 @@ find_package(Threads REQUIRED)
|
|||
find_library(LIBSOLV_LIBRARIES NAMES solv)
|
||||
find_library(LIBSOLVEXT_LIBRARIES NAMES solvext)
|
||||
find_package(CURL REQUIRED)
|
||||
find_library(ARCHIVE_LIBRARIES NAMES archive)
|
||||
find_package(LibArchive REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(tabulate REQUIRED)
|
||||
|
||||
set(MAMBA_REQUIRED_LIBS
|
||||
${LIBSOLV_LIBRARIES}
|
||||
${LIBSOLVEXT_LIBRARIES}
|
||||
${ARCHIVE_LIBRARIES}
|
||||
${LibArchive_LIBRARIES}
|
||||
${CURL_LIBRARIES}
|
||||
${OPENSSL_CRYPTO_LIBRARY}
|
||||
${OPENSSL_LIBRARIES}
|
||||
nlohmann_json::nlohmann_json
|
||||
tabulate::tabulate
|
||||
)
|
||||
|
||||
message("Found libraries: ${MAMBA_REQUIRED_LIBS}")
|
||||
|
|
|
@ -23,7 +23,7 @@ conda install mamba -c conda-forge
|
|||
|
||||
Make sure to have the following requirements in your conda environment:
|
||||
|
||||
- `conda install pybind11 libsolv libarchive libcurl nlohmann_json pip "cpp-tabulate>=1.2" -c conda-forge`
|
||||
- `conda install pybind11 libsolv libarchive libcurl nlohmann_json pip -c conda-forge`
|
||||
|
||||
If you build mamba in a different environment than base, you must also install conda in
|
||||
that environment:
|
||||
|
|
|
@ -4,12 +4,9 @@
|
|||
#include <functional>
|
||||
#include <string_view>
|
||||
|
||||
#include "output.hpp"
|
||||
#include "pool.hpp"
|
||||
|
||||
namespace tabulate {
|
||||
class Table;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "solv/repo.h"
|
||||
|
@ -21,8 +18,6 @@ extern "C"
|
|||
namespace mamba
|
||||
{
|
||||
std::string cut_repo_name(std::ostream& out, const std::string_view& reponame);
|
||||
void solvable_to_stream(std::ostream& out, Solvable* s, int row_count,
|
||||
tabulate::Table& query_result);
|
||||
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
|
||||
|
@ -32,7 +27,7 @@ namespace mamba
|
|||
Query(MPool& pool);
|
||||
|
||||
std::string find(const std::string& query);
|
||||
std::string whatrequires(const std::string& query);
|
||||
std::string whatrequires(const std::string& query, bool tree);
|
||||
std::string dependencytree(const std::string& query);
|
||||
|
||||
private:
|
||||
|
|
|
@ -598,7 +598,11 @@ def repoquery(args, parser):
|
|||
repo.set_installed()
|
||||
repos.append(repo)
|
||||
|
||||
if not args.installed:
|
||||
only_installed = True
|
||||
if args.subcmd == "search" and args.installed == False:
|
||||
only_installed = False
|
||||
|
||||
if not only_installed:
|
||||
index = get_index(channel_urls=index_args['channel_urls'],
|
||||
prepend=index_args['prepend'], platform=None,
|
||||
use_local=index_args['use_local'], use_cache=index_args['use_cache'],
|
||||
|
@ -614,15 +618,15 @@ def repoquery(args, parser):
|
|||
repos.append(repo)
|
||||
|
||||
|
||||
print("\nExecuting the query %s\n" % args.query)
|
||||
print("\nExecuting the query %s\n" % args.package_query)
|
||||
|
||||
query = api.Query(pool)
|
||||
if args.whatrequires:
|
||||
print(query.whatrequires(args.query))
|
||||
elif args.tree:
|
||||
print(query.dependencytree(args.query))
|
||||
else:
|
||||
print(query.find(args.query))
|
||||
if args.subcmd == "whoneeds":
|
||||
print(query.whatrequires(args.package_query, args.tree))
|
||||
if args.subcmd == "depends":
|
||||
print(query.dependencytree(args.package_query))
|
||||
if args.subcmd == "search":
|
||||
print(query.find(args.package_query))
|
||||
|
||||
|
||||
def do_call(args, parser):
|
||||
|
@ -656,42 +660,49 @@ def configure_parser_repoquery(sub_parsers):
|
|||
example = ("""
|
||||
Examples:
|
||||
|
||||
conda repoquery xtensor>=0.18
|
||||
mamba repoquery search xtensor>=0.18
|
||||
mamba repoquery depends xtensor
|
||||
mamba repoquery whoneeds xtl
|
||||
|
||||
""")
|
||||
|
||||
import argparse
|
||||
from argparse import SUPPRESS
|
||||
|
||||
p = sub_parsers.add_parser(
|
||||
'repoquery',
|
||||
description=descr,
|
||||
help=help,
|
||||
epilog=example,
|
||||
epilog=example
|
||||
)
|
||||
|
||||
p.add_argument(
|
||||
'query',
|
||||
action="store",
|
||||
nargs='?',
|
||||
help="Package query.",
|
||||
)
|
||||
|
||||
p.add_argument(
|
||||
"--whatrequires",
|
||||
subsub_parser = p.add_subparsers(dest='subcmd')
|
||||
package_cmds = argparse.ArgumentParser(add_help=False)
|
||||
package_cmds.add_argument('package_query', help='the target package')
|
||||
package_cmds.add_argument(
|
||||
"-i", "--installed",
|
||||
action="store_true",
|
||||
help=SUPPRESS,
|
||||
help=SUPPRESS
|
||||
)
|
||||
|
||||
p.add_argument(
|
||||
"--installed",
|
||||
action="store_true",
|
||||
help=SUPPRESS,
|
||||
view_cmds = argparse.ArgumentParser(add_help=False)
|
||||
view_cmds.add_argument(
|
||||
"-t", "--tree",
|
||||
action="store_true"
|
||||
)
|
||||
|
||||
p.add_argument(
|
||||
"--tree",
|
||||
action="store_true",
|
||||
help=SUPPRESS,
|
||||
subsub_parser.add_parser('whoneeds',
|
||||
help='shows packages that depends on this package',
|
||||
parents=[package_cmds, view_cmds]
|
||||
)
|
||||
|
||||
subsub_parser.add_parser('depends',
|
||||
help='shows packages that depends on this package',
|
||||
parents=[package_cmds, view_cmds]
|
||||
)
|
||||
|
||||
subsub_parser.add_parser('search',
|
||||
help='shows packages that depends on this package',
|
||||
parents=[package_cmds]
|
||||
)
|
||||
|
||||
from conda.cli import conda_argparse
|
||||
|
@ -702,7 +713,6 @@ Examples:
|
|||
p.set_defaults(func='.main_repoquery.execute')
|
||||
return p
|
||||
|
||||
|
||||
def _wrapped_main(*args, **kwargs):
|
||||
if len(args) == 1:
|
||||
args = args + ('-h',)
|
||||
|
|
|
@ -11,8 +11,6 @@ extern "C" {
|
|||
#include <solv/evr.h>
|
||||
}
|
||||
|
||||
#include "tabulate/table.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
namespace printers
|
||||
|
@ -133,6 +131,45 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
void reverse_walk_graph(printers::Node<std::string>& parent,
|
||||
Solvable* s,
|
||||
std::set<Solvable*>& visited_solvs)
|
||||
{
|
||||
|
||||
if (s)
|
||||
{
|
||||
auto* pool = s->repo->pool;
|
||||
// figure out who requires `s`
|
||||
Queue solvables;
|
||||
queue_init(&solvables);
|
||||
|
||||
pool_whatmatchesdep(pool, SOLVABLE_REQUIRES, s->name, &solvables, -1);
|
||||
|
||||
if (solvables.count != 0)
|
||||
{
|
||||
Solvable* rs;
|
||||
for (int i = 0; i < solvables.count; i++)
|
||||
{
|
||||
rs = pool_id2solvable(pool, solvables.elements[i]);
|
||||
if (visited_solvs.count(rs) == 0)
|
||||
{
|
||||
printers::Node<std::string> next_node(concat(pool_id2str(pool, rs->name), " [", pool_id2str(pool, rs->evr), "]"));
|
||||
visited_solvs.insert(rs);
|
||||
reverse_walk_graph(next_node, rs, visited_solvs);
|
||||
parent.add_child(next_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.add_child(concat("\033[2m", pool_id2str(pool, rs->name), " already visited", "\033[00m"));
|
||||
}
|
||||
}
|
||||
queue_free(&solvables);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************
|
||||
* Query implementation *
|
||||
************************/
|
||||
|
@ -183,7 +220,7 @@ namespace mamba
|
|||
return out.str();
|
||||
}
|
||||
|
||||
std::string Query::whatrequires(const std::string& query)
|
||||
std::string Query::whatrequires(const std::string& query, bool tree)
|
||||
{
|
||||
Queue job, solvables;
|
||||
queue_init(&job);
|
||||
|
@ -199,26 +236,49 @@ namespace mamba
|
|||
throw std::runtime_error("Could not generate query for " + query);
|
||||
}
|
||||
|
||||
pool_whatmatchesdep(m_pool.get(), SOLVABLE_REQUIRES, id, &solvables, -1);
|
||||
|
||||
std::stringstream out;
|
||||
if (solvables.count == 0)
|
||||
if (tree)
|
||||
{
|
||||
out << "No entries matching \"" << query << "\" found";
|
||||
}
|
||||
|
||||
printers::Table whatrequires_table_results({"Name", "Version", "Build", "Channel"});
|
||||
for (int i = 0; i < solvables.count; i++)
|
||||
{
|
||||
Solvable* s = pool_id2solvable(m_pool.get(), solvables.elements[i]);
|
||||
solvable_to_stream(out, s, i + 1, whatrequires_table_results);
|
||||
}
|
||||
whatrequires_table_results.print();
|
||||
selection_solvables(m_pool.get(), &job, &solvables);
|
||||
|
||||
if (solvables.count)
|
||||
{
|
||||
Solvable* latest = pool_id2solvable(m_pool.get(), solvables.elements[0]);
|
||||
printers::Node<std::string> root(concat(pool_id2str(m_pool.get(), latest->name), " == ", pool_id2str(m_pool.get(), latest->evr)));
|
||||
root.set_root(true);
|
||||
std::set<Solvable*> visited { latest };
|
||||
|
||||
reverse_walk_graph(root, latest, visited);
|
||||
root.print("", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "No matching package found" << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pool_whatmatchesdep(m_pool.get(), SOLVABLE_REQUIRES, id, &solvables, -1);
|
||||
|
||||
std::stringstream out;
|
||||
if (solvables.count == 0)
|
||||
{
|
||||
out << "No entries matching \"" << query << "\" found";
|
||||
}
|
||||
|
||||
printers::Table whatrequires_table_results({"Name", "Version", "Build", "Channel"});
|
||||
for (int i = 0; i < solvables.count; i++)
|
||||
{
|
||||
Solvable* s = pool_id2solvable(m_pool.get(), solvables.elements[i]);
|
||||
solvable_to_stream(out, s, i + 1, whatrequires_table_results);
|
||||
}
|
||||
whatrequires_table_results.print();
|
||||
|
||||
}
|
||||
queue_free(&job);
|
||||
queue_free(&solvables);
|
||||
|
||||
return out.str();
|
||||
return "";
|
||||
// return out.str();
|
||||
}
|
||||
|
||||
std::string Query::dependencytree(const std::string& query)
|
||||
|
@ -265,8 +325,6 @@ namespace mamba
|
|||
}
|
||||
printers::Node<std::string> root(concat(pool_id2str(m_pool.get(), latest->name), " == ", pool_id2str(m_pool.get(), latest->evr)));
|
||||
root.set_root(true);
|
||||
// std::stringstream solv_str;
|
||||
// solv_str << pool_id2str(m_pool.get(), latest->name) << " == " << ;
|
||||
std::set<Solvable*> visited { latest };
|
||||
walk_graph(root, latest, visited);
|
||||
root.print("", false);
|
||||
|
|
Loading…
Reference in New Issue