diff --git a/libmamba/src/api/list.cpp b/libmamba/src/api/list.cpp index cfc689c209..d42f8e182a 100644 --- a/libmamba/src/api/list.cpp +++ b/libmamba/src/api/list.cpp @@ -28,6 +28,7 @@ namespace mamba bool explicit_ = false; bool md5 = false; bool canonical = false; + bool export_ = false; }; struct formatted_pkg @@ -218,7 +219,13 @@ namespace mamba { if (options.canonical) { - LOG_WARNING << "Option --canonical ignored because of --explicit"; + LOG_WARNING + << "Option --canonical ignored because --explicit was also provided."; + } + if (options.export_) + { + LOG_WARNING + << "Option --export ignored because --explicit was also provided."; } for (auto p : packages) { @@ -234,12 +241,24 @@ namespace mamba } else if (options.canonical) { + if (options.export_) + { + LOG_WARNING + << "Option --export ignored because --canonical was also provided."; + } for (auto p : packages) { std::cout << p.channel << "/" << p.platform << "::" << p.name << "-" << p.version << "-" << p.build_string << std::endl; } } + else if (options.export_) + { + for (auto p : packages) + { + std::cout << p.name << "=" << p.version << "=" << p.build_string << std::endl; + } + } else { auto requested_specs = prefix_data.history().get_requested_specs_map(); @@ -285,6 +304,7 @@ namespace mamba options.explicit_ = config.at("explicit").value(); options.md5 = config.at("md5").value(); options.canonical = config.at("canonical").value(); + options.export_ = config.at("export").value(); auto channel_context = ChannelContext::make_conda_compatible(config.context()); detail::list_packages(config.context(), regex, channel_context, std::move(options)); diff --git a/micromamba/src/list.cpp b/micromamba/src/list.cpp index 9a68ac4aed..5a3a552507 100644 --- a/micromamba/src/list.cpp +++ b/micromamba/src/list.cpp @@ -53,9 +53,19 @@ 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.") + .description("Output canonical names of packages only. Ignored if --explicit is also provided." + ) ); subcom->add_flag("-c,--canonical", canonical.get_cli_config(), canonical.description()); + + auto& export_ = config.insert( + 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." + ) + ); + subcom->add_flag("-e,--export", export_.get_cli_config(), export_.description()); } void diff --git a/micromamba/tests/test_list.py b/micromamba/tests/test_list.py index 4550ca98db..265e6a84ba 100644 --- a/micromamba/tests/test_list.py +++ b/micromamba/tests/test_list.py @@ -82,6 +82,7 @@ def test_list_no_json( @pytest.mark.parametrize("explicit_flag", ["", "--explicit"]) @pytest.mark.parametrize("md5_flag", ["", "--md5"]) @pytest.mark.parametrize("canonical_flag", ["", "-c", "--canonical"]) +@pytest.mark.parametrize("export_flag", ["", "-e", "--export"]) @pytest.mark.parametrize("env_selector", ["", "name", "prefix"]) @pytest.mark.parametrize("shared_pkgs_dirs", [True], indirect=True) def test_list_subcommands( @@ -93,15 +94,22 @@ def test_list_subcommands( explicit_flag, md5_flag, canonical_flag, + export_flag, ): if env_selector == "prefix": - res = helpers.umamba_list("-p", tmp_xtensor_env, explicit_flag, md5_flag, canonical_flag) + res = helpers.umamba_list( + "-p", tmp_xtensor_env, explicit_flag, md5_flag, canonical_flag, export_flag + ) elif env_selector == "name": - res = helpers.umamba_list("-n", tmp_env_name, explicit_flag, md5_flag, canonical_flag) + res = helpers.umamba_list( + "-n", tmp_env_name, explicit_flag, md5_flag, canonical_flag, export_flag + ) else: - res = helpers.umamba_list(explicit_flag, md5_flag, canonical_flag) + res = helpers.umamba_list(explicit_flag, md5_flag, canonical_flag, export_flag) outputs_list = res.strip().split("\n")[2:] + outputs_list = [i for i in outputs_list if i != "" and not i.startswith("Warning")] + items = ["conda-forge/", "::"] if explicit_flag == "--explicit": for output in outputs_list: assert "/conda-forge/" in output @@ -109,12 +117,15 @@ def test_list_subcommands( assert "#" in output else: assert "#" not in output - else: - if canonical_flag == "--canonical": - items = ["conda-forge/", "::"] - for output in outputs_list: - assert all(i in output for i in items) - assert " " not in output + elif canonical_flag in ["-c", "--canonical"]: + for output in outputs_list: + assert all(i in output for i in items) + assert " " not in output + elif export_flag in ["-e", "--export"]: + items += [" "] + for output in outputs_list: + assert all(i not in output for i in items) + assert len(output.split("=")) == 3 @pytest.mark.parametrize("quiet_flag", ["", "-q", "--quiet"])