Fix `repoquery` issues (#2330)

Fix `depends` and `whoneeds` repoquery sub-commands in micromamba
This commit is contained in:
Hind-M 2023-03-06 12:13:19 +01:00 committed by GitHub
parent b38377a479
commit e549d07b0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 281 additions and 25 deletions

View File

@ -100,6 +100,8 @@ namespace mamba
std::ostream& pretty(std::ostream&) const;
bool empty() const;
private:
void reset_pkg_view_list();

View File

@ -18,6 +18,8 @@ namespace mamba
{
auto& ctx = Context::instance();
auto& config = Configuration::instance();
config.at("show_banner").set_value(false);
config.at("use_target_prefix_fallback").set_value(true);
config.at("target_prefix_checks")
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX);
@ -29,6 +31,10 @@ namespace mamba
MultiPackageCache package_caches(ctx.pkgs_dirs);
if (use_local)
{
if (format != QueryResultFormat::kJSON)
{
Console::stream() << "Using local repodata..." << std::endl;
}
auto exp_prefix_data = PrefixData::create(ctx.target_prefix);
if (!exp_prefix_data)
{
@ -37,10 +43,18 @@ namespace mamba
}
PrefixData& prefix_data = exp_prefix_data.value();
MRepo::create(pool, prefix_data);
Console::stream() << "Loaded current active prefix: " << ctx.target_prefix << std::endl;
if (format != QueryResultFormat::kJSON)
{
Console::stream() << "Loaded current active prefix: " << ctx.target_prefix
<< std::endl;
}
}
else
{
if (format != QueryResultFormat::kJSON)
{
Console::stream() << "Getting repodata from channels..." << std::endl;
}
auto exp_load = load_channels(pool, package_caches, 0);
if (!exp_load)
{
@ -70,6 +84,11 @@ namespace mamba
default:
res.groupby("name").table(std::cout);
}
if (res.empty())
{
std::cout << "Channels may not be configured. Try giving a channel with '-c,--channel' option, or use `--use-local=1` to search for installed packages."
<< std::endl;
}
}
}
else if (type == QueryType::kDEPENDS)
@ -91,6 +110,12 @@ namespace mamba
case QueryResultFormat::kRECURSIVETABLE:
res.sort("name").table(std::cout);
}
if (res.empty() && format != QueryResultFormat::kJSON)
{
std::cout << query
<< " may not be installed. Try giving a channel with '-c,--channel' option for remote repoquery"
<< std::endl;
}
}
else if (type == QueryType::kWHONEEDS)
{
@ -114,6 +139,12 @@ namespace mamba
{ "Name", "Version", "Build", concat("Depends:", query), "Channel" }
);
}
if (res.empty() && format != QueryResultFormat::kJSON)
{
std::cout << query
<< " may not be installed. Try giving a channel with '-c,--channel' option for remote repoquery"
<< std::endl;
}
}
config.operation_teardown();

View File

@ -658,18 +658,6 @@ namespace mamba
return out;
}
std::ostream& query_result::pretty(std::ostream& out) const
{
if (!m_pkg_view_list.empty())
{
for (const auto& pkg : m_pkg_view_list)
{
print_solvable(pkg);
}
}
return out;
}
nlohmann::json query_result::json() const
{
nlohmann::json j;
@ -699,6 +687,23 @@ namespace mamba
return j;
}
std::ostream& query_result::pretty(std::ostream& out) const
{
if (!m_pkg_view_list.empty())
{
for (const auto& pkg : m_pkg_view_list)
{
print_solvable(pkg);
}
}
return out;
}
bool query_result::empty() const
{
return m_dep_graph.empty();
}
void query_result::reset_pkg_view_list()
{
auto it = m_dep_graph.nodes().begin();

View File

@ -357,19 +357,25 @@ PYBIND11_MODULE(bindings, m)
"find",
[](const Query& q, const std::string& query, const query::RESULT_FORMAT format) -> std::string
{
query_result res = q.find(query);
std::stringstream res_stream;
switch (format)
{
case query::JSON:
res_stream << q.find(query).groupby("name").json().dump(4);
res_stream << res.groupby("name").json().dump(4);
break;
case query::TREE:
case query::TABLE:
case query::RECURSIVETABLE:
q.find(query).groupby("name").table(res_stream);
res.groupby("name").table(res_stream);
break;
case query::PRETTY:
q.find(query).groupby("name").pretty(res_stream);
res.groupby("name").pretty(res_stream);
}
if (res.empty())
{
res_stream << query
<< " may not be installed. Try specifying a channel with '-c,--channel' option\n";
}
return res_stream.str();
}
@ -397,6 +403,11 @@ PYBIND11_MODULE(bindings, m)
{ "Name", "Version", "Build", concat("Depends:", query), "Channel" }
);
}
if (res.empty())
{
res_stream << query
<< " may not be installed. Try giving a channel with '-c,--channel' option for remote repoquery\n";
}
return res_stream.str();
}
)
@ -424,6 +435,11 @@ PYBIND11_MODULE(bindings, m)
// query), "Channel"});
res.table(res_stream);
}
if (res.empty())
{
res_stream << query
<< " may not be installed. Try giving a channel with '-c,--channel' option for remote repoquery\n";
}
return res_stream.str();
}
);

