Transaction context (#3950)

This commit is contained in:
Johan Mabille 2025-05-23 16:30:02 +02:00 committed by GitHub
parent 6115ac5cf2
commit 7e6435c605
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 473 additions and 486 deletions

View File

@ -64,9 +64,6 @@ namespace mamba
class Logger;
class Context;
std::string env_name(const Context& context, const fs::u8path& prefix);
std::string env_name(const Context& context);
struct ContextOptions
{
bool enable_logging = false;
@ -104,12 +101,6 @@ namespace mamba
bool no_env{ false };
};
struct ThreadsParams
{
std::size_t download_threads{ 5 };
int extract_threads{ 0 };
};
// Configurable
bool experimental = false;
bool experimental_repodata_parsing = true;
@ -131,15 +122,10 @@ namespace mamba
bool extract_sparse = false;
bool dev = false; // TODO this is always used as default=false and isn't set anywhere => to
// be removed if this is the case...
bool dry_run = false;
bool download_only = false;
bool always_yes = false;
bool allow_softlinks = false;
bool always_copy = false;
bool always_softlink = false;
bool register_envs = true;
bool show_anaconda_channel_warnings = true;
@ -167,6 +153,7 @@ namespace mamba
ThreadsParams threads_params;
PrefixParams prefix_params;
ValidationParams validation_params;
LinkParams link_params;
download::RemoteFetchParams remote_fetch_params = {
/* .ssl_verify */ { "" },
@ -222,11 +209,22 @@ namespace mamba
};
}
TransactionParams transaction_params() const
{
return { /* .is_mamba_exe */ command_params.is_mamba_exe,
/* .json_output */ output_params.json,
/* .verbosity */ output_params.verbosity,
/* .shortcut */ shortcuts,
/* .envs_dirs */ envs_dirs,
/* .platform */ platform,
/* .prefix_params */ prefix_params,
/* .link_params */ link_params,
/* .threads_params */ threads_params };
}
std::size_t lock_timeout = 0;
bool use_lockfiles = true;
bool compile_pyc = true;
// Conda compat
bool add_pip_as_python_dependency = true;

View File

@ -10,10 +10,8 @@
#include "mamba/fs/filesystem.hpp"
// TODO: having a file for this single structure is a bit of
// overkill; this should be refactored when we have more structures
// like this (i.e. parameters structures with no dependency on other
// parts of mamba)
// TODO move these structures back to Context.hpp or rename this file
// with a better name when the Context is fully refactored.
namespace mamba
{
struct CommandParams
@ -32,4 +30,32 @@ namespace mamba
fs::u8path conda_prefix;
fs::u8path relocate_prefix;
};
struct LinkParams
{
bool allow_softlinks = false;
bool always_copy = false;
bool always_softlink = false;
bool compile_pyc = true;
};
struct ThreadsParams
{
std::size_t download_threads{ 5 };
int extract_threads{ 0 };
};
struct TransactionParams
{
bool is_mamba_exe;
bool json_output;
int verbosity;
bool shortcuts;
std::vector<fs::u8path> envs_dirs;
std::string platform;
PrefixParams prefix_params;
LinkParams link_params;
ThreadsParams threads_params;
};
}

View File

@ -9,6 +9,7 @@
#include <set>
#include <string>
#include <vector>
#include "fsutil.hpp"
@ -20,6 +21,12 @@ namespace mamba
bool is_conda_environment(const fs::u8path& prefix);
std::string env_name(
const std::vector<fs::u8path>& envs_dirs,
const fs::u8path& root_prefix,
const fs::u8path& prefix
);
class EnvironmentsManager
{
public:

View File

@ -6,7 +6,6 @@
namespace mamba
{
class Context;
class TransactionContext;
namespace fs
@ -14,14 +13,8 @@ namespace mamba
class u8path;
}
void remove_menu_from_json(
const Context& context,
const fs::u8path& json_file,
TransactionContext* transaction_context
);
void create_menu_from_json(
const Context& context,
const fs::u8path& json_file,
TransactionContext* transaction_context
);
void
remove_menu_from_json(const fs::u8path& json_file, const TransactionContext& transaction_context);
void
create_menu_from_json(const fs::u8path& json_file, const TransactionContext& transaction_context);
}

View File

@ -108,9 +108,6 @@ namespace mamba
std::vector<detail::other_pkg_mgr_spec>& other_specs
);
// NOTE: This can be moved to somewhere else if more appropriate
// See: https://github.com/mamba-org/mamba/issues/2288
void print_activation_message(const Context& ctx);
} // namespace mamba
#endif // MAMBA_TRANSACTION_HPP

View File

@ -11,7 +11,7 @@
#include <reproc++/reproc.hpp>
#include "mamba/core/context.hpp"
#include "mamba/core/context_params.hpp"
#include "mamba/core/util.hpp"
#include "mamba/fs/filesystem.hpp"
#include "mamba/specs/match_spec.hpp"
@ -32,62 +32,52 @@ namespace mamba
{
public:
TransactionContext();
struct PythonParams
{
bool has_python = false;
std::string python_version;
std::string old_python_version;
std::string short_python_version;
fs::u8path python_path;
fs::u8path site_packages_path;
};
// TODO: remove this constructor when refactoring
// the MTransaction class.
TransactionContext() = default;
TransactionContext(
TransactionParams transaction_params,
std::pair<std::string, std::string> py_versions,
std::vector<specs::MatchSpec> requested_specs
);
~TransactionContext();
TransactionContext(TransactionContext&&) = default;
explicit TransactionContext(const Context& context);
TransactionContext& operator=(TransactionContext&&) = default;
TransactionContext(
const Context& context,
const fs::u8path& target_prefix,
const std::pair<std::string, std::string>& py_versions,
std::vector<specs::MatchSpec> requested_specs
);
TransactionContext(
const Context& context,
const fs::u8path& target_prefix,
const fs::u8path& relocate_prefix,
const std::pair<std::string, std::string>& py_versions,
std::vector<specs::MatchSpec> requested_specs
);
~TransactionContext();
bool try_pyc_compilation(const std::vector<fs::u8path>& py_files);
void wait_for_pyc_compilation();
bool has_python = false;
fs::u8path target_prefix;
fs::u8path relocate_prefix;
fs::u8path site_packages_path;
fs::u8path python_path;
std::string python_version;
std::string old_python_version;
std::string short_python_version;
bool allow_softlinks = false;
bool always_copy = false;
bool always_softlink = false;
bool compile_pyc = true;
// this needs to be done when python version changes
std::vector<specs::MatchSpec> requested_specs;
const TransactionParams& transaction_params() const;
const PrefixParams& prefix_params() const;
const LinkParams& link_params() const;
const PythonParams& python_params() const;
const Context& context() const
{
return *m_context;
}
const std::vector<specs::MatchSpec>& requested_specs() const;
private:
bool start_pyc_compilation_process();
TransactionParams m_transaction_params;
PythonParams m_python_params;
std::vector<specs::MatchSpec> m_requested_specs;
std::unique_ptr<reproc::process> m_pyc_process = nullptr;
std::unique_ptr<TemporaryFile> m_pyc_script_file = nullptr;
std::unique_ptr<TemporaryFile> m_pyc_compileall = nullptr;
const Context* m_context = nullptr; // TODO: replace by a struct with the necessary params.
void throw_if_not_ready() const;
};
} // namespace mamba

