mirror of https://github.com/mamba-org/mamba.git
feat: add option revision to install command (#3966)
Co-authored-by: Klaim (Joël Lamotte) <142265+Klaim@users.noreply.github.com>
This commit is contained in:
parent
2c3ddf1eef
commit
e3e5f54540
|
@ -99,7 +99,6 @@ It can significantly reduce your CI setup time by:
|
||||||
|
|
||||||
While `mamba` and `micromamba` are generally a drop-in replacement for `conda` there are some differences:
|
While `mamba` and `micromamba` are generally a drop-in replacement for `conda` there are some differences:
|
||||||
|
|
||||||
- `mamba` and `micromamba` do no support revisions (for discussions, see <https://github.com/mamba-org/mamba/issues/803>)
|
|
||||||
- `mamba` and `micromamba` normalize `MatchSpec` strings to the simplest form, whereas `conda` use a more verbose form
|
- `mamba` and `micromamba` normalize `MatchSpec` strings to the simplest form, whereas `conda` use a more verbose form
|
||||||
This can lead to slight differences in the output of `conda env export` and `mamba env export`.
|
This can lead to slight differences in the output of `conda env export` and `mamba env export`.
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ namespace mamba
|
||||||
|
|
||||||
void install(Configuration& config);
|
void install(Configuration& config);
|
||||||
|
|
||||||
|
void install_revision(Configuration& config, std::size_t revision);
|
||||||
|
|
||||||
void install_specs(
|
void install_specs(
|
||||||
Context& ctx,
|
Context& ctx,
|
||||||
ChannelContext& channel_context,
|
ChannelContext& channel_context,
|
||||||
|
@ -130,6 +132,8 @@ namespace mamba
|
||||||
inline void to_json(nlohmann::json&, const other_pkg_mgr_spec&)
|
inline void to_json(nlohmann::json&, const other_pkg_mgr_spec&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void install_revision(Context& ctx, ChannelContext& channel_context, std::size_t revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,8 +66,9 @@ namespace mamba
|
||||||
*/
|
*/
|
||||||
struct PackageDiff
|
struct PackageDiff
|
||||||
{
|
{
|
||||||
std::unordered_map<std::string, specs::PackageInfo> removed_pkg_diff;
|
using package_diff_map = std::unordered_map<std::string, specs::PackageInfo>;
|
||||||
std::unordered_map<std::string, specs::PackageInfo> installed_pkg_diff;
|
package_diff_map removed_pkg_diff;
|
||||||
|
package_diff_map installed_pkg_diff;
|
||||||
|
|
||||||
[[nodiscard]] static PackageDiff
|
[[nodiscard]] static PackageDiff
|
||||||
from_revision(const std::vector<History::UserRequest>& user_requests, std::size_t target_revision);
|
from_revision(const std::vector<History::UserRequest>& user_requests, std::size_t target_revision);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "mamba/core/context.hpp"
|
#include "mamba/core/context.hpp"
|
||||||
#include "mamba/core/env_lockfile.hpp"
|
#include "mamba/core/env_lockfile.hpp"
|
||||||
#include "mamba/core/environments_manager.hpp"
|
#include "mamba/core/environments_manager.hpp"
|
||||||
|
#include "mamba/core/history.hpp"
|
||||||
#include "mamba/core/output.hpp"
|
#include "mamba/core/output.hpp"
|
||||||
#include "mamba/core/package_cache.hpp"
|
#include "mamba/core/package_cache.hpp"
|
||||||
#include "mamba/core/package_database_loader.hpp"
|
#include "mamba/core/package_database_loader.hpp"
|
||||||
|
@ -304,6 +305,24 @@ namespace mamba
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void install_revision(Configuration& config, std::size_t revision)
|
||||||
|
{
|
||||||
|
config.at("use_target_prefix_fallback").set_value(true);
|
||||||
|
config.at("use_default_prefix_fallback").set_value(true);
|
||||||
|
config.at("use_root_prefix_fallback").set_value(true);
|
||||||
|
config.at("target_prefix_checks")
|
||||||
|
.set_value(
|
||||||
|
MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_NOT_ALLOW_MISSING_PREFIX
|
||||||
|
| MAMBA_NOT_ALLOW_NOT_ENV_PREFIX | MAMBA_EXPECT_EXISTING_PREFIX
|
||||||
|
);
|
||||||
|
config.load();
|
||||||
|
|
||||||
|
auto& context = config.context();
|
||||||
|
auto channel_context = ChannelContext::make_conda_compatible(context);
|
||||||
|
|
||||||
|
detail::install_revision(context, channel_context, revision);
|
||||||
|
}
|
||||||
|
|
||||||
void install(Configuration& config)
|
void install(Configuration& config)
|
||||||
{
|
{
|
||||||
auto& ctx = config.context();
|
auto& ctx = config.context();
|
||||||
|
@ -542,18 +561,18 @@ namespace mamba
|
||||||
};
|
};
|
||||||
add_spdlog_logger_to_database(db);
|
add_spdlog_logger_to_database(db);
|
||||||
|
|
||||||
auto exp_load = load_channels(ctx, channel_context, db, package_caches);
|
auto maybe_load = load_channels(ctx, channel_context, db, package_caches);
|
||||||
if (!exp_load)
|
if (!maybe_load)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(exp_load.error().what());
|
throw std::runtime_error(maybe_load.error().what());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto exp_prefix_data = PrefixData::create(ctx.prefix_params.target_prefix, channel_context);
|
auto maybe_prefix_data = PrefixData::create(ctx.prefix_params.target_prefix, channel_context);
|
||||||
if (!exp_prefix_data)
|
if (!maybe_prefix_data)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(exp_prefix_data.error().what());
|
throw std::runtime_error(maybe_prefix_data.error().what());
|
||||||
}
|
}
|
||||||
PrefixData& prefix_data = exp_prefix_data.value();
|
PrefixData& prefix_data = maybe_prefix_data.value();
|
||||||
|
|
||||||
load_installed_packages_in_database(ctx, db, prefix_data);
|
load_installed_packages_in_database(ctx, db, prefix_data);
|
||||||
|
|
||||||
|
@ -741,15 +760,15 @@ namespace mamba
|
||||||
// context. We need to create channels from the specs to be able
|
// context. We need to create channels from the specs to be able
|
||||||
// to download packages.
|
// to download packages.
|
||||||
init_channels_from_package_urls(ctx, channel_context, specs);
|
init_channels_from_package_urls(ctx, channel_context, specs);
|
||||||
auto exp_prefix_data = PrefixData::create(ctx.prefix_params.target_prefix, channel_context);
|
auto maybe_prefix_data = PrefixData::create(ctx.prefix_params.target_prefix, channel_context);
|
||||||
if (!exp_prefix_data)
|
if (!maybe_prefix_data)
|
||||||
{
|
{
|
||||||
// TODO: propagate tl::expected mechanism
|
// TODO: propagate tl::expected mechanism
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
fmt::format("could not load prefix data: {}", exp_prefix_data.error().what())
|
fmt::format("could not load prefix data: {}", maybe_prefix_data.error().what())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
PrefixData& prefix_data = exp_prefix_data.value();
|
PrefixData& prefix_data = maybe_prefix_data.value();
|
||||||
|
|
||||||
MultiPackageCache pkg_caches(ctx.pkgs_dirs, ctx.validation_params);
|
MultiPackageCache pkg_caches(ctx.pkgs_dirs, ctx.validation_params);
|
||||||
|
|
||||||
|
@ -1164,5 +1183,82 @@ namespace mamba
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
get_all_pkg_info(PackageDiff::package_diff_map::value_type& pkg, solver::libsolv::Database& db)
|
||||||
|
{
|
||||||
|
const auto ms = pkg.second.name + "==" + pkg.second.version + " ="
|
||||||
|
+ pkg.second.build_string;
|
||||||
|
db.for_each_package_matching(
|
||||||
|
specs::MatchSpec::parse(ms).value(),
|
||||||
|
[&](specs::PackageInfo&& pkg_info) { pkg.second = pkg_info; }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
install_revision(Context& ctx, ChannelContext& channel_context, std::size_t target_revision)
|
||||||
|
{
|
||||||
|
auto maybe_prefix_data = PrefixData::create(ctx.prefix_params.target_prefix, channel_context);
|
||||||
|
if (!maybe_prefix_data)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(maybe_prefix_data.error().what());
|
||||||
|
}
|
||||||
|
PrefixData& prefix_data = maybe_prefix_data.value();
|
||||||
|
const auto user_requests = prefix_data.history().get_user_requests();
|
||||||
|
|
||||||
|
PackageDiff pkg_diff = PackageDiff::from_revision(user_requests, target_revision);
|
||||||
|
auto removed_pkg_diff = pkg_diff.removed_pkg_diff;
|
||||||
|
auto installed_pkg_diff = pkg_diff.installed_pkg_diff;
|
||||||
|
|
||||||
|
MultiPackageCache package_caches{ ctx.pkgs_dirs, ctx.validation_params };
|
||||||
|
|
||||||
|
solver::libsolv::Database db{ channel_context.params() };
|
||||||
|
add_spdlog_logger_to_database(db);
|
||||||
|
|
||||||
|
auto maybe_load = load_channels(ctx, channel_context, db, package_caches);
|
||||||
|
if (!maybe_load)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(maybe_load.error().what());
|
||||||
|
}
|
||||||
|
|
||||||
|
load_installed_packages_in_database(ctx, db, prefix_data);
|
||||||
|
|
||||||
|
for (auto& pkg : removed_pkg_diff)
|
||||||
|
{
|
||||||
|
get_all_pkg_info(pkg, db);
|
||||||
|
}
|
||||||
|
for (auto& pkg : installed_pkg_diff)
|
||||||
|
{
|
||||||
|
get_all_pkg_info(pkg, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto execute_transaction = [&](MTransaction& transaction)
|
||||||
|
{
|
||||||
|
if (ctx.output_params.json)
|
||||||
|
{
|
||||||
|
transaction.log_json();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto prompt_entry = transaction.prompt(ctx, channel_context);
|
||||||
|
if (prompt_entry)
|
||||||
|
{
|
||||||
|
transaction.execute(ctx, channel_context, prefix_data);
|
||||||
|
}
|
||||||
|
return prompt_entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<specs::PackageInfo> pkgs_to_remove;
|
||||||
|
std::vector<specs::PackageInfo> pkgs_to_install;
|
||||||
|
for (const auto& [_, pkg] : installed_pkg_diff)
|
||||||
|
{
|
||||||
|
pkgs_to_remove.push_back(pkg);
|
||||||
|
}
|
||||||
|
for (const auto& [_, pkg] : removed_pkg_diff)
|
||||||
|
{
|
||||||
|
pkgs_to_install.push_back(pkg);
|
||||||
|
}
|
||||||
|
auto transaction = MTransaction(ctx, db, pkgs_to_remove, pkgs_to_install, package_caches);
|
||||||
|
execute_transaction(transaction);
|
||||||
|
}
|
||||||
} // detail
|
} // detail
|
||||||
} // mamba
|
} // mamba
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "mamba/api/configuration.hpp"
|
#include "mamba/api/configuration.hpp"
|
||||||
#include "mamba/api/install.hpp"
|
#include "mamba/api/install.hpp"
|
||||||
|
|
||||||
|
@ -24,5 +26,16 @@ set_install_command(CLI::App* subcom, Configuration& config)
|
||||||
force_reinstall.description()
|
force_reinstall.description()
|
||||||
);
|
);
|
||||||
|
|
||||||
subcom->callback([&] { return mamba::install(config); });
|
static std::optional<std::size_t> revision = std::nullopt;
|
||||||
|
subcom->callback(
|
||||||
|
[&]
|
||||||
|
{
|
||||||
|
if (revision.has_value())
|
||||||
|
{
|
||||||
|
return mamba::install_revision(config, revision.value());
|
||||||
|
}
|
||||||
|
return mamba::install(config);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
subcom->add_option("--revision", revision, "Revert to the specified revision.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ from pathlib import Path
|
||||||
from packaging.version import Version
|
from packaging.version import Version
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import re
|
||||||
|
|
||||||
# Need to import everything to get fixtures
|
# Need to import everything to get fixtures
|
||||||
from .helpers import * # noqa: F403
|
from .helpers import * # noqa: F403
|
||||||
|
@ -843,3 +844,20 @@ def test_dry_run_pip_section(tmp_home, tmp_root_prefix, tmp_path):
|
||||||
# Check that the packages are not installed using `pip`
|
# Check that the packages are not installed using `pip`
|
||||||
res = helpers.umamba_run("-p", env_prefix, "pip", "list")
|
res = helpers.umamba_run("-p", env_prefix, "pip", "list")
|
||||||
assert "numpy" not in res
|
assert "numpy" not in res
|
||||||
|
|
||||||
|
|
||||||
|
def test_install_revision(tmp_home, tmp_root_prefix):
|
||||||
|
env_name = "myenv"
|
||||||
|
helpers.create("-n", env_name, "python=3.8")
|
||||||
|
helpers.install("-n", env_name, "xtl=0.7.2", "nlohmann_json=3.12.0")
|
||||||
|
helpers.update("-n", env_name, "xtl")
|
||||||
|
helpers.uninstall("-n", env_name, "nlohmann_json")
|
||||||
|
helpers.install("-n", env_name, "--revision", "1")
|
||||||
|
res = helpers.umamba_list(
|
||||||
|
"-n",
|
||||||
|
env_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
xtl_regex = re.compile(r"xtl\s+0.7.2")
|
||||||
|
assert xtl_regex.search(res)
|
||||||
|
assert "nlohmann_json" in res
|
||||||
|
|
Loading…
Reference in New Issue