Skip to content

Commit 630b62f

Browse files
authored
feat: add reverse flag to list command (#3705)
1 parent 0023a3b commit 630b62f

File tree

3 files changed

+77
-6
lines changed

3 files changed

+77
-6
lines changed

libmamba/src/api/list.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace mamba
2424
{
2525
bool full_name;
2626
bool no_pip;
27+
bool reverse;
2728
};
2829

2930
struct formatted_pkg
@@ -36,6 +37,11 @@ namespace mamba
3637
return a.name < b.name;
3738
}
3839

40+
bool compare_reverse_alphabetically(const formatted_pkg& a, const formatted_pkg& b)
41+
{
42+
return a.name >= b.name;
43+
}
44+
3945
std::string strip_from_filename_and_platform(
4046
const std::string& full_str,
4147
const std::string& filename,
@@ -87,7 +93,18 @@ namespace mamba
8793
{
8894
keys.push_back(pkg.first);
8995
}
90-
std::sort(keys.begin(), keys.end());
96+
if (options.reverse)
97+
{
98+
std::sort(
99+
keys.begin(),
100+
keys.end(),
101+
[](const std::string& a, const std::string& b) { return a >= b; }
102+
);
103+
}
104+
else
105+
{
106+
std::sort(keys.begin(), keys.end());
107+
}
91108

92109
for (const auto& key : keys)
93110
{
@@ -168,7 +185,9 @@ namespace mamba
168185
}
169186
}
170187

171-
std::sort(packages.begin(), packages.end(), compare_alphabetically);
188+
auto comparator = options.reverse ? compare_reverse_alphabetically
189+
: compare_alphabetically;
190+
std::sort(packages.begin(), packages.end(), comparator);
172191

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

212232
auto channel_context = ChannelContext::make_conda_compatible(config.context());
213233
detail::list_packages(config.context(), regex, channel_context, std::move(options));

micromamba/src/list.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ init_list_parser(CLI::App* subcom, Configuration& config)
3434
.description("Do not include pip-only installed packages."));
3535
subcom->add_flag("--no-pip", no_pip.get_cli_config<bool>(), no_pip.description());
3636

37+
auto& reverse = config.insert(
38+
Configurable("reverse", false).group("cli").description("List installed packages in reverse order.")
39+
);
40+
subcom->add_flag("--reverse", reverse.get_cli_config<bool>(), reverse.description());
3741
// TODO: implement this in libmamba/list.cpp
3842
/*auto& canonical = config.insert(Configurable("canonical", false)
3943
.group("cli")

micromamba/tests/test_list.py

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@
77
from . import helpers
88

99

10+
@pytest.mark.parametrize("reverse_flag", ["", "--reverse"])
1011
@pytest.mark.parametrize("quiet_flag", ["", "-q", "--quiet"])
1112
@pytest.mark.parametrize("env_selector", ["", "name", "prefix"])
1213
@pytest.mark.parametrize("shared_pkgs_dirs", [True], indirect=True)
13-
def test_list(tmp_home, tmp_root_prefix, tmp_env_name, tmp_xtensor_env, env_selector, quiet_flag):
14+
def test_list(
15+
tmp_home, tmp_root_prefix, tmp_env_name, tmp_xtensor_env, env_selector, quiet_flag, reverse_flag
16+
):
1417
if env_selector == "prefix":
15-
res = helpers.umamba_list("-p", tmp_xtensor_env, "--json", quiet_flag)
18+
res = helpers.umamba_list("-p", tmp_xtensor_env, "--json", quiet_flag, reverse_flag)
1619
elif env_selector == "name":
17-
res = helpers.umamba_list("-n", tmp_env_name, "--json", quiet_flag)
20+
res = helpers.umamba_list("-n", tmp_env_name, "--json", quiet_flag, reverse_flag)
1821
else:
19-
res = helpers.umamba_list("--json", quiet_flag)
22+
res = helpers.umamba_list("--json", quiet_flag, reverse_flag)
2023

2124
assert len(res) > 2
2225

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

34+
if reverse_flag == "--reverse":
35+
assert names.index("xtensor") > names.index("xtl")
36+
else:
37+
assert names.index("xtensor") < names.index("xtl")
38+
39+
40+
@pytest.mark.parametrize("reverse_flag", ["", "--reverse"])
41+
@pytest.mark.parametrize("quiet_flag", ["", "-q", "--quiet"])
42+
@pytest.mark.parametrize("env_selector", ["", "name", "prefix"])
43+
@pytest.mark.parametrize("shared_pkgs_dirs", [True], indirect=True)
44+
def test_list_no_json(
45+
tmp_home, tmp_root_prefix, tmp_env_name, tmp_xtensor_env, env_selector, quiet_flag, reverse_flag
46+
):
47+
if env_selector == "prefix":
48+
res = helpers.umamba_list("-p", tmp_xtensor_env, quiet_flag, reverse_flag)
49+
elif env_selector == "name":
50+
res = helpers.umamba_list("-n", tmp_env_name, quiet_flag, reverse_flag)
51+
else:
52+
res = helpers.umamba_list(quiet_flag, reverse_flag)
53+
54+
assert len(res) > 10
55+
56+
assert "xtensor" in res
57+
assert "xtl" in res
58+
59+
# This is what res looks like in this case (with or without a header delimiter):
60+
# List of packages in environment: "xxx"
61+
62+
# Name Version Build Channel
63+
# ────────────────────────────────────────────────────
64+
# _libgcc_mutex 0.1 conda_forge conda-forge
65+
# _openmp_mutex 4.5 2_gnu conda-forge
66+
packages = res[res.rindex("Channel") :].split("\n", 1)[1]
67+
packages_list = packages.strip().split("\n")[1:]
68+
for package in packages_list:
69+
channel = package.split(" ")[-1]
70+
channel = channel.replace("\r", "")
71+
assert channel == "conda-forge"
72+
73+
if reverse_flag == "--reverse":
74+
assert res.find("xtensor") > res.find("xtl")
75+
else:
76+
assert res.find("xtensor") < res.find("xtl")
77+
3178

3279
@pytest.mark.parametrize("quiet_flag", ["", "-q", "--quiet"])
3380
@pytest.mark.parametrize("shared_pkgs_dirs", [True], indirect=True)

0 commit comments

Comments
 (0)