mirror of https://github.com/mamba-org/mamba.git
feat: add revisions flag to list command (#3800)
This commit is contained in:
parent
c6ff043d71
commit
b117f3acae
|
@ -38,6 +38,7 @@ namespace mamba
|
|||
static UserRequest prefilled(const Context& context);
|
||||
|
||||
std::string date;
|
||||
int revision_num = 0;
|
||||
std::string cmd;
|
||||
std::string conda_version;
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace mamba
|
|||
bool md5 = false;
|
||||
bool canonical = false;
|
||||
bool export_ = false;
|
||||
bool revisions = false;
|
||||
};
|
||||
|
||||
struct formatted_pkg
|
||||
|
@ -153,31 +154,52 @@ namespace mamba
|
|||
if (ctx.output_params.json)
|
||||
{
|
||||
auto jout = nlohmann::json::array();
|
||||
std::vector<std::string> keys;
|
||||
|
||||
keys = get_record_keys(options, all_records);
|
||||
|
||||
for (const auto& key : keys)
|
||||
if (options.revisions)
|
||||
{
|
||||
auto obj = nlohmann::json();
|
||||
const auto& pkg_info = all_records.find(key)->second;
|
||||
auto user_requests = prefix_data.history().get_user_requests();
|
||||
|
||||
if (accept_package(pkg_info))
|
||||
for (auto r : user_requests)
|
||||
{
|
||||
auto channels = channel_context.make_channel(pkg_info.package_url);
|
||||
assert(channels.size() == 1); // A URL can only resolve to one channel
|
||||
if ((r.link_dists.size() > 0) || (r.unlink_dists.size() > 0))
|
||||
{
|
||||
auto obj = nlohmann::json();
|
||||
|
||||
obj["channel"] = get_formatted_channel(pkg_info, channels.front());
|
||||
obj["base_url"] = get_base_url(pkg_info, channels.front());
|
||||
obj["url"] = pkg_info.package_url;
|
||||
obj["md5"] = pkg_info.md5;
|
||||
obj["build_number"] = pkg_info.build_number;
|
||||
obj["build_string"] = pkg_info.build_string;
|
||||
obj["dist_name"] = pkg_info.str();
|
||||
obj["name"] = pkg_info.name;
|
||||
obj["platform"] = pkg_info.platform;
|
||||
obj["version"] = pkg_info.version;
|
||||
jout.push_back(obj);
|
||||
obj["date"] = r.date;
|
||||
obj["install"] = r.link_dists;
|
||||
obj["remove"] = r.unlink_dists;
|
||||
obj["rev"] = r.revision_num;
|
||||
jout.push_back(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string> keys;
|
||||
keys = get_record_keys(options, all_records);
|
||||
|
||||
for (const auto& key : keys)
|
||||
{
|
||||
auto obj = nlohmann::json();
|
||||
const auto& pkg_info = all_records.find(key)->second;
|
||||
|
||||
if (accept_package(pkg_info))
|
||||
{
|
||||
auto channels = channel_context.make_channel(pkg_info.package_url);
|
||||
assert(channels.size() == 1); // A URL can only resolve to one channel
|
||||
|
||||
obj["channel"] = get_formatted_channel(pkg_info, channels.front());
|
||||
obj["base_url"] = get_base_url(pkg_info, channels.front());
|
||||
obj["url"] = pkg_info.package_url;
|
||||
obj["md5"] = pkg_info.md5;
|
||||
obj["build_number"] = pkg_info.build_number;
|
||||
obj["build_string"] = pkg_info.build_string;
|
||||
obj["dist_name"] = pkg_info.str();
|
||||
obj["name"] = pkg_info.name;
|
||||
obj["platform"] = pkg_info.platform;
|
||||
obj["version"] = pkg_info.version;
|
||||
jout.push_back(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << jout.dump(4) << std::endl;
|
||||
|
@ -215,7 +237,42 @@ namespace mamba
|
|||
std::sort(packages.begin(), packages.end(), comparator);
|
||||
|
||||
// format and print output
|
||||
if (options.explicit_)
|
||||
if (options.revisions)
|
||||
{
|
||||
if (options.explicit_)
|
||||
{
|
||||
LOG_WARNING
|
||||
<< "Option --explicit ignored because --revisions was also provided.";
|
||||
}
|
||||
if (options.canonical)
|
||||
{
|
||||
LOG_WARNING
|
||||
<< "Option --canonical ignored because --revisions was also provided.";
|
||||
}
|
||||
if (options.export_)
|
||||
{
|
||||
LOG_WARNING
|
||||
<< "Option --export ignored because --revisions was also provided.";
|
||||
}
|
||||
auto user_requests = prefix_data.history().get_user_requests();
|
||||
for (auto r : user_requests)
|
||||
{
|
||||
if ((r.link_dists.size() > 0) || (r.unlink_dists.size() > 0))
|
||||
{
|
||||
std::cout << r.date << " (rev " << r.revision_num << ")" << std::endl;
|
||||
for (auto ud : r.unlink_dists)
|
||||
{
|
||||
std::cout << "-" << ud << std::endl;
|
||||
}
|
||||
for (auto ld : r.link_dists)
|
||||
{
|
||||
std::cout << "+" << ld << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (options.explicit_)
|
||||
{
|
||||
if (options.canonical)
|
||||
{
|
||||
|
@ -305,6 +362,7 @@ namespace mamba
|
|||
options.md5 = config.at("md5").value<bool>();
|
||||
options.canonical = config.at("canonical").value<bool>();
|
||||
options.export_ = config.at("export").value<bool>();
|
||||
options.revisions = config.at("revisions").value<bool>();
|
||||
|
||||
auto channel_context = ChannelContext::make_conda_compatible(config.context());
|
||||
detail::list_packages(config.context(), regex, channel_context, std::move(options));
|
||||
|
|
|
@ -203,6 +203,7 @@ namespace mamba
|
|||
std::vector<History::UserRequest> History::get_user_requests()
|
||||
{
|
||||
std::vector<UserRequest> res;
|
||||
int revision_num = 0;
|
||||
for (const auto& el : parse())
|
||||
{
|
||||
UserRequest r;
|
||||
|
@ -223,6 +224,10 @@ namespace mamba
|
|||
r.link_dists.push_back(x.substr(1));
|
||||
}
|
||||
}
|
||||
if ((r.link_dists.size() > 0) || (r.unlink_dists.size() > 0))
|
||||
{
|
||||
r.revision_num = revision_num++;
|
||||
}
|
||||
res.push_back(r);
|
||||
}
|
||||
// TODO add some stuff here regarding version of conda?
|
||||
|
|
|
@ -39,10 +39,13 @@ init_list_parser(CLI::App* subcom, Configuration& config)
|
|||
);
|
||||
subcom->add_flag("--reverse", reverse.get_cli_config<bool>(), reverse.description());
|
||||
|
||||
auto& explicit_ = config.insert(Configurable("explicit", false)
|
||||
.group("cli")
|
||||
.description("List explicitly all installed packages with URL."
|
||||
));
|
||||
auto& explicit_ = config.insert(
|
||||
Configurable("explicit", false)
|
||||
.group("cli")
|
||||
.description(
|
||||
"List explicitly all installed packages with URL. Ignored if --revisions is also provided."
|
||||
)
|
||||
);
|
||||
subcom->add_flag("--explicit", explicit_.get_cli_config<bool>(), explicit_.description());
|
||||
|
||||
auto& md5 = config.insert(
|
||||
|
@ -53,7 +56,8 @@ init_list_parser(CLI::App* subcom, Configuration& config)
|
|||
auto& canonical = config.insert(
|
||||
Configurable("canonical", false)
|
||||
.group("cli")
|
||||
.description("Output canonical names of packages only. Ignored if --explicit is also provided."
|
||||
.description(
|
||||
"Output canonical names of packages only. Ignored if --revisions or --explicit is also provided."
|
||||
)
|
||||
);
|
||||
subcom->add_flag("-c,--canonical", canonical.get_cli_config<bool>(), canonical.description());
|
||||
|
@ -62,10 +66,15 @@ init_list_parser(CLI::App* subcom, Configuration& config)
|
|||
Configurable("export", false)
|
||||
.group("cli")
|
||||
.description(
|
||||
"Output explicit, machine-readable requirement strings instead of human-readable lists of packages. Ignored if --explicit or --canonical is also provided."
|
||||
"Output explicit, machine-readable requirement strings instead of human-readable lists of packages. Ignored if --revisions, --explicit or --canonical is also provided."
|
||||
)
|
||||
);
|
||||
subcom->add_flag("-e,--export", export_.get_cli_config<bool>(), export_.description());
|
||||
|
||||
auto& revisions = config.insert(
|
||||
Configurable("revisions", false).group("cli").description("List the revision history.")
|
||||
);
|
||||
subcom->add_flag("--revisions", revisions.get_cli_config<bool>(), revisions.description());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -3,6 +3,7 @@ import subprocess
|
|||
import sys
|
||||
|
||||
import pytest
|
||||
import re
|
||||
|
||||
from . import helpers
|
||||
|
||||
|
@ -209,3 +210,43 @@ def test_regex(tmp_home, tmp_root_prefix, tmp_xtensor_env, quiet_flag):
|
|||
filtered_res = helpers.umamba_list("^xt", "--json", quiet_flag)
|
||||
filtered_names = sorted([i["name"] for i in filtered_res])
|
||||
assert filtered_names == ["xtensor", "xtl"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("revisions_flag", ["", "--revisions"])
|
||||
@pytest.mark.parametrize("json_flag", ["", "--json"])
|
||||
def test_revisions(revisions_flag, json_flag):
|
||||
env_name = "myenv"
|
||||
|
||||
helpers.create("-n", env_name, "python=3.8")
|
||||
helpers.install("-n", env_name, "xeus=2.0")
|
||||
helpers.update("-n", env_name, "xeus=4.0")
|
||||
helpers.uninstall("-n", env_name, "xeus")
|
||||
res = helpers.umamba_list("-n", env_name, revisions_flag, json_flag)
|
||||
|
||||
if revisions_flag == "--revisions":
|
||||
if json_flag == "--json":
|
||||
# print(res)
|
||||
assert all(res[i]["rev"] == i for i in range(len(res)))
|
||||
assert any("python-3.8" in i for i in res[0]["install"])
|
||||
assert any("xeus-2.0" in i for i in res[2]["remove"])
|
||||
assert any("xeus-4.0" in i for i in res[2]["install"])
|
||||
assert any("xeus-4.0" in i for i in res[3]["remove"])
|
||||
assert len(res[3]["install"]) == 0
|
||||
else:
|
||||
# Splitting on dates (e.g. 2025-02-18) which are at the beginning of each new revision
|
||||
revisions = re.split(r"\d{4}-\d{2}-\d{2}", res)[1:]
|
||||
assert all("rev" in revisions[i] for i in range(len(revisions)))
|
||||
assert "python-3.8" in revisions[0]
|
||||
assert revisions[0].count("+") == len(revisions[0].strip().split("\n")) - 1
|
||||
rev_2 = revisions[2].split("\n")[1:]
|
||||
assert "xeus-2.0" in revisions[2]
|
||||
assert "xeus-4.0" in revisions[2]
|
||||
for line in rev_2:
|
||||
if "xeus-2.0" in line:
|
||||
assert line.startswith("-")
|
||||
elif "xeus-4.0" in line:
|
||||
assert line.startswith("+")
|
||||
assert "xeus-4.0" in revisions[3]
|
||||
assert "+" not in revisions[3]
|
||||
else:
|
||||
assert "xeus" not in res
|
||||
|
|
Loading…
Reference in New Issue