View File

@ -60,7 +60,7 @@ set_common_search(CLI::App* subcom, bool is_repoquery)
subcom->add_flag(
"--recursive",
recursive,
"Show dependencies recursively (i.e. transitive dependencies)."
"Show dependencies recursively, i.e. transitive dependencies (only for `depends`)"
);
static bool pretty_print = false;
@ -69,8 +69,12 @@ set_common_search(CLI::App* subcom, bool is_repoquery)
static std::vector<std::string> specs;
subcom->add_option("specs", specs, "Specs to search")->required();
static int local = 0;
subcom->add_flag("--local,!--remote", local, "Use installed data or remote repositories");
static int local = -1;
subcom->add_option(
"--use-local",
local,
"Use installed data (--use-local=1, default for `depends` and `whoneeds`) or remote repositories (--use-local=0, default for `search`).\nIf the `-c,--channel` option is set, it has the priority and --use-local is set to 0"
);
auto& platform = config.at("platform");
subcom->add_option("--platform", platform.get_cli_config<std::string>(), platform.description());
@ -80,19 +84,20 @@ set_common_search(CLI::App* subcom, bool is_repoquery)
{
auto qtype = str_to_qtype(query_type);
QueryResultFormat format = QueryResultFormat::kTABLE;
bool use_local = true;
switch (qtype)
{
case QueryType::kSEARCH:
format = QueryResultFormat::kTABLE;
local = (local == 0) ? false : local > 0;
use_local = local > 0; // use remote repodata by default for `search`
break;
case QueryType::kDEPENDS:
format = QueryResultFormat::kTABLE;
local = (local == 0) ? true : local > 0;
use_local = (local == -1) || (local > 0);
break;
case QueryType::kWHONEEDS:
format = QueryResultFormat::kTABLE;
local = (local == 0) ? true : local > 0;
use_local = (local == -1) || (local > 0);
break;
}
if (qtype == QueryType::kDEPENDS && recursive)
@ -110,10 +115,15 @@ set_common_search(CLI::App* subcom, bool is_repoquery)
format = QueryResultFormat::kPRETTY;
}
// if (ctx.json)
// format = QueryResultFormat::kJSON;
if (config.at("json").compute().value<bool>())
{
format = QueryResultFormat::kJSON;
}
repoquery(qtype, format, local, specs[0]);
auto& channels = config.at("channels").compute().value<std::vector<std::string>>();
use_local = use_local && channels.empty();
repoquery(qtype, format, use_local, specs[0]);
}
);
}

View File

@ -307,6 +307,23 @@ def umamba_run(*args, **kwargs):
return res.decode()
def umamba_repoquery(*args, no_rc=True):
umamba = get_umamba()
cmd = [umamba, "repoquery"] + [arg for arg in args if arg]
if no_rc:
cmd += ["--no-rc"]
res = subprocess_run(*cmd)
if "--json" in args:
j = json.loads(res)
return j
return res.decode()
def get_concrete_pkg(t, needle):
pkgs = t["actions"]["LINK"]
for p in pkgs:

View File

