diff --git a/libmamba/src/api/configuration.cpp b/libmamba/src/api/configuration.cpp index b2df44b90..17f771398 100644 --- a/libmamba/src/api/configuration.cpp +++ b/libmamba/src/api/configuration.cpp @@ -1893,23 +1893,43 @@ namespace mamba context.prefix_params.target_prefix / ".mambarc" }; std::vector sources; + std::set known_locations; + + // We only want to insert locations once, with the least precedence + // to emulate conda's IndexSet behavior + + // This is especially important when the base env is active + // as target_prefix and root_prefix are the same. + // If there is a .condarc in the root_prefix, we don't want + // to load it twice, once for the root_prefix and once for the + // target_prefix with the highest precedence. + auto insertIntoSources = [&](const std::vector& locations) + { + for (auto& location : locations) + { + if (known_locations.insert(location).second) + { + sources.emplace_back(location); + } + } + }; if (level >= RCConfigLevel::kSystemDir) { - sources.insert(sources.end(), system.begin(), system.end()); + insertIntoSources(system); } if ((level >= RCConfigLevel::kRootPrefix) && !context.prefix_params.root_prefix.empty()) { - sources.insert(sources.end(), root.begin(), root.end()); + insertIntoSources(root); } if (level >= RCConfigLevel::kHomeDir) { - sources.insert(sources.end(), conda_user.begin(), conda_user.end()); - sources.insert(sources.end(), mamba_user.begin(), mamba_user.end()); + insertIntoSources(conda_user); + insertIntoSources(mamba_user); } if ((level >= RCConfigLevel::kTargetPrefix) && !context.prefix_params.target_prefix.empty()) { - sources.insert(sources.end(), prefix.begin(), prefix.end()); + insertIntoSources(prefix); } // Sort by precedence diff --git a/libmamba/tests/include/mambatests.hpp b/libmamba/tests/include/mambatests.hpp index 352333668..d9c6355de 100644 --- a/libmamba/tests/include/mambatests.hpp +++ b/libmamba/tests/include/mambatests.hpp @@ -45,7 +45,7 @@ namespace mambatests } // Provides the context object to use in all tests needing it. - // Note that this context is setup to handle logigng and signal handling. + // Note that this context is setup to handle logging and signal handling. inline mamba::Context& context() { return singletons().context; diff --git a/libmamba/tests/src/core/test_configuration.cpp b/libmamba/tests/src/core/test_configuration.cpp index 49f2a6bab..e368b529f 100644 --- a/libmamba/tests/src/core/test_configuration.cpp +++ b/libmamba/tests/src/core/test_configuration.cpp @@ -1112,6 +1112,39 @@ namespace mamba } } + // Regression test for https://github.com/mamba-org/mamba/issues/2704 + TEST_CASE_FIXTURE(Configuration, "deduplicate_rc_files") + { + using namespace detail; + + std::vector sources; + + auto temp_prefix = std::make_unique(); + auto temp_home = std::make_unique(); + + util::set_env("MAMBA_ROOT_PREFIX", temp_prefix->path().string()); + + // the target_prefix is the same as the root_prefix for the base env + util::set_env("MAMBA_TARGET_PREFIX", temp_prefix->path().string()); + util::set_env("HOME", temp_home->path().string()); + util::set_env("USERPROFILE", temp_home->path().string()); + + auto root_config_file = temp_prefix->path() / ".condarc"; + std::ofstream out_root_config(root_config_file.std_path()); + out_root_config << "channel_alias: http://outer.com\n"; + out_root_config.close(); + + auto user_config_file = temp_home->path() / ".condarc"; + std::ofstream out_user_config(user_config_file.std_path()); + out_user_config << "channel_alias: http://inner.com\n"; + out_user_config.close(); + + config.load(); + + REQUIRE_EQ(config.sources().size(), 2); + REQUIRE_EQ(config.at("channel_alias").value(), "http://inner.com"); + } + TEST_CASE_FIXTURE(Configuration, "print_scalar_node") { using namespace detail;