View File

@ -26,8 +26,6 @@
namespace mamba
{
class Context;
const std::regex& token_regex();
const std::regex& http_basicauth_regex();
@ -337,7 +335,7 @@ namespace mamba
quote_for_shell(const std::vector<std::string>& arguments, const std::string& shell = "");
std::size_t clean_trash_files(const fs::u8path& prefix, bool deep_clean);
std::size_t remove_or_rename(const Context& context, const fs::u8path& path);
std::size_t remove_or_rename(const fs::u8path& target_prefix, const fs::u8path& path);
// Unindent a string literal
std::string unindent(const char* p);
@ -364,20 +362,11 @@ namespace mamba
bool ensure_comspec_set();
struct WrappedCallOptions
{
bool is_mamba_exe = false;
bool dev_mode = false;
bool debug_wrapper_scripts = false;
static WrappedCallOptions from_context(const Context&);
};
std::unique_ptr<TemporaryFile> wrap_call(
const fs::u8path& root_prefix,
const fs::u8path& prefix,
const std::vector<std::string>& arguments, // TODO: c++20 replace by std::span
WrappedCallOptions options = {}
bool is_mamba_exe = false
);
struct PreparedWrappedCall
@ -389,7 +378,7 @@ namespace mamba
PreparedWrappedCall prepare_wrapped_call(
const PrefixParams& prefix_params,
const std::vector<std::string>& cmd,
WrappedCallOptions options
bool is_mamba_exe
);
/// Returns `true` if the filename matches names of files which should be interpreted as YAML.

View File

@ -1745,7 +1745,7 @@ namespace mamba
host max concurrency minus the value, zero (default) is the host max
concurrency value.)")));
insert(Configurable("allow_softlinks", &m_context.allow_softlinks)
insert(Configurable("allow_softlinks", &m_context.link_params.allow_softlinks)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
@ -1755,7 +1755,7 @@ namespace mamba
such as when installing on a different filesystem than the one that
the package cache is on.)")));
insert(Configurable("always_copy", &m_context.always_copy)
insert(Configurable("always_copy", &m_context.link_params.always_copy)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
@ -1764,13 +1764,13 @@ namespace mamba
Register a preference that files be copied into a prefix during
install rather than hard-linked.)")));
insert(Configurable("always_softlink", &m_context.always_softlink)
insert(Configurable("always_softlink", &m_context.link_params.always_softlink)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
.needs({ "always_copy" })
.set_post_merge_hook<decltype(m_context.always_softlink)>(
[&](decltype(m_context.always_softlink)& value)
.set_post_merge_hook<decltype(m_context.link_params.always_softlink)>(
[&](decltype(m_context.link_params.always_softlink)& value)
{ return detail::always_softlink_hook(*this, value); }
)
.description("Use soft-link instead of hard-link")
@ -1854,7 +1854,7 @@ namespace mamba
However, some filesystems do not support file locking and locks do not always
make sense - like when on an HPC. Default is true (use a lockfile)")));
insert(Configurable("compile_pyc", &m_context.compile_pyc)
insert(Configurable("compile_pyc", &m_context.link_params.compile_pyc)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()

View File

@ -9,6 +9,7 @@
#include "mamba/api/info.hpp"
#include "mamba/core/channel_context.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/environments_manager.hpp"
#include "mamba/core/util_os.hpp"
#include "mamba/core/virtual_packages.hpp"
#include "mamba/util/environment.hpp"
@ -164,7 +165,11 @@ namespace mamba
std::string name, location;
if (!ctx.prefix_params.target_prefix.empty())
{
name = env_name(ctx);
name = env_name(
ctx.envs_dirs,
ctx.prefix_params.root_prefix,
ctx.prefix_params.target_prefix
);
location = ctx.prefix_params.target_prefix.string();
}
else

View File

@ -19,6 +19,7 @@
#include "mamba/core/package_database_loader.hpp"
#include "mamba/core/pinning.hpp"
#include "mamba/core/transaction.hpp"
#include "mamba/core/util_os.hpp"
#include "mamba/core/virtual_packages.hpp"
#include "mamba/download/downloader.hpp"
#include "mamba/fs/filesystem.hpp"
@ -451,6 +452,36 @@ namespace mamba
namespace
{
void print_activation_message(const Context& ctx)
{
// Check that the target prefix is not active before printing the activation message
if (util::get_env("CONDA_PREFIX") != ctx.prefix_params.target_prefix)
{
// Get the name of the executable used directly from the command.
const auto executable = get_self_exe_path().stem().string();
// Get the name of the environment
const auto environment = env_name(
ctx.envs_dirs,
ctx.prefix_params.root_prefix,
ctx.prefix_params.target_prefix
);
Console::stream() << "\nTo activate this environment, use:\n\n"
" "
<< executable << " activate " << environment
<< "\n\n"
"Or to execute a single command in this environment, use:\n\n"
" "
<< executable
<< " run "
// Use -n or -p depending on if the env_name is a full prefix or
// just a name.
<< (environment == ctx.prefix_params.target_prefix ? "-p " : "-n ")
<< environment << " mycommand\n";
}
}
void install_specs_impl(
Context& ctx,
ChannelContext& channel_context,

View File

@ -175,7 +175,7 @@ namespace mamba
auto [wrapped_command, tmpfile] = prepare_wrapped_call(
ctx.prefix_params,
command,
WrappedCallOptions::from_context(ctx)
ctx.command_params.is_mamba_exe
);
reproc::options options;

View File

@ -379,32 +379,6 @@ namespace mamba
m_authentication_infos_loaded = true;
}
std::string env_name(const Context& context, const fs::u8path& prefix)
{
if (prefix.empty())
{
throw std::runtime_error("Empty path");
}
if (paths_equal(prefix, context.prefix_params.root_prefix))
{
return ROOT_ENV_NAME;
}
fs::u8path maybe_env_dir = prefix.parent_path();
for (const auto& d : context.envs_dirs)
{
if (paths_equal(d, maybe_env_dir))
{
return prefix.filename().string();
}
}
return prefix.string();
}
std::string env_name(const Context& context)
{
return env_name(context, context.prefix_params.target_prefix);
}
void Context::debug_print() const
{
#define PRINT_CTX(xout, xname) fmt::print(xout, "{}: {}\n", #xname, xname)
@ -417,7 +391,7 @@ namespace mamba
PRINT_CTX(out, prefix_params.root_prefix);
PRINT_CTX(out, dry_run);
PRINT_CTX(out, always_yes);
PRINT_CTX(out, allow_softlinks);
PRINT_CTX(out, link_params.allow_softlinks);
PRINT_CTX(out, offline);
PRINT_CTX(out, output_params.quiet);
PRINT_CTX(out, src_params.no_rc);

View File

@ -21,6 +21,31 @@ namespace mamba
return fs::exists(prefix / PREFIX_MAGIC_FILE);
}
std::string env_name(
const std::vector<fs::u8path>& envs_dirs,
const fs::u8path& root_prefix,
const fs::u8path& prefix
)
{
if (prefix.empty())
{
throw std::runtime_error("Empty path");
}
if (paths_equal(prefix, root_prefix))
{
return ROOT_ENV_NAME;
}
fs::u8path maybe_env_dir = prefix.parent_path();
for (const auto& d : envs_dirs)
{
if (paths_equal(d, maybe_env_dir))
{
return prefix.filename().string();
}
}
return prefix.string();
}
EnvironmentsManager::EnvironmentsManager(const Context& context)
: m_context(context)
{

View File

@ -143,18 +143,19 @@ namespace mamba
const python_entry_point_parsed& entry_point
)
{
const fs::u8path& target_prefix = m_context->prefix_params().target_prefix;
#ifdef _WIN32
// We add -script.py to WIN32, and link the conda.exe launcher which will
// automatically find the correct script to launch
std::string win_script = path.string() + "-script.py";
std::string win_script_gen_str = path.generic_string() + "-script.py";
fs::u8path script_path = m_context->target_prefix / win_script;
fs::u8path script_path = target_prefix / win_script;
#else
fs::u8path script_path = m_context->target_prefix / path;
fs::u8path script_path = target_prefix / path;
#endif
if (fs::exists(script_path))
{
m_clobber_warnings.push_back(fs::relative(script_path, m_context->target_prefix).string());
m_clobber_warnings.push_back(fs::relative(script_path, target_prefix).string());
fs::remove(script_path);
}
if (!fs::is_directory(script_path.parent_path()))
@ -164,9 +165,10 @@ namespace mamba
std::ofstream out_file = open_ofstream(script_path);
fs::u8path python_path;
if (m_context->has_python)
if (m_context->python_params().has_python)
{
python_path = m_context->relocate_prefix / m_context->python_path;
python_path = m_context->prefix_params().relocate_prefix
/ m_context->python_params().python_path;
}
if (!python_path.empty())
{
@ -180,19 +182,16 @@ namespace mamba
fs::u8path script_exe = path;
script_exe.replace_extension("exe");
if (fs::exists(m_context->target_prefix / script_exe))
if (fs::exists(target_prefix / script_exe))
{
m_clobber_warnings.push_back(fs::relative(script_exe.string()).string());
fs::remove(m_context->target_prefix / script_exe);
fs::remove(target_prefix / script_exe);
}
std::ofstream conda_exe_f = open_ofstream(
m_context->target_prefix / script_exe,
std::ios::binary
);
std::ofstream conda_exe_f = open_ofstream(target_prefix / script_exe, std::ios::binary);
conda_exe_f.write(reinterpret_cast<char*>(conda_exe), conda_exe_len);
conda_exe_f.close();
make_executable(m_context->target_prefix / script_exe);
make_executable(target_prefix / script_exe);
return std::array<std::string, 2>{ win_script_gen_str, script_exe.generic_string() };
#else
if (!python_path.empty())
@ -316,8 +315,8 @@ namespace mamba
failure
*/
bool run_script(
const Context& context,
const fs::u8path& prefix,
const TransactionParams& transaction_params,
const PrefixParams& prefix_params,
const specs::PackageInfo& pkg_info,
const std::string& action = "post-link",
const std::string& env_prefix = "",
@ -327,12 +326,12 @@ namespace mamba
fs::u8path path;
if (util::on_win)
{
path = prefix / get_bin_directory_short_path()
path = prefix_params.target_prefix / get_bin_directory_short_path()
/ util::concat(".", pkg_info.name, "-", action, ".bat");
}
else
{
path = prefix / get_bin_directory_short_path()
path = prefix_params.target_prefix / get_bin_directory_short_path()
/ util::concat(".", pkg_info.name, "-", action, ".sh");
}
@ -369,10 +368,10 @@ namespace mamba
if (activate)
{
script_file = wrap_call(
context.prefix_params.root_prefix,
prefix,
prefix_params.root_prefix,
prefix_params.target_prefix,
{ "@CALL", path.string() },
WrappedCallOptions::from_context(context)
transaction_params.is_mamba_exe
);
command_args = { comspec.value(), "/d", "/c", script_file->path().string() };
@ -396,10 +395,10 @@ namespace mamba
{
// std::string caller
script_file = wrap_call(
context.prefix_params.root_prefix.string(),
prefix,
prefix_params.root_prefix.string(),
prefix_params.target_prefix,
{ ".", path.string() },
WrappedCallOptions::from_context(context)
transaction_params.is_mamba_exe
);
command_args.push_back(shell_path.string());
command_args.push_back(script_file->path().string());
@ -412,8 +411,8 @@ namespace mamba
}
}
envmap["ROOT_PREFIX"] = context.prefix_params.root_prefix.string();
envmap["PREFIX"] = env_prefix.size() ? env_prefix : prefix.string();
envmap["ROOT_PREFIX"] = prefix_params.root_prefix.string();
envmap["PREFIX"] = env_prefix.size() ? env_prefix : prefix_params.target_prefix.string();
envmap["PKG_NAME"] = pkg_info.name;
envmap["PKG_VERSION"] = pkg_info.version;
envmap["PKG_BUILDNUM"] = std::to_string(pkg_info.build_number);
@ -444,7 +443,7 @@ namespace mamba
auto [status, ec] = reproc::run(command_args, options);
auto msg = get_prefix_messages(envmap["PREFIX"]);
if (context.output_params.json)
if (transaction_params.json_output)
{
// TODO implement cerr also on Console?
std::cerr << msg;
@ -481,14 +480,14 @@ namespace mamba
bool UnlinkPackage::unlink_path(const nlohmann::json& path_data)
{
const auto& context = m_context->context();
std::string subtarget = path_data["_path"].get<std::string>();
fs::u8path dst = m_context->target_prefix / subtarget;
const fs::u8path& target_prefix = m_context->prefix_params().target_prefix;
fs::u8path dst = target_prefix / subtarget;
LOG_TRACE << "Unlinking '" << dst.string() << "'";
std::error_code err;
if (remove_or_rename(context, dst) == 0)
if (remove_or_rename(target_prefix, dst) == 0)
{
LOG_DEBUG << "Error when removing file '" << dst.string() << "' will be ignored";
}
@ -512,7 +511,7 @@ namespace mamba
}
if (is_empty)
{
remove_or_rename(context, parent_path);
remove_or_rename(target_prefix, parent_path);
}
else
{
@ -520,7 +519,7 @@ namespace mamba
}
}
parent_path = parent_path.parent_path();
if (parent_path == m_context->target_prefix)
if (parent_path == target_prefix)
{
break;
}
@ -530,9 +529,9 @@ namespace mamba
bool UnlinkPackage::execute()
{
const auto& context = m_context->context();
// find the recorded JSON file
fs::u8path json = m_context->target_prefix / "conda-meta" / (m_specifier + ".json");
fs::u8path json = m_context->prefix_params().target_prefix / "conda-meta"
/ (m_specifier + ".json");
LOG_INFO << "Unlinking package '" << m_specifier << "'";
LOG_DEBUG << "Use metadata found at '" << json.string() << "'";
@ -545,7 +544,7 @@ namespace mamba
std::string fpath = path["_path"];
if (std::regex_match(fpath, MENU_PATH_REGEX))
{
remove_menu_from_json(context, m_context->target_prefix / fpath, m_context);
remove_menu_from_json(m_context->prefix_params().target_prefix / fpath, *m_context);
}
unlink_path(path);
@ -585,13 +584,16 @@ namespace mamba
fs::u8path dst, rel_dst;
if (noarch_python)
{
rel_dst = get_python_noarch_target_path(subtarget, m_context->site_packages_path);
dst = m_context->target_prefix / rel_dst;
rel_dst = get_python_noarch_target_path(
subtarget,
m_context->python_params().site_packages_path
);
dst = m_context->prefix_params().target_prefix / rel_dst;
}
else
{
rel_dst = subtarget;
dst = m_context->target_prefix / rel_dst;
dst = m_context->prefix_params().target_prefix / rel_dst;
}
fs::u8path src = m_source / subtarget;
@ -623,7 +625,7 @@ namespace mamba
{
// we have to replace the PREFIX stuff in the data
// and copy the file
std::string new_prefix = m_context->relocate_prefix.string();
std::string new_prefix = m_context->prefix_params().relocate_prefix.string();
#ifdef _WIN32
util::replace_all(new_prefix, "\\", "/");
#endif
@ -747,7 +749,7 @@ namespace mamba
#if defined(__APPLE__)
if (binary_changed && m_pkg_info.platform == "osx-arm64")
{
codesign(dst, m_context->context().output_params.verbosity > 1);
codesign(dst, m_context->transaction_params().verbosity > 1);
}
#endif
return std::make_tuple(std::string(validation::sha256sum(dst)), rel_dst.generic_string());
@ -755,8 +757,8 @@ namespace mamba
if ((path_data.path_type == PathType::HARDLINK) || path_data.no_link)
{
bool copy = path_data.no_link || m_context->always_copy;
bool softlink = m_context->always_softlink;
bool copy = path_data.no_link || m_context->link_params().always_copy;
bool softlink = m_context->link_params().always_softlink;
if (!copy && !softlink)
{
@ -765,7 +767,7 @@ namespace mamba
if (lec)
{
softlink = m_context->allow_softlinks;
softlink = m_context->link_params().allow_softlinks;
copy = !softlink;
}
else
@ -827,9 +829,9 @@ namespace mamba
std::vector<fs::u8path> pyc_files;
for (auto& f : py_files)
{
pyc_files.push_back(pyc_path(f, m_context->short_python_version));
pyc_files.push_back(pyc_path(f, m_context->python_params().short_python_version));
}
if (m_context->compile_pyc)
if (m_context->link_params().compile_pyc)
{
m_context->try_pyc_compilation(py_files);
}
@ -846,8 +848,6 @@ namespace mamba
bool LinkPackage::execute()
{
const auto& context = m_context->context();
nlohmann::json index_json, out_json;
LOG_TRACE << "Preparing linking from '" << m_source.string() << "'";
@ -941,13 +941,17 @@ namespace mamba
{
// here we try to avoid recomputing the costly sha256 sum
std::error_code ec;
auto points_to = fs::canonical(m_context->target_prefix / files_record[i], ec);
auto points_to = fs::canonical(
m_context->prefix_params().target_prefix / files_record[i],
ec
);
bool found = false;
if (!ec)
{
for (std::size_t pix = 0; pix < files_record.size(); ++pix)
{
if ((m_context->target_prefix / files_record[pix]) == points_to)
if ((m_context->prefix_params().target_prefix / files_record[pix])
== points_to)
{
if (paths_json["paths"][pix].contains("sha256_in_prefix"))
{
@ -964,7 +968,10 @@ namespace mamba
}
if (!found)
{
bool exists = fs::exists(m_context->target_prefix / files_record[i], ec);
bool exists = fs::exists(
m_context->prefix_params().target_prefix / files_record[i],
ec
);
if (ec)
{
LOG_WARNING << "Could not check existence for " << files_record[i] << ": "
@ -975,7 +982,7 @@ namespace mamba
if (exists)
{
paths_json["paths"][i]["sha256_in_prefix"] = validation::sha256sum(
m_context->target_prefix / files_record[i]
m_context->prefix_params().target_prefix / files_record[i]
);
}
else
@ -994,8 +1001,8 @@ namespace mamba
out_json["paths_data"] = paths_json;
out_json["files"] = files_record;
specs::MatchSpec* requested_spec = nullptr;
for (auto& ms : m_context->requested_specs)
const specs::MatchSpec* requested_spec = nullptr;
for (auto& ms : m_context->requested_specs())
{
if (ms.name().contains(m_pkg_info.name))
{
@ -1025,9 +1032,10 @@ namespace mamba
{
if (std::regex_match(sub_path_json.path, py_file_re))
{
for_compilation.push_back(
get_python_noarch_target_path(sub_path_json.path, m_context->site_packages_path)
);
for_compilation.push_back(get_python_noarch_target_path(
sub_path_json.path,
m_context->python_params().site_packages_path
));
}
}
@ -1072,21 +1080,31 @@ namespace mamba
}
// Create all start menu shortcuts if prefix name doesn't start with underscore
if (util::on_win && context.shortcuts
&& m_context->target_prefix.filename().string()[0] != '_')
if (util::on_win && m_context->transaction_params().shortcuts
&& m_context->prefix_params().target_prefix.filename().string()[0] != '_')
{
for (auto& path : paths_data)
{
if (std::regex_match(path.path, MENU_PATH_REGEX))
{
create_menu_from_json(context, m_context->target_prefix / path.path, m_context);
create_menu_from_json(
m_context->prefix_params().target_prefix / path.path,
*m_context
);
}
}
}
run_script(context, m_context->target_prefix, m_pkg_info, "post-link", "", true);
run_script(
m_context->transaction_params(),
m_context->prefix_params(),
m_pkg_info,
"post-link",
"",
true
);
fs::u8path prefix_meta = m_context->target_prefix / "conda-meta";
fs::u8path prefix_meta = m_context->prefix_params().target_prefix / "conda-meta";
if (!fs::exists(prefix_meta))
{
fs::create_directory(prefix_meta);

View File

@ -16,6 +16,7 @@
#endif
#include "mamba/core/context.hpp"
#include "mamba/core/environments_manager.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/transaction_context.hpp"
#include "mamba/util/string.hpp"
@ -24,9 +25,13 @@ namespace mamba
{
namespace detail
{
std::string get_formatted_env_name(const Context& context, const fs::u8path& target_prefix)
std::string get_formatted_env_name(
const std::vector<fs::u8path>& envs_dirs,
const fs::u8path& root_prefix,
const fs::u8path& target_prefix
)
{
std::string name = env_name(context, target_prefix);
std::string name = env_name(envs_dirs, root_prefix, target_prefix);
if (name.find_first_of("\\/") != std::string::npos)
{
return "";
@ -193,18 +198,11 @@ namespace mamba
#endif
void
replace_variables(const Context& ctx, std::string& text, TransactionContext* transaction_context)
void replace_variables(std::string& text, const TransactionContext& context)
{
fs::u8path root_prefix = ctx.prefix_params.root_prefix;
fs::u8path target_prefix;
std::string py_ver;
if (transaction_context)
{
target_prefix = transaction_context->target_prefix;
py_ver = transaction_context->python_version;
}
fs::u8path root_prefix = context.prefix_params().root_prefix;
fs::u8path target_prefix = context.prefix_params().target_prefix;
std::string py_ver = context.python_params().python_version;
std::string distribution_name = root_prefix.filename().string();
if (distribution_name.size() > 1)
@ -214,7 +212,7 @@ namespace mamba
auto to_forward_slash = [](const fs::u8path& p) { return util::path_to_posix(p.string()); };
auto platform_split = util::split(ctx.platform, "-");
auto platform_split = util::split(context.transaction_params().platform, "-");
std::string platform_bitness;
if (platform_split.size() >= 2)
{
@ -232,7 +230,12 @@ namespace mamba
{ "${PY_VER}", py_ver },
{ "${MENU_DIR}", to_forward_slash(target_prefix / "Menu") },
{ "${DISTRIBUTION_NAME}", distribution_name },
{ "${ENV_NAME}", detail::get_formatted_env_name(ctx, target_prefix) },
{ "${ENV_NAME}",
detail::get_formatted_env_name(
context.transaction_params().envs_dirs,
root_prefix,
target_prefix
) },
{ "${PLATFORM}", platform_bitness },
};
@ -260,20 +263,24 @@ namespace mamba
};
void create_remove_shortcut_impl(
const Context& ctx,
const fs::u8path& json_file,
TransactionContext* transaction_context,
const TransactionContext& context,
[[maybe_unused]] bool remove
)
{
std::string json_content = mamba::read_contents(json_file);
replace_variables(ctx, json_content, transaction_context);
replace_variables(json_content, context);
auto j = nlohmann::json::parse(json_content);
std::string menu_name = j.value("menu_name", "Mamba Shortcuts");
std::string name_suffix;
std::string e_name = detail::get_formatted_env_name(ctx, transaction_context->target_prefix);
const PrefixParams& pp = context.prefix_params();
std::string e_name = detail::get_formatted_env_name(
context.transaction_params().envs_dirs,
pp.root_prefix,
pp.target_prefix
);
if (e_name.size())
{
@ -295,8 +302,8 @@ namespace mamba
// ]
// }
const fs::u8path root_prefix = ctx.prefix_params.root_prefix;
const fs::u8path target_prefix = ctx.prefix_params.target_prefix;
const fs::u8path root_prefix = pp.root_prefix;
const fs::u8path target_prefix = pp.target_prefix;
// using legacy stuff here
const fs::u8path root_py = root_prefix / "python.exe";
@ -474,15 +481,12 @@ namespace mamba
}
}
void remove_menu_from_json(
const Context& context,
const fs::u8path& json_file,
TransactionContext* transaction_context
)
void
remove_menu_from_json(const fs::u8path& json_file, const TransactionContext& transaction_context)
{
try
{
create_remove_shortcut_impl(context, json_file, transaction_context, true);
create_remove_shortcut_impl(json_file, transaction_context, true);
}
catch (const std::exception& e)
{
@ -490,15 +494,12 @@ namespace mamba
}
}
void create_menu_from_json(
const Context& context,
const fs::u8path& json_file,
TransactionContext* transaction_context
)
void
create_menu_from_json(const fs::u8path& json_file, const TransactionContext& transaction_context)
{
try
{
create_remove_shortcut_impl(context, json_file, transaction_context, false);
create_remove_shortcut_impl(json_file, transaction_context, false);
}
catch (const std::exception& e)
{

View File

@ -335,7 +335,7 @@ namespace mamba
auto [wrapped_command, script_file] = prepare_wrapped_call(
context.prefix_params,
command,
WrappedCallOptions::from_context(context)
context.command_params.is_mamba_exe
);
fmt::print(LOG_DEBUG, "Running wrapped script: {}", fmt::join(command, " "));

View File

@ -41,32 +41,6 @@ namespace mamba
{
namespace nl = nlohmann;
void print_activation_message(const Context& ctx)
{
// Check that the target prefix is not active before printing the activation message
if (util::get_env("CONDA_PREFIX") != ctx.prefix_params.target_prefix)
{
// Get the name of the executable used directly from the command.
const auto executable = get_self_exe_path().stem().string();
// Get the name of the environment
const auto environment = env_name(ctx);
Console::stream() << "\nTo activate this environment, use:\n\n"
" "
<< executable << " activate " << environment
<< "\n\n"
"Or to execute a single command in this environment, use:\n\n"
" "
<< executable
<< " run "
// Use -n or -p depending on if the env_name is a full prefix or just
// a name.
<< (environment == ctx.prefix_params.target_prefix ? "-p " : "-n ")
<< environment << " mycommand\n";
}
}
namespace
{
bool need_pkg_download(const specs::PackageInfo& pkg_info, MultiPackageCache& caches)
@ -239,9 +213,7 @@ namespace mamba
}
m_transaction_context = TransactionContext(
ctx,
ctx.prefix_params.target_prefix,
ctx.prefix_params.relocate_prefix,
ctx.transaction_params(),
find_python_version(m_solution, database),
specs_to_install
);
@ -293,9 +265,7 @@ namespace mamba
[&](const auto& item) { requested_specs.push_back(item.spec); }
);
m_transaction_context = TransactionContext(
ctx,
ctx.prefix_params.target_prefix,
ctx.prefix_params.relocate_prefix,
ctx.transaction_params(),
find_python_version(m_solution, database),
std::move(requested_specs)
);
@ -345,9 +315,7 @@ namespace mamba
);
m_transaction_context = TransactionContext(
ctx,
ctx.prefix_params.target_prefix,
ctx.prefix_params.relocate_prefix,
ctx.transaction_params(),
find_python_version(m_solution, database),
std::move(specs_to_install)
);

View File

@ -90,67 +90,39 @@ namespace mamba
}
}
TransactionContext::TransactionContext() = default;
TransactionContext::TransactionContext(const Context& context)
: m_context(&context)
TransactionContext::PythonParams
build_python_params(std::pair<std::string, std::string> py_versions)
{
compile_pyc = this->context().compile_pyc;
TransactionContext::PythonParams res;
if (py_versions.first.size() != 0)
{
res.has_python = true;
res.python_version = std::move(py_versions.first);
res.old_python_version = std::move(py_versions.second);
res.short_python_version = compute_short_python_version(res.python_version);
res.python_path = get_python_short_path(res.short_python_version);
res.site_packages_path = get_python_site_packages_short_path(res.short_python_version);
}
return res;
}
TransactionContext::TransactionContext(
const Context& context,
const fs::u8path& ltarget_prefix,
const std::pair<std::string, std::string>& py_versions,
TransactionParams transaction_params,
std::pair<std::string, std::string> py_versions,
std::vector<specs::MatchSpec> lrequested_specs
)
: has_python(py_versions.first.size() != 0)
, target_prefix(ltarget_prefix)
, relocate_prefix(ltarget_prefix)
, python_version(py_versions.first)
, old_python_version(py_versions.second)
, requested_specs(std::move(lrequested_specs))
, m_context(&context)
: m_transaction_params(std::move(transaction_params))
, m_python_params(build_python_params(std::move(py_versions)))
, m_requested_specs(std::move(lrequested_specs))
{
const auto& ctx = this->context();
compile_pyc = ctx.compile_pyc;
allow_softlinks = ctx.allow_softlinks;
always_copy = ctx.always_copy;
always_softlink = ctx.always_softlink;
std::string old_short_python_version;
if (python_version.size() == 0)
if (m_python_params.python_version.size() == 0)
{
LOG_INFO << "No python version given to TransactionContext, leaving it empty";
}
else
PrefixParams& pp = m_transaction_params.prefix_params;
if (pp.relocate_prefix.empty())
{
short_python_version = compute_short_python_version(python_version);
python_path = get_python_short_path(short_python_version);
site_packages_path = get_python_site_packages_short_path(short_python_version);
}
if (!old_python_version.empty())
{
old_short_python_version = compute_short_python_version(old_python_version);
}
}
TransactionContext::TransactionContext(
const Context& context,
const fs::u8path& ltarget_prefix,
const fs::u8path& lrelocate_prefix,
const std::pair<std::string, std::string>& py_versions,
std::vector<specs::MatchSpec> lrequested_specs
)
: TransactionContext(context, ltarget_prefix, py_versions, std::move(lrequested_specs))
{
if (lrelocate_prefix.empty())
{
relocate_prefix = ltarget_prefix;
}
else
{
relocate_prefix = lrelocate_prefix;
pp.relocate_prefix = pp.target_prefix;
}
}
@ -159,114 +131,14 @@ namespace mamba
wait_for_pyc_compilation();
}
void TransactionContext::throw_if_not_ready() const
{
if (m_context == nullptr)
{
throw mamba_error(
"attempted to use TransactionContext while no Context was specified",
mamba_error_code::internal_failure
);
}
}
bool TransactionContext::start_pyc_compilation_process()
{
throw_if_not_ready();
if (m_pyc_process)
{
return true;
}
#ifndef _WIN32
std::signal(SIGPIPE, SIG_IGN);
#endif
const auto complete_python_path = target_prefix / python_path;
std::vector<std::string> command = {
complete_python_path.string(), "-Wi", "-m", "compileall", "-q", "-l", "-i", "-"
};
auto py_ver_split = util::split(python_version, ".");
try
{
if (std::stoull(py_ver_split[0]) >= 3 && std::stoull(py_ver_split[1]) > 5)
{
m_pyc_compileall = std::make_unique<TemporaryFile>();
std::ofstream compileall_f = open_ofstream(m_pyc_compileall->path());
compile_python_sources(compileall_f);
compileall_f.close();
command = { complete_python_path.string(),
"-Wi",
"-u",
m_pyc_compileall->path().string() };
}
}
catch (const std::exception& e)
{
LOG_ERROR << "Bad conversion of Python version '" << python_version << "': " << e.what();
return false;
}
m_pyc_process = std::make_unique<reproc::process>();
reproc::options options;
#ifndef _WIN32
options.env.behavior = reproc::env::empty;
#endif
std::map<std::string, std::string> envmap;
auto& ctx = context();
envmap["MAMBA_EXTRACT_THREADS"] = std::to_string(ctx.threads_params.extract_threads);
auto qemu_ld_prefix = util::get_env("QEMU_LD_PREFIX");
if (qemu_ld_prefix)
{
envmap["QEMU_LD_PREFIX"] = qemu_ld_prefix.value();
}
options.env.extra = envmap;
options.stop = {
{ reproc::stop::wait, reproc::milliseconds(10000) },
{ reproc::stop::terminate, reproc::milliseconds(5000) },
{ reproc::stop::kill, reproc::milliseconds(2000) },
};
options.redirect.out.type = reproc::redirect::pipe;
options.redirect.err.type = reproc::redirect::pipe;
const std::string cwd = target_prefix.string();
options.working_directory = cwd.c_str();
auto [wrapped_command, script_file] = prepare_wrapped_call(
context().prefix_params,
command,
WrappedCallOptions::from_context(ctx)
);
m_pyc_script_file = std::move(script_file);
LOG_INFO << "Running wrapped python compilation command " << util::join(" ", command);
std::error_code ec = m_pyc_process->start(wrapped_command, options);
if (ec == std::errc::no_such_file_or_directory)
{
LOG_ERROR << "Program not found. Make sure it's available from the PATH. "
<< ec.message();
m_pyc_process = nullptr;
return false;
}
return true;
}
bool TransactionContext::try_pyc_compilation(const std::vector<fs::u8path>& py_files)
{
throw_if_not_ready();
// throw_if_not_ready();
static std::mutex pyc_compilation_mutex;
std::lock_guard<std::mutex> lock(pyc_compilation_mutex);
if (!has_python)
if (!python_params().has_python)
{
LOG_WARNING << "Can't compile pyc: Python not found";
return false;
@ -298,7 +170,7 @@ namespace mamba
void TransactionContext::wait_for_pyc_compilation()
{
throw_if_not_ready();
// throw_if_not_ready();
if (m_pyc_process)
{
@ -338,4 +210,126 @@ namespace mamba
m_pyc_process = nullptr;
}
}
auto TransactionContext::transaction_params() const -> const TransactionParams&
{
return m_transaction_params;
}
auto TransactionContext::prefix_params() const -> const PrefixParams&
{
return m_transaction_params.prefix_params;
}
auto TransactionContext::link_params() const -> const LinkParams&
{
return m_transaction_params.link_params;
}
auto TransactionContext::python_params() const -> const PythonParams&
{
return m_python_params;
}
const std::vector<specs::MatchSpec>& TransactionContext::requested_specs() const
{
return m_requested_specs;
}
bool TransactionContext::start_pyc_compilation_process()
{
// TODO for now, we are sure that the TransactionContext is ready
// here since this method is called by the Link class, which requires
// an initialized TransactionContext in its constructor.
// This should be enforced by removing the default constructor of
// TransactionContext.
// throw_if_not_ready();
if (m_pyc_process)
{
return true;
}
#ifndef _WIN32
std::signal(SIGPIPE, SIG_IGN);
#endif
const auto complete_python_path = prefix_params().target_prefix / python_params().python_path;
std::vector<std::string> command = {
complete_python_path.string(), "-Wi", "-m", "compileall", "-q", "-l", "-i", "-"
};
auto py_ver_split = util::split(python_params().python_version, ".");
try
{
if (std::stoull(py_ver_split[0]) >= 3 && std::stoull(py_ver_split[1]) > 5)
{
m_pyc_compileall = std::make_unique<TemporaryFile>();
std::ofstream compileall_f = open_ofstream(m_pyc_compileall->path());
compile_python_sources(compileall_f);
compileall_f.close();
command = { complete_python_path.string(),
"-Wi",
"-u",
m_pyc_compileall->path().string() };
}
}
catch (const std::exception& e)
{
LOG_ERROR << "Bad conversion of Python version '" << python_params().python_version
<< "': " << e.what();
return false;
}
m_pyc_process = std::make_unique<reproc::process>();
reproc::options options;
#ifndef _WIN32
options.env.behavior = reproc::env::empty;
#endif
std::map<std::string, std::string> envmap;
envmap["MAMBA_EXTRACT_THREADS"] = std::to_string(
m_transaction_params.threads_params.extract_threads
);
auto qemu_ld_prefix = util::get_env("QEMU_LD_PREFIX");
if (qemu_ld_prefix)
{
envmap["QEMU_LD_PREFIX"] = qemu_ld_prefix.value();
}
options.env.extra = envmap;
options.stop = {
{ reproc::stop::wait, reproc::milliseconds(10000) },
{ reproc::stop::terminate, reproc::milliseconds(5000) },
{ reproc::stop::kill, reproc::milliseconds(2000) },
};
options.redirect.out.type = reproc::redirect::pipe;
options.redirect.err.type = reproc::redirect::pipe;
const std::string cwd = prefix_params().target_prefix.string();
options.working_directory = cwd.c_str();
auto [wrapped_command, script_file] = prepare_wrapped_call(
prefix_params(),
command,
transaction_params().is_mamba_exe
);
m_pyc_script_file = std::move(script_file);
LOG_INFO << "Running wrapped python compilation command " << util::join(" ", command);
std::error_code ec = m_pyc_process->start(wrapped_command, options);
if (ec == std::errc::no_such_file_or_directory)
{
LOG_ERROR << "Program not found. Make sure it's available from the PATH. "
<< ec.message();
m_pyc_process = nullptr;
return false;
}
return true;
}
}

View File

@ -50,7 +50,6 @@ extern "C"
#include <nlohmann/json.hpp>
#include <tl/expected.hpp>
#include "mamba/core/context.hpp"
#include "mamba/core/error_handling.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/invoke.hpp"
@ -565,7 +564,7 @@ namespace mamba
return deleted_files;
}
std::size_t remove_or_rename(const Context& context, const fs::u8path& path)
std::size_t remove_or_rename(const fs::u8path& target_prefix, const fs::u8path& path)
{
std::error_code ec;
std::size_t result = 0;
@ -620,13 +619,12 @@ namespace mamba
{
// The conda-meta directory is locked by transaction execute
auto trash_index = open_ofstream(
context.prefix_params.target_prefix / "conda-meta" / "mamba_trash.txt",
target_prefix / "conda-meta" / "mamba_trash.txt",
std::ios::app | std::ios::binary
);
// TODO add some unicode tests here?
trash_index << fs::relative(trash_file, context.prefix_params.target_prefix).string()
<< "\n";
trash_index << fs::relative(trash_file, target_prefix).string() << "\n";
return 1;
}
@ -1395,20 +1393,16 @@ namespace mamba
return infile;
}
WrappedCallOptions WrappedCallOptions::from_context(const Context& context)
namespace
{
return {
/* .is_mamba_exe = */ context.command_params.is_mamba_exe,
/* .dev_mode = */ context.dev,
/* .debug_wrapper_scripts = */ false,
};
constexpr bool debug_wrapper_scripts = false;
}
std::unique_ptr<TemporaryFile> wrap_call(
const fs::u8path& root_prefix,
const fs::u8path& prefix,
const std::vector<std::string>& arguments,
const WrappedCallOptions options
bool is_mamba_exe
)
{
// todo add abspath here
@ -1423,16 +1417,9 @@ namespace mamba
std::string bat_name = get_self_exe_path().stem().string();
if (options.dev_mode)
{
conda_bat = (fs::u8path(CONDA_PACKAGE_ROOT) / "shell" / "condabin" / "conda.bat").string();
}
else
{
conda_bat = util::get_env("CONDA_BAT")
.value_or((fs::absolute(root_prefix) / "condabin" / bat_name).string());
}
if (!fs::exists(conda_bat) && options.is_mamba_exe)
conda_bat = util::get_env("CONDA_BAT")
.value_or((fs::absolute(root_prefix) / "condabin" / bat_name).string());
if (!fs::exists(conda_bat) && is_mamba_exe)
{
// this adds in the needed .bat files for activation
init_root_prefix_cmdexe(root_prefix);
@ -1442,7 +1429,7 @@ namespace mamba
std::ofstream out = open_ofstream(tf->path());
std::string silencer = options.debug_wrapper_scripts ? "" : "@";
std::string silencer = debug_wrapper_scripts ? "" : "@";
out << silencer << "ECHO OFF\n";
out << silencer << "SET PYTHONIOENCODING=utf-8\n";
@ -1452,21 +1439,7 @@ namespace mamba
"do set \"_CONDA_OLD_CHCP=%%B\"\n";
out << silencer << "chcp 65001 > NUL\n";
if (options.dev_mode)
{
// from conda.core.initialize import CONDA_PACKAGE_ROOT
out << silencer << "SET CONDA_DEV=1\n";
// In dev mode, conda is really:
// 'python -m conda'
// *with* PYTHONPATH set.
out << silencer << "SET PYTHONPATH=" << CONDA_PACKAGE_ROOT << "\n";
out << silencer << "SET CONDA_EXE=" << "python.exe" << "\n"; // TODO this should be
// `sys.executable`
out << silencer << "SET _CE_M=-m\n";
out << silencer << "SET _CE_CONDA=conda\n";
}
if (options.debug_wrapper_scripts)
if (debug_wrapper_scripts)
{
out << "echo *** environment before *** 1>&2\n";
out << "SET 1>&2\n";
@ -1475,7 +1448,7 @@ namespace mamba
out << silencer << "CALL \"" << conda_bat << "\" activate " << prefix << "\n";
out << silencer << "IF %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%\n";
if (options.debug_wrapper_scripts)
if (debug_wrapper_scripts)
{
out << "echo *** environment after *** 1>&2\n";
out << "SET 1>&2\n";
@ -1487,33 +1460,15 @@ namespace mamba
std::string shebang, dev_arg;
if (!options.is_mamba_exe)
if (!is_mamba_exe)
{
// During tests, we sometimes like to have a temp env with e.g. an old python
// in it and have it run tests against the very latest development sources.
// For that to work we need extra smarts here, we want it to be instead:
if (options.dev_mode)
if (auto exe = util::get_env("CONDA_EXE"))
{
shebang += std::string(root_prefix / "bin" / "python");
shebang += " -m conda";
dev_arg = "--dev";
shebang = exe.value();
}
else
{
if (auto exe = util::get_env("CONDA_EXE"))
{
shebang = exe.value();
}
else
{
shebang = std::string(root_prefix / "bin" / "conda");
}
}
if (options.dev_mode)
{
// out << ">&2 export PYTHONPATH=" << CONDA_PACKAGE_ROOT << "\n";
shebang = std::string(root_prefix / "bin" / "conda");
}
hook_quoted << std::quoted(shebang, '\'') << " 'shell.posix' 'hook' " << dev_arg;
@ -1525,7 +1480,7 @@ namespace mamba
hook_quoted << "\"$MAMBA_EXE\" 'shell' 'hook' '-s' 'bash' '-r' "
<< std::quoted(root_prefix.string(), '\'');
}
if (options.debug_wrapper_scripts)
if (debug_wrapper_scripts)
{
out << "set -x\n";
out << ">&2 echo \"*** environment before ***\"\n"
@ -1534,7 +1489,7 @@ namespace mamba
}
out << "eval \"$(" << hook_quoted.str() << ")\"\n";
if (!options.is_mamba_exe)
if (!is_mamba_exe)
{
out << "conda activate " << dev_arg << " " << std::quoted(prefix.string()) << "\n";
}
@ -1545,7 +1500,7 @@ namespace mamba
}
if (options.debug_wrapper_scripts)
if (debug_wrapper_scripts)
{
out << ">&2 echo \"*** environment after ***\"\n"
<< ">&2 env\n";
@ -1559,7 +1514,7 @@ namespace mamba
PreparedWrappedCall prepare_wrapped_call(
const PrefixParams& prefix_params,
const std::vector<std::string>& cmd,
WrappedCallOptions options
bool is_mamba_exe
)
{
std::vector<std::string> command_args;
@ -1576,7 +1531,12 @@ namespace mamba
);
}
script_file = wrap_call(prefix_params.root_prefix, prefix_params.target_prefix, cmd, options);
script_file = wrap_call(
prefix_params.root_prefix,
prefix_params.target_prefix,
cmd,
is_mamba_exe
);
command_args = { comspec.value(), "/D", "/C", script_file->path().string() };
}
@ -1594,7 +1554,12 @@ namespace mamba
shell_path = "sh";
}
script_file = wrap_call(prefix_params.root_prefix, prefix_params.target_prefix, cmd, options);
script_file = wrap_call(
prefix_params.root_prefix,
prefix_params.target_prefix,
cmd,
is_mamba_exe
);
command_args.push_back(shell_path.string());
command_args.push_back(script_file->path().string());
}

View File

@ -1080,11 +1080,11 @@ namespace mamba
TEST_BOOL_CONFIGURABLE(retry_clean_cache, config.at("retry_clean_cache").value<bool>());
TEST_BOOL_CONFIGURABLE(allow_softlinks, ctx.allow_softlinks);
TEST_BOOL_CONFIGURABLE(allow_softlinks, ctx.link_params.allow_softlinks);
TEST_BOOL_CONFIGURABLE(always_softlink, ctx.always_softlink);
TEST_BOOL_CONFIGURABLE(always_softlink, ctx.link_params.always_softlink);
TEST_BOOL_CONFIGURABLE(always_copy, ctx.always_copy);
TEST_BOOL_CONFIGURABLE(always_copy, ctx.link_params.always_copy);
TEST_CASE_METHOD(Configuration, "always_softlink_and_copy")
{

View File

@ -12,6 +12,7 @@
#include "mamba/core/channel_context.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/environments_manager.hpp"
#include "mamba/core/fsutil.hpp"
#include "mamba/core/history.hpp"
#include "mamba/core/link.hpp"
@ -131,15 +132,19 @@ namespace mamba
ctx.envs_dirs = { ctx.prefix_params.root_prefix / "envs" };
fs::u8path prefix = "/home/user/micromamba/envs/testprefix";
REQUIRE(env_name(ctx, prefix) == "testprefix");
auto& pp = ctx.prefix_params;
REQUIRE(env_name(ctx.envs_dirs, pp.root_prefix, prefix) == "testprefix");
prefix = "/home/user/micromamba/envs/a.txt";
REQUIRE(env_name(ctx, prefix) == "a.txt");
REQUIRE(env_name(ctx.envs_dirs, pp.root_prefix, prefix) == "a.txt");
prefix = "/home/user/micromamba/envs/a.txt";
REQUIRE(env_name(ctx, prefix) == "a.txt");
REQUIRE(env_name(ctx.envs_dirs, pp.root_prefix, prefix) == "a.txt");
prefix = "/home/user/micromamba/envs/abc/a.txt";
REQUIRE(env_name(ctx, prefix) == "/home/user/micromamba/envs/abc/a.txt");
REQUIRE(
env_name(ctx.envs_dirs, pp.root_prefix, prefix)
== "/home/user/micromamba/envs/abc/a.txt"
);
prefix = "/home/user/env";
REQUIRE(env_name(ctx, prefix) == "/home/user/env");
REQUIRE(env_name(ctx.envs_dirs, pp.root_prefix, prefix) == "/home/user/env");
}
}
}

View File

@ -929,10 +929,10 @@ bind_submodule_impl(pybind11::module_ m)
.def_readwrite("json", &Context::OutputParams::json)
.def_readwrite("quiet", &Context::OutputParams::quiet);
py::class_<Context::ThreadsParams>(ctx, "ThreadsParams")
py::class_<ThreadsParams>(ctx, "ThreadsParams")
.def(py::init<>())
.def_readwrite("download_threads", &Context::ThreadsParams::download_threads)
.def_readwrite("extract_threads", &Context::ThreadsParams::extract_threads);
.def_readwrite("download_threads", &ThreadsParams::download_threads)
.def_readwrite("extract_threads", &ThreadsParams::extract_threads);
py::class_<PrefixParams>(ctx, "PrefixParams")
.def(py::init<>())

View File

@ -328,7 +328,7 @@ set_env_command(CLI::App* com, mamba::Configuration& config)
{
const auto& prefix = ctx.prefix_params.target_prefix;
// Remove env directory or rename it (e.g. if used)
remove_or_rename(ctx, mamba::util::expand_home(prefix.string()));
mamba::remove_or_rename(prefix, mamba::util::expand_home(prefix.string()));
mamba::EnvironmentsManager env_manager{ ctx };
// Unregister environment

View File

@ -17,6 +17,7 @@
#include "mamba/api/configuration.hpp"
#include "mamba/api/install.hpp"
#include "mamba/core/environments_manager.hpp"
#include "mamba/core/error_handling.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/util_os.hpp"
@ -66,7 +67,7 @@ set_ps_command(CLI::App* subcom, Context& context)
auto prefix = el["prefix"].get<std::string>();
if (!prefix.empty())
{
prefix = env_name(context, prefix);
prefix = env_name(context.envs_dirs, context.prefix_params.root_prefix, prefix);
}
table.add_row({