@ -0,0 +1,175 @@
import os
import platform
import shutil
import pytest
from .helpers import create, get_env, random_string, umamba_repoquery
class TestRepoquery:
env_name = random_string()
root_prefix = os.environ["MAMBA_ROOT_PREFIX"]
current_prefix = os.environ["CONDA_PREFIX"]
prefix = os.path.join(root_prefix, "envs", env_name)
@classmethod
def setup_class(cls):
create(
"yaml=0.2.5",
"pyyaml=6.0",
"-c",
"conda-forge",
"-n",
TestRepoquery.env_name,
"--json",
no_dry_run=True,
)
os.environ["CONDA_PREFIX"] = TestRepoquery.prefix
@classmethod
def teardown_class(cls):
os.environ["CONDA_PREFIX"] = TestRepoquery.current_prefix
shutil.rmtree(get_env(TestRepoquery.env_name))
# Testing `depends`
def test_depends(self):
res = umamba_repoquery("depends", "yaml=0.2.5", "--json")
assert res["query"]["query"] == "yaml =0.2.5*"
assert res["query"]["type"] == "depends"
pkgs = res["result"]["pkgs"]
assert any(x["channel"] == "conda-forge" for x in pkgs)
assert any(x["name"] == "yaml" for x in pkgs)
assert any(x["version"] == "0.2.5" for x in pkgs)
if platform.system() == "Linux":
assert any(x["name"] == "libgcc-ng" for x in pkgs)
def test_depends_remote(self):
res = umamba_repoquery("depends", "yaml", "--use-local=0")
assert 'No entries matching "yaml" found' in res
def test_depends_not_installed(self):
res = umamba_repoquery("depends", "xtensor")
assert 'No entries matching "xtensor" found' in res
def test_depends_not_installed_with_channel(self):
res = umamba_repoquery(
"depends", "-c", "conda-forge", "xtensor=0.24.5", "--json"
)
assert res["query"]["query"] == "xtensor =0.24.5*"
assert res["query"]["type"] == "depends"
assert "conda-forge" in res["result"]["graph_roots"][0]["channel"]
assert res["result"]["graph_roots"][0]["name"] == "xtensor"
assert res["result"]["graph_roots"][0]["version"] == "0.24.5"
pkgs = res["result"]["pkgs"]
assert any(x["name"] == "xtensor" for x in pkgs)
assert any(x["name"] == "xtl" for x in pkgs)
if platform.system() == "Linux":
assert any(x["name"] == "libgcc-ng" for x in pkgs)
assert any(x["name"] == "libstdcxx-ng" for x in pkgs)
def test_depends_recursive(self):
res = umamba_repoquery(
"depends", "-c", "conda-forge", "xtensor=0.24.5", "--recursive"
)
if platform.system() == "Linux":
assert "libzlib" in res
elif platform.system() == "Darwin":
assert "libcxx" in res
elif platform.system() == "Windows":
assert "vc" in res
def test_depends_tree(self):
res = umamba_repoquery(
"depends", "-c", "conda-forge", "xtensor=0.24.5", "--tree"
)
if platform.system() == "Linux":
assert "libzlib" in res
elif platform.system() == "Darwin":
assert "libcxx" in res
elif platform.system() == "Windows":
assert "vc" in res
# Testing `whoneeds`
def test_whoneeds(self):
res = umamba_repoquery("whoneeds", "yaml", "--json")
assert res["query"]["query"] == "yaml"
assert res["query"]["type"] == "whoneeds"
assert res["result"]["pkgs"][0]["channel"] == "conda-forge"
assert res["result"]["pkgs"][0]["name"] == "pyyaml"
assert res["result"]["pkgs"][0]["version"] == "6.0"
def test_whoneeds_remote(self):
res = umamba_repoquery("whoneeds", "yaml", "--use-local=0")
assert 'No entries matching "yaml" found' in res
def test_whoneeds_not_installed(self):
res = umamba_repoquery("whoneeds", "xtensor")
assert 'No entries matching "xtensor" found' in res
def test_whoneeds_not_installed_with_channel(self):
res = umamba_repoquery(
"whoneeds", "-c", "conda-forge", "xtensor=0.24.5", "--json"
)
assert res["query"]["query"] == "xtensor =0.24.5*"
assert res["query"]["type"] == "whoneeds"
pkgs = res["result"]["pkgs"]
assert all("conda-forge" in x["channel"] for x in pkgs)
assert any(x["name"] == "cppcolormap" for x in pkgs)
assert any(x["name"] == "pyxtensor" for x in pkgs)
assert any(x["name"] == "qpot" for x in pkgs)
def test_whoneeds_tree(self):
res = umamba_repoquery(
"whoneeds", "-c", "conda-forge", "xtensor=0.24.5", "--tree"
)
assert "cppcolormap" in res
assert "pyxtensor" in res
assert "qpot" in res
# Testing `search`
def test_remote_search_installed_pkg(self):
res = umamba_repoquery("search", "yaml")
assert 'No entries matching "yaml" found' in res
assert (
"Channels may not be configured. Try giving a channel with '-c,--channel' option, or use `--use-local=1` to search for installed packages."
in res
)
def test_local_search_installed_pkg(self):
res = umamba_repoquery("search", "yaml", "--use-local=1", "--json")
assert res["query"]["query"] == "yaml"
assert res["query"]["type"] == "search"
assert res["result"]["pkgs"][0]["channel"] == "conda-forge"
assert res["result"]["pkgs"][0]["name"] == "yaml"
assert res["result"]["pkgs"][0]["version"] == "0.2.5"
def test_remote_search_not_installed_pkg(self):
res = umamba_repoquery(
"search", "-c", "conda-forge", "xtensor=0.24.5", "--json"
)
assert res["query"]["query"] == "xtensor =0.24.5*"
assert res["query"]["type"] == "search"
assert "conda-forge" in res["result"]["pkgs"][0]["channel"]
assert res["result"]["pkgs"][0]["name"] == "xtensor"
assert res["result"]["pkgs"][0]["version"] == "0.24.5"