Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add reverse flag to list command #3705

Merged
merged 17 commits into from
Jan 15, 2025
24 changes: 22 additions & 2 deletions libmamba/src/api/list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace mamba
{
bool full_name;
bool no_pip;
bool reverse;
};

struct formatted_pkg
Expand All @@ -36,6 +37,11 @@ namespace mamba
return a.name < b.name;
}

bool compare_reverse_alphabetically(const formatted_pkg& a, const formatted_pkg& b)
{
return a.name >= b.name;
}

std::string strip_from_filename_and_platform(
const std::string& full_str,
const std::string& filename,
Expand Down Expand Up @@ -87,7 +93,18 @@ namespace mamba
{
keys.push_back(pkg.first);
}
std::sort(keys.begin(), keys.end());
if (options.reverse)
{
std::sort(
keys.begin(),
keys.end(),
[](const std::string& a, const std::string& b) { return a >= b; }
);
}
else
{
std::sort(keys.begin(), keys.end());
}

for (const auto& key : keys)
{
Expand Down Expand Up @@ -168,7 +185,9 @@ namespace mamba
}
}

std::sort(packages.begin(), packages.end(), compare_alphabetically);
auto comparator = options.reverse ? compare_reverse_alphabetically
: compare_alphabetically;
std::sort(packages.begin(), packages.end(), comparator);

// format and print table
printers::Table t({ "Name", "Version", "Build", "Channel" });
Expand Down Expand Up @@ -208,6 +227,7 @@ namespace mamba
detail::list_options options;
options.full_name = config.at("full_name").value<bool>();
options.no_pip = config.at("no_pip").value<bool>();
options.reverse = config.at("reverse").value<bool>();

auto channel_context = ChannelContext::make_conda_compatible(config.context());
detail::list_packages(config.context(), regex, channel_context, std::move(options));
Expand Down
4 changes: 4 additions & 0 deletions micromamba/src/list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ init_list_parser(CLI::App* subcom, Configuration& config)
.description("Do not include pip-only installed packages."));
subcom->add_flag("--no-pip", no_pip.get_cli_config<bool>(), no_pip.description());

auto& reverse = config.insert(
Configurable("reverse", false).group("cli").description("List installed packages in reverse order.")
);
subcom->add_flag("--reverse", reverse.get_cli_config<bool>(), reverse.description());
// TODO: implement this in libmamba/list.cpp
/*auto& canonical = config.insert(Configurable("canonical", false)
.group("cli")
Expand Down
55 changes: 51 additions & 4 deletions micromamba/tests/test_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@
from . import helpers


@pytest.mark.parametrize("reverse_flag", ["", "--reverse"])
@pytest.mark.parametrize("quiet_flag", ["", "-q", "--quiet"])
@pytest.mark.parametrize("env_selector", ["", "name", "prefix"])
@pytest.mark.parametrize("shared_pkgs_dirs", [True], indirect=True)
def test_list(tmp_home, tmp_root_prefix, tmp_env_name, tmp_xtensor_env, env_selector, quiet_flag):
def test_list(
tmp_home, tmp_root_prefix, tmp_env_name, tmp_xtensor_env, env_selector, quiet_flag, reverse_flag
):
if env_selector == "prefix":
res = helpers.umamba_list("-p", tmp_xtensor_env, "--json", quiet_flag)
res = helpers.umamba_list("-p", tmp_xtensor_env, "--json", quiet_flag, reverse_flag)
elif env_selector == "name":
res = helpers.umamba_list("-n", tmp_env_name, "--json", quiet_flag)
res = helpers.umamba_list("-n", tmp_env_name, "--json", quiet_flag, reverse_flag)
else:
res = helpers.umamba_list("--json", quiet_flag)
res = helpers.umamba_list("--json", quiet_flag, reverse_flag)

assert len(res) > 2

Expand All @@ -28,6 +31,50 @@ def test_list(tmp_home, tmp_root_prefix, tmp_env_name, tmp_xtensor_env, env_sele
for i in res
)

if reverse_flag == "--reverse":
assert names.index("xtensor") > names.index("xtl")
jjerphan marked this conversation as resolved.
Show resolved Hide resolved
else:
assert names.index("xtensor") < names.index("xtl")


@pytest.mark.parametrize("reverse_flag", ["", "--reverse"])
@pytest.mark.parametrize("quiet_flag", ["", "-q", "--quiet"])
@pytest.mark.parametrize("env_selector", ["", "name", "prefix"])
@pytest.mark.parametrize("shared_pkgs_dirs", [True], indirect=True)
def test_list_no_json(
tmp_home, tmp_root_prefix, tmp_env_name, tmp_xtensor_env, env_selector, quiet_flag, reverse_flag
):
if env_selector == "prefix":
res = helpers.umamba_list("-p", tmp_xtensor_env, quiet_flag, reverse_flag)
elif env_selector == "name":
res = helpers.umamba_list("-n", tmp_env_name, quiet_flag, reverse_flag)
else:
res = helpers.umamba_list(quiet_flag, reverse_flag)

assert len(res) > 10

assert "xtensor" in res
assert "xtl" in res

# This is what res looks like in this case (with or without a header delimiter):
# List of packages in environment: "xxx"

# Name Version Build Channel
# ────────────────────────────────────────────────────
# _libgcc_mutex 0.1 conda_forge conda-forge
# _openmp_mutex 4.5 2_gnu conda-forge
packages = res[res.rindex("Channel") :].split("\n", 1)[1]
jjerphan marked this conversation as resolved.
Show resolved Hide resolved
packages_list = packages.strip().split("\n")[1:]
for package in packages_list:
channel = package.split(" ")[-1]
channel = channel.replace("\r", "")
assert channel == "conda-forge"

if reverse_flag == "--reverse":
assert res.find("xtensor") > res.find("xtl")
else:
assert res.find("xtensor") < res.find("xtl")


@pytest.mark.parametrize("quiet_flag", ["", "-q", "--quiet"])
@pytest.mark.parametrize("shared_pkgs_dirs", [True], indirect=True)
Expand Down
Loading