Context: not a singleton (#2615)

Context is not a singleton anymore.

---------

Co-authored-by: Johan Mabille <johan.mabille@gmail.com>
This commit is contained in:
Klaim (Joël Lamotte) 2023-09-05 10:55:43 +02:00 committed by GitHub
parent 0a5ed8d71f
commit bbac096a04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
112 changed files with 1961 additions and 1075 deletions

View File

@ -9,7 +9,10 @@
namespace mamba
{
class Context;
class Configuration;
struct ContextOptions;
class MainExecutor;
}
#ifdef __cplusplus
@ -17,7 +20,13 @@ extern "C"
{
#endif
mamba::Configuration* mamba_new_configuration();
mamba::MainExecutor* mamba_new_main_executor();
void mamba_delete_main_executor(mamba::MainExecutor* main_executor);
mamba::Context* mamba_new_context(mamba::ContextOptions* options);
void mamba_delete_context(mamba::Context* context);
mamba::Configuration* mamba_new_configuration(mamba::Context* context);
void mamba_delete_configuration(mamba::Configuration* config);
int mamba_create(mamba::Configuration* config);

View File

@ -388,7 +388,7 @@ namespace mamba
{
public:
Configuration();
explicit Configuration(Context& ctx);
~Configuration();
std::map<std::string, Configurable>& config();
@ -403,6 +403,15 @@ namespace mamba
std::vector<fs::u8path> sources() const;
std::vector<fs::u8path> valid_sources() const;
Context& context()
{
return m_context;
}
const Context& context() const
{
return m_context;
}
void set_rc_values(std::vector<fs::u8path> possible_rc_paths, const RCConfigLevel& level);
void load();
@ -450,11 +459,14 @@ namespace mamba
static YAML::Node load_rc_file(const fs::u8path& file);
static std::vector<fs::u8path> compute_default_rc_sources(const RCConfigLevel& level);
static std::vector<fs::u8path>
compute_default_rc_sources(const Context& context, const RCConfigLevel& level);
std::vector<fs::u8path>
get_existing_rc_sources(const std::vector<fs::u8path>& possible_rc_paths);
Context& m_context;
std::vector<fs::u8path> m_sources;
std::vector<fs::u8path> m_valid_sources;
std::map<fs::u8path, YAML::Node> m_rc_yaml_nodes_cache;
@ -644,6 +656,8 @@ namespace mamba
template <class T>
void ConfigurableImpl<T>::compute(int options, const ConfigurationLevel& level)
{
assert(m_config); // REVIEW: should this be a if & throw?
bool hook_disabled = options & MAMBA_CONF_DISABLE_HOOK;
bool force_compute = options & MAMBA_CONF_FORCE_COMPUTE;
@ -663,7 +677,7 @@ namespace mamba
);
}
auto& ctx = Context::instance();
const auto& ctx = m_config->context();
m_sources.clear();
m_values.clear();

View File

@ -55,9 +55,9 @@ namespace mamba
namespace detail
{
void create_target_directory(const fs::u8path prefix);
void create_target_directory(const Context& context, const fs::u8path prefix);
void create_empty_target(const fs::u8path& prefix);
void create_empty_target(const Context& context, const fs::u8path& prefix);
void file_specs_hook(Configuration& config, std::vector<std::string>& file_specs);
@ -81,9 +81,9 @@ namespace mamba
std::vector<other_pkg_mgr_spec> others_pkg_mgrs_specs;
};
bool eval_selector(const std::string& selector);
bool eval_selector(const std::string& selector, const std::string& platform);
yaml_file_contents read_yaml_file(fs::u8path yaml_file);
yaml_file_contents read_yaml_file(fs::u8path yaml_file, const std::string platform);
std::tuple<std::vector<PackageInfo>, std::vector<MatchSpec>>
parse_urls_to_package_info(const std::vector<std::string>& urls, ChannelContext& channel_context);

View File

@ -11,17 +11,21 @@
#include <string_view>
#include "mamba/core/mamba_fs.hpp"
#include "mamba/core/palette.hpp"
namespace mamba
{
void shell_init(const std::string& shell_type, const fs::u8path& prefix);
void shell_deinit(const std::string& shell_type, const fs::u8path& prefix);
void shell_reinit(const fs::u8path& prefix);
void shell_hook(const std::string& shell_type);
void shell_activate(const fs::u8path& prefix, const std::string& shell_type, bool stack);
void shell_reactivate(const std::string& shell_type);
void shell_deactivate(const std::string& shell_type);
void shell_enable_long_path_support();
class Context;
void shell_init(Context& ctx, const std::string& shell_type, const fs::u8path& prefix);
void shell_deinit(Context& ctx, const std::string& shell_type, const fs::u8path& prefix);
void shell_reinit(Context& ctx, const fs::u8path& prefix);
void shell_hook(Context& ctx, const std::string& shell_type);
void
shell_activate(Context& ctx, const fs::u8path& prefix, const std::string& shell_type, bool stack);
void shell_reactivate(Context& ctx, const std::string& shell_type);
void shell_deactivate(Context& ctx, const std::string& shell_type);
void shell_enable_long_path_support(Palette palette = Palette::no_color());
}
#endif

View File

@ -18,6 +18,8 @@
namespace mamba
{
class Context;
enum class ActivationType
{
ACTIVATE,
@ -93,8 +95,9 @@ namespace mamba
protected:
Activator();
explicit Activator(const Context& context);
const Context& m_context;
bool m_stack = false;
ActivationType m_action;
@ -105,7 +108,10 @@ namespace mamba
{
public:
PosixActivator() = default;
explicit PosixActivator(const Context& context)
: Activator(context)
{
}
virtual ~PosixActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override;
@ -123,7 +129,10 @@ namespace mamba
{
public:
CshActivator() = default;
explicit CshActivator(const Context& context)
: Activator(context)
{
}
virtual ~CshActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override;
@ -141,7 +150,10 @@ namespace mamba
{
public:
CmdExeActivator() = default;
explicit CmdExeActivator(const Context& context)
: Activator(context)
{
}
virtual ~CmdExeActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override;
@ -159,7 +171,10 @@ namespace mamba
{
public:
PowerShellActivator() = default;
explicit PowerShellActivator(const Context& context)
: Activator(context)
{
}
virtual ~PowerShellActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override;
@ -177,7 +192,10 @@ namespace mamba
{
public:
XonshActivator() = default;
explicit XonshActivator(const Context& context)
: Activator(context)
{
}
virtual ~XonshActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override;
@ -195,7 +213,10 @@ namespace mamba
{
public:
FishActivator() = default;
explicit FishActivator(const Context& context)
: Activator(context)
{
}
virtual ~FishActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override;

View File

@ -18,7 +18,10 @@
namespace mamba
{
class Context;
std::vector<std::string> get_known_platforms();
// Note: Channels can only be created using ChannelContext.
class Channel
{
@ -37,7 +40,8 @@ namespace mamba
const std::optional<std::string>& auth() const;
const std::optional<std::string>& token() const;
const std::optional<std::string>& package_filename() const;
const validation::RepoChecker& repo_checker(MultiPackageCache& caches) const;
const validation::RepoChecker&
repo_checker(Context& context, MultiPackageCache& caches) const;
std::string base_url() const;
std::string platform_url(std::string platform, bool with_credential = true) const;
@ -70,6 +74,12 @@ namespace mamba
// This is used to make sure that there is a unique repo for every channel
mutable std::unique_ptr<validation::RepoChecker> p_repo_checker;
// Note: as long as Channel is not a regular value-type and we want each
// instance only possible to create through ChannelContext, we need
// to have Channel's constructor only available to ChannelContext,
// therefore enabling it's use through this `friend` statement.
// However, all this should be removed as soon as Channel is changed to
// be a regular value-type (regular as in the regular concept).
friend class ChannelContext;
};
@ -87,7 +97,7 @@ namespace mamba
using channel_map = std::map<std::string, Channel>;
using multichannel_map = std::map<std::string, std::vector<std::string>>;
ChannelContext();
ChannelContext(Context& context);
~ChannelContext();
ChannelContext(const ChannelContext&) = delete;
@ -101,8 +111,14 @@ namespace mamba
const Channel& get_channel_alias() const;
const channel_map& get_custom_channels() const;
Context& context() const
{
return m_context;
}
private:
Context& m_context;
ChannelCache m_channel_cache;
Channel m_channel_alias;
channel_map m_custom_channels;

View File

@ -9,7 +9,6 @@
#include <map>
#include <optional>
#include <regex>
#include <string>
#include <vector>
@ -31,6 +30,13 @@ namespace mamba
kEnabled
};
struct ValidationOptions
{
VerificationLevel safety_checks = VerificationLevel::kWarn;
bool extra_safety_checks = false;
bool verify_artifacts = false;
};
enum class ChannelPriority
{
@ -53,8 +59,15 @@ namespace mamba
};
class Logger;
class Context;
std::string env_name(const fs::u8path& prefix);
std::string env_name(const Context& context, const fs::u8path& prefix);
std::string env_name(const Context& context);
struct ContextOptions
{
bool enable_logging_and_signal_handling = false;
};
// Context singleton class
class Context
@ -163,9 +176,7 @@ namespace mamba
// add start menu shortcuts on Windows (not implemented on Linux / macOS)
bool shortcuts = true;
VerificationLevel safety_checks = VerificationLevel::kWarn;
bool extra_safety_checks = false;
bool verify_artifacts = false;
ValidationOptions validation_params;
// debug helpers
bool keep_temp_files = false;
@ -195,7 +206,7 @@ namespace mamba
std::string host_platform = std::string(specs::build_platform_name());
std::string platform = std::string(specs::build_platform_name());
std::vector<std::string> platforms();
std::vector<std::string> platforms() const;
std::vector<std::string> channels;
std::map<std::string, std::string> custom_channels;
@ -227,13 +238,6 @@ namespace mamba
bool repodata_use_zst = true;
std::vector<std::string> repodata_has_zst = { "https://conda.anaconda.org/conda-forge" };
// usernames on anaconda.org can have a underscore, which influences the
// first two characters
const std::regex token_regex{ "/t/([a-zA-Z0-9-_]{0,2}[a-zA-Z0-9-]*)" };
const std::regex http_basicauth_regex{ "(://|^)([^\\s]+):([^\\s]+)@" };
static Context& instance();
Context(const Context&) = delete;
Context& operator=(const Context&) = delete;
@ -246,11 +250,12 @@ namespace mamba
void set_verbosity(int lvl);
void set_log_level(log_level level);
protected:
Context();
Context(const ContextOptions& options = {});
~Context();
// Enables the provided context to drive the logging system and setup signal handling.
// This function must be called only for one Context in the lifetime of the program.
static void enable_logging_and_signal_handling(Context& context);
private:
@ -265,6 +270,8 @@ namespace mamba
TaskSynchronizer tasksync;
};
} // namespace mamba
#endif // MAMBA_CONTEXT_HPP

View File

@ -14,6 +14,8 @@
namespace mamba
{
class Context;
const char PREFIX_MAGIC_FILE[] = "conda-meta/history";
bool is_conda_environment(const fs::u8path& prefix);
@ -22,12 +24,15 @@ namespace mamba
{
public:
explicit EnvironmentsManager(const Context& context);
void register_env(const fs::u8path& location);
void unregister_env(const fs::u8path& location);
std::set<fs::u8path> list_all_known_prefixes();
private:
const Context& m_context;
std::set<std::string>
clean_environments_txt(const fs::u8path& env_txt_file, const fs::u8path& location);
std::string remove_trailing_slash(std::string p);

View File

@ -31,6 +31,7 @@ namespace mamba
selfupdate_failure,
satisfiablitity_error,
user_interrupted,
incorrect_usage,
};
class mamba_error : public std::runtime_error

View File

@ -13,12 +13,13 @@
#include <thread>
#include <vector>
#include "mamba/core/error_handling.hpp"
namespace mamba
{
class MainExecutorError : public std::runtime_error
struct MainExecutorError : public mamba_error
{
using std::runtime_error::runtime_error;
using mamba_error::mamba_error;
};
// Main execution resource (for example threads) handler for this library.

View File

@ -28,6 +28,7 @@ namespace mamba
struct ZstdStream;
struct Bzip2Stream;
class Context;
class CURLHandle;
class CURLMultiHandle;
@ -36,13 +37,14 @@ namespace mamba
******************************/
void get_config(
const Context& context,
bool& set_low_speed_opt,
bool& set_ssl_no_revoke,
long& connect_timeout_secs,
std::string& ssl_verify
);
std::size_t get_default_retry_timeout();
std::size_t get_default_retry_timeout(const Context& context);
/*******************
* DownloadTarget *
@ -52,7 +54,12 @@ namespace mamba
{
public:
DownloadTarget(const std::string& name, const std::string& url, const std::string& filename);
DownloadTarget(
Context& context,
const std::string& name,
const std::string& url,
const std::string& filename
);
~DownloadTarget();
DownloadTarget(const DownloadTarget&) = delete;
@ -127,8 +134,14 @@ namespace mamba
const CURLHandle& get_curl_handle() const;
const Context& context() const
{
return m_context;
}
private:
Context& m_context;
std::unique_ptr<ZstdStream> m_zstd_stream;
std::unique_ptr<Bzip2Stream> m_bzip2_stream;
std::unique_ptr<CURLHandle> m_curl_handle;
@ -166,7 +179,7 @@ namespace mamba
{
public:
MultiDownloadTarget();
explicit MultiDownloadTarget(const Context& context);
~MultiDownloadTarget();
void add(DownloadTarget* target);
@ -176,6 +189,7 @@ namespace mamba
bool check_msgs(bool failfast);
const Context& m_context;
std::vector<DownloadTarget*> m_targets;
std::vector<DownloadTarget*> m_retry_targets;
std::unique_ptr<CURLMultiHandle> p_curl_handle;

View File

@ -17,6 +17,8 @@
namespace mamba
{
class Context;
class History
{
public:
@ -32,7 +34,7 @@ namespace mamba
struct UserRequest
{
static UserRequest prefilled();
static UserRequest prefilled(const Context& context);
std::string date;
std::string cmd;

View File

@ -7,6 +7,7 @@
#ifndef MAMBA_CORE_LINK
#define MAMBA_CORE_LINK
#include <regex>
#include <stack>
#include <string>
#include <tuple>
@ -25,7 +26,7 @@ namespace mamba
std::string replace_long_shebang(const std::string& shebang);
std::string python_shebang(const std::string& python_exe);
static const std::regex shebang_regex("^(#!" // pretty much the whole match string
inline const std::regex shebang_regex("^(#!" // pretty much the whole match string
"(?:[ ]*)" // allow spaces between #! and beginning of
// the executable path
"(/(?:\\\\ |[^ \n\r\t])*)" // the executable is the next

View File

@ -3,8 +3,16 @@
namespace mamba
{
void remove_menu_from_json(const fs::u8path& json_file, TransactionContext* context);
void create_menu_from_json(const fs::u8path& json_file, TransactionContext* context);
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
);
#ifdef _WIN32
namespace win
{

View File

@ -21,6 +21,8 @@
namespace mamba
{
class Context;
std::string cut_repo_name(const std::string& reponame);
namespace printers
@ -145,9 +147,9 @@ namespace mamba
void cancel_json_print();
protected:
const Context& context() const;
Console();
Console(const Context& context);
~Console();
private:
@ -158,6 +160,9 @@ namespace mamba
std::unique_ptr<ConsoleData> p_data;
friend class ProgressProxy;
static void set_singleton(Console& console);
static void clear_singleton();
};
class MessageLogger

View File

@ -19,6 +19,8 @@
namespace mamba
{
struct ValidationOptions;
enum class Writable
{
UNKNOWN,
@ -32,7 +34,7 @@ namespace mamba
{
public:
PackageCacheData(const fs::u8path& path);
explicit PackageCacheData(const fs::u8path& path);
bool create_directory();
void set_writable(Writable writable);
@ -40,8 +42,8 @@ namespace mamba
fs::u8path path() const;
void clear_query_cache(const PackageInfo& s);
bool has_valid_tarball(const PackageInfo& s);
bool has_valid_extracted_dir(const PackageInfo& s);
bool has_valid_tarball(const PackageInfo& s, const ValidationOptions& options);
bool has_valid_extracted_dir(const PackageInfo& s, const ValidationOptions& options);
private:
@ -57,7 +59,7 @@ namespace mamba
{
public:
MultiPackageCache(const std::vector<fs::u8path>& pkgs_dirs);
MultiPackageCache(const std::vector<fs::u8path>& pkgs_dirs, const ValidationOptions& options);
std::vector<fs::u8path> paths() const;
@ -75,6 +77,7 @@ namespace mamba
std::vector<PackageCacheData> m_caches;
std::map<std::string, fs::u8path> m_cached_tarballs;
std::map<std::string, fs::u8path> m_cached_extracted_dirs;
const ValidationOptions& m_options;
};
} // namespace mamba

View File

@ -19,6 +19,7 @@
#include "mamba_fs.hpp"
#include "package_cache.hpp"
#include "progress_bar.hpp"
#include "tasksync.hpp"
#include "thread_utils.hpp"
namespace mamba
@ -39,6 +40,8 @@ namespace mamba
EXTRACT_ERROR
};
// TODO: REVIEW: consider caputring a reference to the context from the ChannelContext, if
// that makes sense.
PackageDownloadExtractTarget(const PackageInfo& pkg_info, ChannelContext& channel_context);
void write_repodata_record(const fs::u8path& base_path);
@ -46,15 +49,15 @@ namespace mamba
bool finalize_callback(const DownloadTarget& target);
bool finished();
void validate();
bool extract();
bool extract_from_cache();
bool validate_extract();
bool extract(const Context& context);
bool extract_from_cache(const Context& context);
bool validate_extract(const Context& context);
const std::string& name() const;
std::size_t expected_size() const;
VALIDATION_RESULT validation_result() const;
void clear_cache() const;
DownloadTarget* target(MultiPackageCache& cache);
DownloadTarget* target(Context& context, MultiPackageCache& cache);
std::exception m_decompress_exception;
@ -77,6 +80,8 @@ namespace mamba
VALIDATION_RESULT m_validation_result = VALIDATION_RESULT::UNDEFINED;
TaskSynchronizer m_tasksync;
std::function<void(ProgressBarRepr&)> extract_repr();
std::function<void(ProgressProxy&)> extract_progress_callback();
};

View File

@ -15,6 +15,23 @@
namespace mamba
{
struct ValidationOptions;
class Context;
// Determine the kind of command line to run to extract subprocesses.
enum class extract_subproc_mode
{
mamba_package,
micromamba,
};
struct ExtractOptions
{
bool sparse = false;
extract_subproc_mode subproc_mode;
static ExtractOptions from_context(const Context&);
};
enum compression_algorithm
{
none,
@ -38,22 +55,32 @@ namespace mamba
int compression_level
);
void extract_archive(const fs::u8path& file, const fs::u8path& destination);
void
extract_archive(const fs::u8path& file, const fs::u8path& destination, const ExtractOptions& options);
void extract_conda(
const fs::u8path& file,
const fs::u8path& dest_dir,
const ExtractOptions& options,
const std::vector<std::string>& parts = { "info", "pkg" }
);
void extract(const fs::u8path& file, const fs::u8path& destination);
fs::u8path extract(const fs::u8path& file);
void extract_subproc(const fs::u8path& file, const fs::u8path& dest);
void
extract(const fs::u8path& file, const fs::u8path& destination, const ExtractOptions& options);
fs::u8path extract(const fs::u8path& file, const ExtractOptions& options);
void
extract_subproc(const fs::u8path& file, const fs::u8path& dest, const ExtractOptions& options);
bool transmute(
const fs::u8path& pkg_file,
const fs::u8path& target,
int compression_level,
int compression_threads
int compression_threads,
const ExtractOptions& options
);
bool validate(const fs::u8path& pkg_folder);
bool validate(const fs::u8path& pkg_folder, const ValidationOptions& options);
} // namespace mamba
#endif // MAMBA_PACKAGE_HANDLING_HPP

View File

@ -59,6 +59,7 @@ namespace mamba
void remove_repo(::Id repo_id, bool reuse_ids);
ChannelContext& channel_context() const;
Context& context() const;
private:

View File

@ -15,6 +15,7 @@
namespace mamba
{
class ProgressBar;
struct ProgressBarOptions;
// TODO: find a way to define it here without
// impoorting spdlog and modst of the STL.
class ProgressBarRepr;
@ -86,6 +87,7 @@ namespace mamba
bool started() const;
int width() const;
const ProgressBarOptions& options() const;
private:

View File

@ -20,12 +20,15 @@ extern "C" // Incomplete header
#include <solv/conda.h>
}
#include "mamba/core/context.hpp"
#include "mamba/core/package_info.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/util/graph.hpp"
namespace mamba
{
using GraphicsParams = Context::GraphicsParams;
void print_dep_graph(
std::ostream& out,
Solvable* s,
@ -93,7 +96,7 @@ namespace mamba
std::ostream& table(std::ostream&) const;
std::ostream& table(std::ostream&, const std::vector<std::string_view>& fmt) const;
std::ostream& tree(std::ostream&) const;
std::ostream& tree(std::ostream&, const GraphicsParams& graphics) const;
nlohmann::json json(ChannelContext& channel_context) const;
std::ostream& pretty(std::ostream&) const;

View File

@ -14,6 +14,8 @@
namespace mamba
{
class Context;
bool is_process_name_running(const std::string& name);
std::string generate_unique_process_name(std::string_view program_name);
const fs::u8path& proc_dir();
@ -27,6 +29,7 @@ namespace mamba
public:
ScopedProcFile(
const Context& context,
const std::string& name,
const std::vector<std::string>& command,
LockFile proc_dir_lock = lock_proc_dir()
@ -43,6 +46,7 @@ namespace mamba
};
int run_in_environment(
const Context& context,
const fs::u8path& prefix,
std::vector<std::string> command,
const std::string& cwd,

View File

@ -26,14 +26,20 @@ extern const char data_mamba_completion_posix[];
namespace mamba
{
class Context;
std::string guess_shell();
#ifdef _WIN32
void init_cmd_exe_registry(const std::wstring& reg_path, const fs::u8path& conda_prefix);
void init_cmd_exe_registry(
const Context& context,
const std::wstring& reg_path,
const fs::u8path& conda_prefix
);
#endif
fs::u8path get_self_exe_path();
std::string get_hook_contents(const std::string& shell);
std::string get_hook_contents(const Context& context, const std::string& shell);
// this function calls cygpath to convert win path to unix
std::string native_path_to_unix(const std::string& path, bool is_a_path_env = false);
@ -45,27 +51,38 @@ namespace mamba
xonsh_content(const fs::u8path& env_prefix, const std::string& shell, const fs::u8path& mamba_exe);
void modify_rc_file(
const Context& context,
const fs::u8path& file_path,
const fs::u8path& conda_prefix,
const std::string& shell,
const fs::u8path& mamba_exe
);
void
reset_rc_file(const fs::u8path& file_path, const std::string& shell, const fs::u8path& mamba_exe);
void reset_rc_file(
const Context& context,
const fs::u8path& file_path,
const std::string& shell,
const fs::u8path& mamba_exe
);
// we need this function during linking...
void init_root_prefix_cmdexe(const fs::u8path& root_prefix);
void deinit_root_prefix_cmdexe(const fs::u8path& root_prefix);
void init_root_prefix(const std::string& shell, const fs::u8path& root_prefix);
void deinit_root_prefix(const std::string& shell, const fs::u8path& root_prefix);
void init_root_prefix_cmdexe(const Context& context, const fs::u8path& root_prefix);
void deinit_root_prefix_cmdexe(const Context& context, const fs::u8path& root_prefix);
void init_root_prefix(Context& context, const std::string& shell, const fs::u8path& root_prefix);
void
deinit_root_prefix(Context& context, const std::string& shell, const fs::u8path& root_prefix);
std::string powershell_contents(const fs::u8path& conda_prefix);
void init_powershell(const fs::u8path& profile_path, const fs::u8path& conda_prefix);
void deinit_powershell(const fs::u8path& profile_path, const fs::u8path& conda_prefix);
void
init_powershell(const Context& context, const fs::u8path& profile_path, const fs::u8path& conda_prefix);
void deinit_powershell(
const Context& context,
const fs::u8path& profile_path,
const fs::u8path& conda_prefix
);
void init_shell(const std::string& shell, const fs::u8path& conda_prefix);
void deinit_shell(const std::string& shell, const fs::u8path& conda_prefix);
void init_shell(Context& context, const std::string& shell, const fs::u8path& conda_prefix);
void deinit_shell(Context& context, const std::string& shell, const fs::u8path& conda_prefix);
std::vector<std::string> find_initialized_shells();
}

View File

@ -150,6 +150,7 @@ namespace mamba
subdir_metadata m_metadata;
std::unique_ptr<TemporaryFile> m_temp_file;
const Channel* p_channel = nullptr;
Context* p_context = nullptr;
};
// Contrary to conda original function, this one expects a full url

View File

@ -70,9 +70,11 @@ namespace mamba
const fs::u8path m_cache_path;
Solution m_solution;
History::UserRequest m_history_entry = History::UserRequest::prefilled();
History::UserRequest m_history_entry;
std::vector<MatchSpec> m_requested_specs;
MTransaction(MPool&, MultiPackageCache&);
};
MTransaction create_explicit_transaction_from_urls(

View File

@ -33,14 +33,19 @@ namespace mamba
public:
TransactionContext();
explicit TransactionContext(const Context& context);
TransactionContext& operator=(const TransactionContext&);
TransactionContext(
const Context& context,
const fs::u8path& target_prefix,
const std::pair<std::string, std::string>& py_versions,
const std::vector<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,
@ -50,7 +55,7 @@ namespace mamba
bool try_pyc_compilation(const std::vector<fs::u8path>& py_files);
void wait_for_pyc_compilation();
bool has_python;
bool has_python = false;
fs::u8path target_prefix;
fs::u8path relocate_prefix;
fs::u8path site_packages_path;
@ -66,6 +71,11 @@ namespace mamba
bool relink_noarch = false;
std::vector<MatchSpec> requested_specs;
const Context& context() const
{
return *m_context;
}
private:
bool start_pyc_compilation_process();
@ -73,6 +83,10 @@ namespace mamba
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

@ -33,6 +33,8 @@
namespace mamba
{
class Context;
// Used when we want a callback which does nothing.
struct no_op
{
@ -60,6 +62,55 @@ namespace mamba
);
}
// @return `true` if `TemporaryFile` will not delete files once destroy.
// If `set_persist_temporary_files` was not called, returns `false` by default.
//
// @warning This function must be called in the execution scope `main()`, doing otherwise leads
// to undefined behavior.
//
// @warning This is a thread-safe accessor for a global parameter: the returned value is
// therefore obsolete before being obtained and should be considered as a hint.
bool must_persist_temporary_files();
// Controls if `TemporaryFile` will delete files once destroy or not.
// This is useful for debugging situations where temporary data lead to unexpected behavior.
//
// @warning This function must be called in the execution scope `main()`, doing otherwise leads
// to undefined behavior.
//
// @warning This is a thread-safe function setting a global parameter: if concurrent threads
// are both calling this function with different value there is no guarantee as to which
// value will be retained.
// However if there is exactly one thread executing this function then the following is true:
// const auto result = set_persist_temporary_files(must_persist);
// result == must_persist && must_persist_temporary_files() == must_persist
bool set_persist_temporary_files(bool will_persist);
// @return `true` if `TemporaryDirectory` will not delete files once destroy.
// If `set_persist_temporary_files` was not called, returns `false` by default.
//
// @warning This function must be called in the execution scope `main()`, doing otherwise leads
// to undefined behavior.
//
// @warning This is a thread-safe accessor for a global parameter: the returned value is
// therefore obsolete before being obtained and should be considered as a hint.
bool must_persist_temporary_directories();
// Controls if `TemporaryDirectory` will delete files once destroy or not.
// This is useful for debugging situations where temporary data lead to unexpected behavior.
//
// @warning This function must be called in the execution scope `main()`, doing otherwise leads
// to undefined behavior.
//
// @warning This is a thread-safe function setting a global parameter: if concurrent threads
// are both calling this function with different value there is no guarantee as to which
// value will be retained.
// However if there is exactly one thread executing this function then the following is true:
// const auto result = set_persist_temporary_directories(must_persist);
// result == must_persist && must_persist_temporary_directories() == must_persist
bool set_persist_temporary_directories(bool will_persist);
class TemporaryDirectory
{
public:
@ -131,6 +182,29 @@ namespace mamba
// result == allow && is_file_locking_allowed() == allow
bool allow_file_locking(bool allow);
// @return The file locking timeout used by `LockFile` at construction.
//
// @warning This function must be called in the execution scope `main()`, doing otherwise leads
// to undefined behavior.
//
// @warning This is a thread-safe accessor for a global parameter: the returned value is
// therefore obsolete before being obtained and should be considered as a hint.
std::chrono::seconds default_file_locking_timeout();
// Changes the locking duration when `LockFile` is constructed without a specified locking
// timeout.
//
// @warning This function must be called in the execution scope `main()`, doing otherwise leads
// to undefined behavior.
//
// @warning This is a thread-safe function setting a global parameter: if concurrent threads
// are both calling this function with different value there is no guarantee as to which
// value will be retained.
// However if there is exactly one thread executing this function then the following is true:
// const auto result = set_file_locking_timeout(timeout);
// result == timeout && default_file_locking_timeout() == timeout
std::chrono::seconds set_file_locking_timeout(const std::chrono::seconds& new_timeout);
// This is a non-throwing file-locking mechanism.
// It can be used on a file or directory path. In the case of a directory path a file will be
// created to be locked. The locking will be implemented using the OS's filesystem locking
@ -185,7 +259,7 @@ namespace mamba
// re-assigned:
// - `this->is_locked() == false` and `if(*this) ...` will go in the `false` branch.
// - accessors will throw, except `is_locked()`, `count_lock_owners()`, and `error()`
LockFile(const fs::u8path& path);
explicit LockFile(const fs::u8path& path);
LockFile(const fs::u8path& path, const std::chrono::seconds& timeout);
~LockFile();
@ -282,7 +356,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 fs::u8path& path);
std::size_t remove_or_rename(const Context& context, const fs::u8path& path);
// Unindent a string literal
std::string unindent(const char* p);
@ -308,16 +382,35 @@ namespace mamba
open_ifstream(const fs::u8path& path, std::ios::openmode mode = std::ios::in | std::ios::binary);
bool ensure_comspec_set();
struct WrappedCallOptions
{
bool is_micromamba = false;
bool dev_mode = false;
bool debug_wrapper_scripts = false;
static WrappedCallOptions from_context(const Context&);
};
std::unique_ptr<TemporaryFile> wrap_call(
const Context& context,
const fs::u8path& root_prefix,
const fs::u8path& prefix,
bool dev_mode,
bool debug_wrapper_scripts,
const std::vector<std::string>& arguments
const std::vector<std::string>& arguments, // TODO: c++20 replace by std::span
WrappedCallOptions options = {}
);
std::tuple<std::vector<std::string>, std::unique_ptr<TemporaryFile>>
prepare_wrapped_call(const fs::u8path& prefix, const std::vector<std::string>& cmd);
struct PreparedWrappedCall
{
std::vector<std::string> wrapped_command;
std::unique_ptr<TemporaryFile> temporary_file;
};
PreparedWrappedCall prepare_wrapped_call(
const Context& context,
const fs::u8path& prefix,
const std::vector<std::string>& cmd
);
/// Returns `true` if the filename matches names of files which should be interpreted as YAML.
/// NOTE: this does not check if the file exists.
@ -325,7 +418,6 @@ namespace mamba
std::optional<std::string>
proxy_match(const std::string& url, const std::map<std::string, std::string>& proxy_servers);
std::optional<std::string> proxy_match(const std::string& url);
std::string hide_secrets(std::string_view str);

View File

@ -11,6 +11,7 @@
#include <string>
#include "mamba/core/fsutil.hpp"
#include "mamba/core/palette.hpp"
namespace mamba
{
@ -36,7 +37,7 @@ namespace mamba
#endif
void run_as_admin(const std::string& args);
bool enable_long_paths_support(bool force);
bool enable_long_paths_support(bool force, Palette palette = Palette::no_color());
std::string windows_version();
std::string macos_version();
std::string linux_version();

View File

@ -475,7 +475,7 @@ namespace mamba::validation
std::vector<fs::u8path> possible_update_files();
virtual std::unique_ptr<RepoIndexChecker>
build_index_checker(const TimeRef& time_reference, const std::string& url, const fs::u8path& cache_path) const = 0;
build_index_checker(Context& context, const TimeRef& time_reference, const std::string& url, const fs::u8path& cache_path) const = 0;
protected:
@ -522,6 +522,7 @@ namespace mamba::validation
* @param cache_path Path to the cache directory
*/
RepoChecker(
Context& context,
const std::string& base_url,
const fs::u8path& ref_path,
const fs::u8path& cache_path = ""
@ -544,6 +545,7 @@ namespace mamba::validation
std::size_t m_root_version = 0;
fs::u8path m_ref_path;
fs::u8path m_cache_path;
Context& m_context;
fs::u8path initial_trusted_root();
fs::u8path ref_root();
@ -590,6 +592,7 @@ namespace mamba::validation
RoleFullKeys self_keys() const override;
std::unique_ptr<RepoIndexChecker> build_index_checker(
Context& context,
const TimeRef& time_reference,
const std::string& url,
const fs::u8path& cache_path
@ -672,6 +675,7 @@ namespace mamba::validation
* from repository base URL.
*/
std::unique_ptr<RepoIndexChecker> build_index_checker(
Context& context,
const TimeRef& time_reference,
const std::string& url,
const fs::u8path& cache_path
@ -735,6 +739,7 @@ namespace mamba::validation
* from repository base URL.
*/
std::unique_ptr<RepoIndexChecker> build_index_checker(
Context& context,
const TimeRef& time_reference,
const std::string& url,
const fs::u8path& cache_path

View File

@ -14,7 +14,7 @@
namespace mamba
{
std::vector<PackageInfo> get_virtual_packages();
std::vector<PackageInfo> get_virtual_packages(const Context& context);
namespace detail
{
@ -23,11 +23,12 @@ namespace mamba
PackageInfo make_virtual_package(
const std::string& name,
const std::string& subdir,
const std::string& version = "",
const std::string& build_string = ""
);
std::vector<PackageInfo> dist_packages();
std::vector<PackageInfo> dist_packages(const Context& context);
}
}

View File

@ -8,12 +8,21 @@
#define MAMBA_UTIL_URL_MANIP_HPP
#include <optional>
#include <regex>
#include <string>
#include <string_view>
#include <vector>
namespace mamba::util
{
namespace conda_urls
{
// usernames on anaconda.org can have a underscore, which influences the
// first two characters
inline const std::regex token_regex{ "/t/([a-zA-Z0-9-_]{0,2}[a-zA-Z0-9-]*)" };
inline const std::regex http_basicauth_regex{ "(://|^)([^\\s]+):([^\\s]+)@" };
}
/**
* Escape reserved URL reserved characters with '%' encoding.
*

View File

@ -16,12 +16,45 @@
#include "mamba/api/list.hpp"
#include "mamba/api/remove.hpp"
#include "mamba/api/update.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/execution.hpp"
mamba::MainExecutor*
mamba_new_main_executor()
{
return new mamba::MainExecutor;
}
void
mamba_delete_main_executor(mamba::MainExecutor* main_executor)
{
delete main_executor;
}
mamba::Context*
mamba_new_context(mamba::ContextOptions* options)
{
if (options)
{
return new mamba::Context{ *options };
}
else
{
return new mamba::Context;
}
}
void
mamba_delete_context(mamba::Context* context)
{
delete context;
}
mamba::Configuration*
mamba_new_configuration()
mamba_new_configuration(mamba::Context* context)
{
return new mamba::Configuration;
assert(context != nullptr);
return new mamba::Configuration(*context);
}
void

View File

@ -48,12 +48,12 @@ namespace mamba
{
int RETRY_SUBDIR_FETCH = 1 << 0;
auto& ctx = Context::instance();
auto& ctx = pool.context();
std::vector<std::string> channel_urls = ctx.channels;
std::vector<MSubdirData> subdirs;
MultiDownloadTarget multi_dl;
MultiDownloadTarget multi_dl{ ctx };
std::vector<std::pair<int, int>> priorities;
int max_prio = static_cast<int>(channel_urls.size());

View File

@ -20,7 +20,7 @@ namespace mamba
{
void clean(Configuration& config, int options)
{
auto& ctx = Context::instance();
auto& ctx = config.context();
config.at("use_target_prefix_fallback").set_value(true);
config.load();
@ -44,7 +44,7 @@ namespace mamba
std::vector<fs::u8path> envs;
MultiPackageCache caches(ctx.pkgs_dirs);
MultiPackageCache caches(ctx.pkgs_dirs, ctx.validation_params);
if (!ctx.dry_run && (clean_index || clean_all))
{
Console::stream() << "Cleaning index cache..";

View File

@ -32,7 +32,12 @@ namespace mamba
{
bool ConfigurableImplBase::env_var_configured() const
{
if (Context::instance().src_params.no_env)
if (m_config == nullptr)
{
return false;
}
if (m_config->context().src_params.no_env)
{
return false;
}
@ -49,12 +54,22 @@ namespace mamba
bool ConfigurableImplBase::env_var_active() const
{
return !Context::instance().src_params.no_env || (m_name == "no_env");
if (m_config == nullptr)
{
return false;
}
return !m_config->context().src_params.no_env || (m_name == "no_env");
}
bool ConfigurableImplBase::rc_configured() const
{
return m_rc_configured && !Context::instance().src_params.no_rc;
if (m_config == nullptr)
{
return false;
}
return m_rc_configured && !m_config->context().src_params.no_rc;
}
@ -656,7 +671,7 @@ namespace mamba
void post_root_prefix_rc_loading(Configuration& config)
{
if (!Context::instance().src_params.no_rc)
if (!config.context().src_params.no_rc)
{
rc_loading_hook(config, RCConfigLevel::kHomeDir);
config.at("no_env").compute(MAMBA_CONF_FORCE_COMPUTE);
@ -665,7 +680,7 @@ namespace mamba
void post_target_prefix_rc_loading(Configuration& config)
{
if (!Context::instance().src_params.no_rc)
if (!config.context().src_params.no_rc)
{
rc_loading_hook(config, RCConfigLevel::kTargetPrefix);
config.at("no_env").compute(MAMBA_CONF_FORCE_COMPUTE);
@ -674,7 +689,7 @@ namespace mamba
mamba::log_level log_level_fallback_hook(Configuration& config)
{
auto& ctx = Context::instance();
const auto& ctx = config.context();
if (ctx.output_params.json)
{
@ -700,16 +715,14 @@ namespace mamba
}
}
void verbose_hook(int& lvl)
void verbose_hook(Context& ctx, int& lvl)
{
auto& ctx = Context::instance();
ctx.output_params.verbosity = lvl;
}
void target_prefix_checks_hook(int& options)
void target_prefix_checks_hook(const Context& ctx, int& options)
{
auto& ctx = Context::instance();
auto& prefix = ctx.prefix_params.target_prefix;
const auto& prefix = ctx.prefix_params.target_prefix;
bool no_checks = options & MAMBA_NO_PREFIX_CHECK;
bool allow_missing = options & MAMBA_ALLOW_MISSING_PREFIX;
@ -757,10 +770,8 @@ namespace mamba
}
}
void rc_files_hook(std::vector<fs::u8path>& files)
void rc_files_hook(const Context& ctx, std::vector<fs::u8path>& files)
{
auto& ctx = Context::instance();
if (!files.empty())
{
if (ctx.src_params.no_rc)
@ -825,9 +836,9 @@ namespace mamba
}
}
std::vector<fs::u8path> fallback_envs_dirs_hook()
std::vector<fs::u8path> fallback_envs_dirs_hook(const Context& context)
{
return { Context::instance().prefix_params.root_prefix / "envs" };
return { context.prefix_params.root_prefix / "envs" };
}
void envs_dirs_hook(std::vector<fs::u8path>& dirs)
@ -843,9 +854,9 @@ namespace mamba
}
}
std::vector<fs::u8path> fallback_pkgs_dirs_hook()
std::vector<fs::u8path> fallback_pkgs_dirs_hook(const Context& context)
{
std::vector<fs::u8path> paths = { Context::instance().prefix_params.root_prefix / "pkgs",
std::vector<fs::u8path> paths = { context.prefix_params.root_prefix / "pkgs",
env::home_directory() / ".mamba" / "pkgs" };
#ifdef _WIN32
auto appdata = env::get("APPDATA");
@ -881,9 +892,9 @@ namespace mamba
}
}
void extract_threads_hook()
void extract_threads_hook(const Context& context)
{
DownloadExtractSemaphore::set_max(Context::instance().threads_params.extract_threads);
DownloadExtractSemaphore::set_max(context.threads_params.extract_threads);
}
}
@ -1059,18 +1070,17 @@ namespace mamba
* Configuration implementation *
********************************/
Configuration::Configuration()
Configuration::Configuration(Context& ctx)
: m_context(ctx)
{
set_configurables();
}
void Configuration::set_configurables()
{
auto& ctx = Context::instance();
// Basic
insert(
Configurable("root_prefix", &ctx.prefix_params.root_prefix)
Configurable("root_prefix", &m_context.prefix_params.root_prefix)
.group("Basic")
.set_env_var_names()
.needs({ "create_base", "rc_files" })
@ -1085,7 +1095,7 @@ namespace mamba
.set_single_op_lifetime()
.description("Define if base environment will be initialized empty"));
insert(Configurable("target_prefix", &ctx.prefix_params.target_prefix)
insert(Configurable("target_prefix", &m_context.prefix_params.target_prefix)
.group("Basic")
.set_env_var_names()
.needs({ "root_prefix",
@ -1101,7 +1111,7 @@ namespace mamba
.set_post_context_hook([this]
{ return detail::post_target_prefix_rc_loading(*this); }));
insert(Configurable("relocate_prefix", &ctx.prefix_params.relocate_prefix)
insert(Configurable("relocate_prefix", &m_context.prefix_params.relocate_prefix)
.group("Basic")
.set_env_var_names()
.needs({ "target_prefix" })
@ -1118,35 +1128,41 @@ namespace mamba
.needs({ "target_prefix", "rc_files" })
.description("The type of checks performed on the target prefix")
.set_single_op_lifetime()
.set_post_merge_hook(detail::target_prefix_checks_hook));
.set_post_merge_hook<int>([this](int& value)
{ detail::target_prefix_checks_hook(m_context, value); }
));
insert(Configurable("env_name", std::string(""))
.group("Basic")
.needs({ "root_prefix", "spec_file_env_name", "envs_dirs" })
.set_single_op_lifetime()
.set_post_merge_hook<std::string>([&](std::string& value)
.set_post_merge_hook<std::string>([this](std::string& value)
{ return detail::env_name_hook(*this, value); })
.description("Name of the target prefix"));
insert(Configurable("envs_dirs", &ctx.envs_dirs)
insert(Configurable("envs_dirs", &m_context.envs_dirs)
.group("Basic")
.set_rc_configurable(RCConfigLevel::kHomeDir)
.set_env_var_names({ "CONDA_ENVS_DIRS" })
.needs({ "root_prefix" })
.set_fallback_value_hook(detail::fallback_envs_dirs_hook)
.set_fallback_value_hook<decltype(m_context.envs_dirs)>(
[this] { return detail::fallback_envs_dirs_hook(m_context); }
)
.set_post_merge_hook(detail::envs_dirs_hook)
.description("Possible locations of named environments"));
insert(Configurable("pkgs_dirs", &ctx.pkgs_dirs)
insert(Configurable("pkgs_dirs", &m_context.pkgs_dirs)
.group("Basic")
.set_rc_configurable()
.set_env_var_names({ "CONDA_PKGS_DIRS" })
.needs({ "root_prefix" })
.set_fallback_value_hook(detail::fallback_pkgs_dirs_hook)
.set_fallback_value_hook<decltype(m_context.pkgs_dirs)>(
[this] { return detail::fallback_pkgs_dirs_hook(m_context); }
)
.set_post_merge_hook(detail::pkgs_dirs_hook)
.description("Possible locations of packages caches"));
insert(Configurable("platform", &ctx.platform)
insert(Configurable("platform", &m_context.platform)
.group("Basic")
.set_rc_configurable()
.set_env_var_names({ "CONDA_SUBDIR", "MAMBA_PLATFORM" })
@ -1174,7 +1190,7 @@ namespace mamba
.set_single_op_lifetime()
.description("Others package managers specifications"));
insert(Configurable("experimental", &ctx.experimental)
insert(Configurable("experimental", &m_context.experimental)
.group("Basic")
.description("Enable experimental features")
.set_rc_configurable()
@ -1184,7 +1200,7 @@ namespace mamba
under active development and not stable yet.)"))
.set_post_merge_hook(detail::experimental_hook));
insert(Configurable("debug", &ctx.debug)
insert(Configurable("debug", &m_context.debug)
.group("Basic")
.set_env_var_names()
.description("Turn on the debug mode")
@ -1196,7 +1212,7 @@ namespace mamba
.set_post_merge_hook(detail::debug_hook));
// Channels
insert(Configurable("channels", &ctx.channels)
insert(Configurable("channels", &m_context.channels)
.group("Channels")
.set_rc_configurable()
.set_env_var_names({ "CONDA_CHANNELS" })
@ -1205,18 +1221,18 @@ namespace mamba
.long_description(unindent(R"(
The list of channels where the packages will be searched for.
See also 'channel_priority'.)"))
.set_post_merge_hook<decltype(ctx.channels)>(
[&](decltype(ctx.channels)& value)
.set_post_merge_hook<decltype(m_context.channels)>(
[&](decltype(m_context.channels)& value)
{ return detail::channels_hook(*this, value); }
));
insert(Configurable("channel_alias", &ctx.channel_alias)
insert(Configurable("channel_alias", &m_context.channel_alias)
.group("Channels")
.set_rc_configurable()
.set_env_var_names()
.description("The prepended url location to associate with channel names"));
insert(Configurable("default_channels", &ctx.default_channels)
insert(Configurable("default_channels", &m_context.default_channels)
.group("Channels")
.set_rc_configurable()
.set_env_var_names()
@ -1225,14 +1241,14 @@ namespace mamba
The list of channel names and/or urls used for the 'defaults'
multichannel.)")));
insert(Configurable("custom_channels", &ctx.custom_channels)
insert(Configurable("custom_channels", &m_context.custom_channels)
.group("Channels")
.set_rc_configurable()
.set_env_var_names()
.description("Custom channels")
.long_description("A dictionary with name: url to use for custom channels."));
insert(Configurable("custom_multichannels", &ctx.custom_multichannels)
insert(Configurable("custom_multichannels", &m_context.custom_multichannels)
.group("Channels")
.set_rc_configurable()
.description("Custom multichannels")
@ -1240,18 +1256,19 @@ namespace mamba
"A dictionary with name: list of names/urls to use for custom multichannels."
));
insert(Configurable("override_channels_enabled", &ctx.override_channels_enabled)
insert(Configurable("override_channels_enabled", &m_context.override_channels_enabled)
.group("Channels")
.set_rc_configurable()
.set_env_var_names()
.description("Permit use of the --override-channels command-line flag"));
insert(Configurable("repodata_use_zst", &ctx.repodata_use_zst)
insert(Configurable("repodata_use_zst", &m_context.repodata_use_zst)
.group("Repodata")
.set_rc_configurable()
.description("Use zstd encoded repodata when fetching"));
insert(Configurable("repodata_has_zst", &ctx.repodata_has_zst)
insert(Configurable("repodata_has_zst", &m_context.repodata_has_zst)
.group("Repodata")
.set_rc_configurable()
.description("Channels that have zstd encoded repodata (saves a HEAD request)"));
@ -1268,7 +1285,7 @@ namespace mamba
WARNING: overrides 'ssl_verify' if provided and 'ssl_verify'
also contains a path to SSL certificates.)")));
insert(Configurable("local_repodata_ttl", &ctx.local_repodata_ttl)
insert(Configurable("local_repodata_ttl", &m_context.local_repodata_ttl)
.group("Network")
.set_rc_configurable()
.description("Repodata time-to-live")
@ -1280,13 +1297,13 @@ namespace mamba
locally cache repodata before checking the remote server for
an update.)")));
insert(Configurable("offline", &ctx.offline)
insert(Configurable("offline", &m_context.offline)
.group("Network")
.set_rc_configurable()
.set_env_var_names()
.description("Force use cached repodata"));
insert(Configurable("ssl_no_revoke", &ctx.remote_fetch_params.ssl_no_revoke)
insert(Configurable("ssl_no_revoke", &m_context.remote_fetch_params.ssl_no_revoke)
.group("Network")
.set_rc_configurable()
.set_env_var_names()
@ -1296,7 +1313,7 @@ namespace mamba
It's only working for Windows back-end.
WARNING: this option loosens the SSL security.)")));
insert(Configurable("ssl_verify", &ctx.remote_fetch_params.ssl_verify)
insert(Configurable("ssl_verify", &m_context.remote_fetch_params.ssl_verify)
.group("Network")
.set_rc_configurable()
.set_env_var_names()
@ -1306,11 +1323,11 @@ namespace mamba
the string "<false>" to indicate no SSL verification, or a path to
a directory with cert files, or a cert file..)"))
.needs({ "cacert_path", "offline" })
.set_post_merge_hook<decltype(ctx.remote_fetch_params.ssl_verify)>(
.set_post_merge_hook<decltype(m_context.remote_fetch_params.ssl_verify)>(
[this](auto&... args) { return detail::ssl_verify_hook(*this, args...); }
));
insert(Configurable("proxy_servers", &ctx.remote_fetch_params.proxy_servers)
insert(Configurable("proxy_servers", &m_context.remote_fetch_params.proxy_servers)
.group("Network")
.set_rc_configurable()
.description("Use a proxy server for network connections")
@ -1320,7 +1337,7 @@ namespace mamba
the value is the url of the proxy server, optionally with username and password
in the form of scheme://username:password@hostname.)")));
insert(Configurable("remote_connect_timeout_secs", &ctx.remote_fetch_params.connect_timeout_secs)
insert(Configurable("remote_connect_timeout_secs", &m_context.remote_fetch_params.connect_timeout_secs)
.group("Network")
.set_rc_configurable()
.set_env_var_names()
@ -1328,14 +1345,14 @@ namespace mamba
"The number seconds conda will wait for your client to establish a connection to a remote url resource."
));
insert(Configurable("remote_backoff_factor", &ctx.remote_fetch_params.retry_backoff)
insert(Configurable("remote_backoff_factor", &m_context.remote_fetch_params.retry_backoff)
.group("Network")
.set_rc_configurable()
.set_env_var_names()
.description("The factor determines the time HTTP connection should wait for attempt."
));
insert(Configurable("remote_max_retries", &ctx.remote_fetch_params.max_retries)
insert(Configurable("remote_max_retries", &m_context.remote_fetch_params.max_retries)
.group("Network")
.set_rc_configurable()
.set_env_var_names()
@ -1343,7 +1360,7 @@ namespace mamba
// Solver
insert(Configurable("channel_priority", &ctx.channel_priority)
insert(Configurable("channel_priority", &m_context.channel_priority)
.group("Solver")
.set_rc_configurable()
.set_env_var_names()
@ -1385,14 +1402,14 @@ namespace mamba
the packages specifications, which is the default
behavior.)")));
insert(Configurable("add_pip_as_python_dependency", &ctx.add_pip_as_python_dependency)
insert(Configurable("add_pip_as_python_dependency", &m_context.add_pip_as_python_dependency)
.group("Solver")
.set_rc_configurable()
.set_env_var_names()
.description("Add pip as a Python dependency")
.long_description("Automatically add pip as a Python dependency"));
insert(Configurable("pinned_packages", &ctx.pinned_packages)
insert(Configurable("pinned_packages", &m_context.pinned_packages)
.group("Solver")
.set_rc_configurable()
.set_env_var_names()
@ -1424,21 +1441,21 @@ namespace mamba
.set_env_var_names()
.description("If solve fails, try to fetch updated repodata"));
insert(Configurable("allow_uninstall", &ctx.allow_uninstall)
insert(Configurable("allow_uninstall", &m_context.allow_uninstall)
.group("Solver")
.set_rc_configurable()
.set_env_var_names()
.description("Allow uninstall when installing or updating packages. Default is true."
));
insert(Configurable("allow_downgrade", &ctx.allow_downgrade)
insert(Configurable("allow_downgrade", &m_context.allow_downgrade)
.group("Solver")
.set_rc_configurable()
.set_env_var_names()
.description("Allow downgrade when installing packages. Default is false."));
// Extract, Link & Install
insert(Configurable("download_threads", &ctx.threads_params.download_threads)
insert(Configurable("download_threads", &m_context.threads_params.download_threads)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
@ -1448,11 +1465,11 @@ namespace mamba
Defines the number of threads for package download.
It has to be strictly positive.)")));
insert(Configurable("extract_threads", &ctx.threads_params.extract_threads)
insert(Configurable("extract_threads", &m_context.threads_params.extract_threads)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
.set_post_context_hook(detail::extract_threads_hook)
.set_post_context_hook([this] { return detail::extract_threads_hook(m_context); })
.description("Defines the number of threads for package extraction")
.long_description(unindent(R"(
Defines the number of threads for package extraction.
@ -1460,7 +1477,7 @@ namespace mamba
host max concurrency minus the value, zero (default) is the host max
concurrency value.)")));
insert(Configurable("allow_softlinks", &ctx.allow_softlinks)
insert(Configurable("allow_softlinks", &m_context.allow_softlinks)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
@ -1470,7 +1487,7 @@ namespace mamba
such as when installing on a different filesystem than the one that
the package cache is on.)")));
insert(Configurable("always_copy", &ctx.always_copy)
insert(Configurable("always_copy", &m_context.always_copy)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
@ -1479,13 +1496,13 @@ namespace mamba
Register a preference that files be copied into a prefix during
install rather than hard-linked.)")));
insert(Configurable("always_softlink", &ctx.always_softlink)
insert(Configurable("always_softlink", &m_context.always_softlink)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
.needs({ "always_copy" })
.set_post_merge_hook<decltype(ctx.always_softlink)>(
[&](decltype(ctx.always_softlink)& value)
.set_post_merge_hook<decltype(m_context.always_softlink)>(
[&](decltype(m_context.always_softlink)& value)
{ return detail::always_softlink_hook(*this, value); }
)
.description("Use soft-link instead of hard-link")
@ -1496,7 +1513,7 @@ namespace mamba
!WARNING: Using this option can result in corruption of long-lived
environments due to broken links (deleted cache).)")));
insert(Configurable("shortcuts", &ctx.shortcuts)
insert(Configurable("shortcuts", &m_context.shortcuts)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
@ -1504,7 +1521,7 @@ namespace mamba
"Install start-menu shortcuts on Windows (not implemented on Linux / macOS)"
));
insert(Configurable("safety_checks", &ctx.safety_checks)
insert(Configurable("safety_checks", &m_context.validation_params.safety_checks)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names({ "CONDA_SAFETY_CHECKS", "MAMBA_SAFETY_CHECKS" })
@ -1513,7 +1530,7 @@ namespace mamba
Enforce available safety guarantees during package installation. The
value must be one of 'enabled', 'warn', or 'disabled'.)")));
insert(Configurable("extra_safety_checks", &ctx.extra_safety_checks)
insert(Configurable("extra_safety_checks", &m_context.validation_params.extra_safety_checks)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names({ "CONDA_EXTRA_SAFETY_CHECKS", "MAMBA_EXTRA_SAFETY_CHECKS" })
@ -1522,7 +1539,7 @@ namespace mamba
Spend extra time validating package contents. Currently, runs sha256
verification on every file within each package during installation.)")));
insert(Configurable("verify_artifacts", &ctx.verify_artifacts)
insert(Configurable("verify_artifacts", &m_context.validation_params.verify_artifacts)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
@ -1531,7 +1548,7 @@ namespace mamba
Spend extra time validating package contents. It consists of running
cryptographic verifications on channels and packages metadata.)")));
insert(Configurable("lock_timeout", &ctx.lock_timeout)
insert(Configurable("lock_timeout", &m_context.lock_timeout)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
@ -1540,7 +1557,7 @@ namespace mamba
Lockfile timeout for blocking mode when waiting for another process
to release the path. Default is 0 (no timeout))")));
insert(Configurable("use_lockfiles", &ctx.use_lockfiles)
insert(Configurable("use_lockfiles", &m_context.use_lockfiles)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
@ -1551,20 +1568,20 @@ 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", &ctx.compile_pyc)
insert(Configurable("compile_pyc", &m_context.compile_pyc)
.group("Extract, Link & Install")
.set_rc_configurable()
.set_env_var_names()
.description("Defines if PYC files will be compiled or not"));
// Output, Prompt and Flow
insert(Configurable("always_yes", &ctx.always_yes)
insert(Configurable("always_yes", &m_context.always_yes)
.group("Output, Prompt and Flow Control")
.set_rc_configurable()
.set_env_var_names()
.description("Automatically answer yes on prompted questions"));
insert(Configurable("auto_activate_base", &ctx.auto_activate_base)
insert(Configurable("auto_activate_base", &m_context.auto_activate_base)
.group("Output, Prompt and Flow Control")
.set_rc_configurable()
.set_env_var_names()
@ -1573,18 +1590,18 @@ namespace mamba
Automatically activate the base environment during shell
initialization.)")));
insert(Configurable("dry_run", &ctx.dry_run)
insert(Configurable("dry_run", &m_context.dry_run)
.group("Output, Prompt and Flow Control")
.set_env_var_names()
.description("Only display what would have been done"));
insert(Configurable("download_only", &ctx.download_only)
insert(Configurable("download_only", &m_context.download_only)
.group("Output, Prompt and Flow Control")
.set_env_var_names()
.description("Only download and extract packages, do not link them into environment."
));
insert(Configurable("log_level", &ctx.output_params.logging_level)
insert(Configurable("log_level", &m_context.output_params.logging_level)
.group("Output, Prompt and Flow Control")
.set_rc_configurable()
.set_env_var_names()
@ -1598,7 +1615,7 @@ namespace mamba
be one of {'off', 'fatal', 'error', 'warning', 'info',
'debug', 'trace'}.)")));
insert(Configurable("log_backtrace", &ctx.output_params.log_backtrace)
insert(Configurable("log_backtrace", &m_context.output_params.log_backtrace)
.group("Output, Prompt and Flow Control")
.set_rc_configurable()
.set_env_var_names()
@ -1607,7 +1624,7 @@ namespace mamba
Set the log backtrace size. It will replay the n last
logs if an error is thrown during the execution.)")));
insert(Configurable("log_pattern", &ctx.output_params.log_pattern)
insert(Configurable("log_pattern", &m_context.output_params.log_pattern)
.group("Output, Prompt and Flow Control")
.set_rc_configurable()
.set_env_var_names()
@ -1615,14 +1632,14 @@ namespace mamba
.long_description(unindent(R"(
Set the log pattern.)")));
insert(Configurable("json", &ctx.output_params.json)
insert(Configurable("json", &m_context.output_params.json)
.group("Output, Prompt and Flow Control")
.set_rc_configurable()
.needs({ "print_config_only", "print_context_only" })
.set_env_var_names()
.description("Report all output as json"));
insert(Configurable("changeps1", &ctx.change_ps1)
insert(Configurable("changeps1", &m_context.change_ps1)
.group("Output, Prompt and Flow Control")
.set_rc_configurable()
.set_env_var_names()
@ -1630,7 +1647,7 @@ namespace mamba
"When using activate, change the command prompt ($PS1) to include the activated environment."
));
insert(Configurable("shell_completion", &ctx.shell_completion)
insert(Configurable("shell_completion", &m_context.shell_completion)
.group("Output, Prompt and Flow Control")
.set_rc_configurable()
.set_env_var_names()
@ -1638,7 +1655,7 @@ namespace mamba
"Enable or disable shell autocompletion (currently works for bash and zsh)."
));
insert(Configurable("env_prompt", &ctx.env_prompt)
insert(Configurable("env_prompt", &m_context.env_prompt)
.group("Output, Prompt and Flow Control")
.set_rc_configurable()
.set_env_var_names()
@ -1694,7 +1711,7 @@ namespace mamba
.group("Output, Prompt and Flow Control")
.description("Display configs values"));
insert(Configurable("quiet", &ctx.output_params.quiet)
insert(Configurable("quiet", &m_context.output_params.quiet)
.group("Output, Prompt and Flow Control")
.set_rc_configurable()
.set_env_var_names()
@ -1703,7 +1720,8 @@ namespace mamba
insert(Configurable("verbose", 0)
.group("Output, Prompt and Flow Control")
.set_post_merge_hook(detail::verbose_hook)
.set_post_merge_hook<int>([this](int& value)
{ return detail::verbose_hook(m_context, value); })
.description("Set the verbosity")
.long_description(unindent(R"(
Set the verbosity of .
@ -1717,7 +1735,10 @@ namespace mamba
.group("Config sources")
.set_env_var_names({ "MAMBARC", "CONDARC" })
.needs({ "no_rc" })
.set_post_merge_hook(detail::rc_files_hook)
.set_post_merge_hook<std::vector<fs::u8path>>(
[this](std::vector<fs::u8path>& value)
{ return detail::rc_files_hook(m_context, value); }
)
.description("Paths to the configuration files to use"));
insert(Configurable("override_rc_files", true)
@ -1725,12 +1746,12 @@ namespace mamba
.set_env_var_names()
.description("Whether to override rc files by highest precedence"));
insert(Configurable("no_rc", &ctx.src_params.no_rc)
insert(Configurable("no_rc", &m_context.src_params.no_rc)
.group("Config sources")
.set_env_var_names()
.description("Disable the use of configuration files"));
insert(Configurable("no_env", &ctx.src_params.no_env)
insert(Configurable("no_env", &m_context.src_params.no_env)
.group("Config sources")
.set_env_var_names()
.description("Disable the use of environment variables"));
@ -1780,10 +1801,9 @@ namespace mamba
// give env::user_config_dir a mamba argument, all so I can supply conda in a few default
// cases. It seems like ../conda is an easier solution
//
std::vector<fs::u8path> Configuration::compute_default_rc_sources(const RCConfigLevel& level)
std::vector<fs::u8path>
Configuration::compute_default_rc_sources(const Context& context, const RCConfigLevel& level)
{
auto& ctx = Context::instance();
std::vector<fs::u8path> system;
if constexpr (util::on_mac || util::on_linux)
{
@ -1800,10 +1820,10 @@ namespace mamba
"C:\\ProgramData\\conda\\.mambarc" };
}
std::vector<fs::u8path> root = { ctx.prefix_params.root_prefix / ".condarc",
ctx.prefix_params.root_prefix / "condarc",
ctx.prefix_params.root_prefix / "condarc.d",
ctx.prefix_params.root_prefix / ".mambarc" };
std::vector<fs::u8path> root = { context.prefix_params.root_prefix / ".condarc",
context.prefix_params.root_prefix / "condarc",
context.prefix_params.root_prefix / "condarc.d",
context.prefix_params.root_prefix / ".mambarc" };
std::vector<fs::u8path> conda_user = {
env::user_config_dir() / "../conda/.condarc",
@ -1830,10 +1850,10 @@ namespace mamba
mamba_user.push_back(fs::u8path(env::get("MAMBARC").value()));
}
std::vector<fs::u8path> prefix = { ctx.prefix_params.target_prefix / ".condarc",
ctx.prefix_params.target_prefix / "condarc",
ctx.prefix_params.target_prefix / "condarc.d",
ctx.prefix_params.target_prefix / ".mambarc" };
std::vector<fs::u8path> prefix = { context.prefix_params.target_prefix / ".condarc",
context.prefix_params.target_prefix / "condarc",
context.prefix_params.target_prefix / "condarc.d",
context.prefix_params.target_prefix / ".mambarc" };
std::vector<fs::u8path> sources;
@ -1841,7 +1861,7 @@ namespace mamba
{
sources.insert(sources.end(), system.begin(), system.end());
}
if ((level >= RCConfigLevel::kRootPrefix) && !ctx.prefix_params.root_prefix.empty())
if ((level >= RCConfigLevel::kRootPrefix) && !context.prefix_params.root_prefix.empty())
{
sources.insert(sources.end(), root.begin(), root.end());
}
@ -1850,7 +1870,7 @@ namespace mamba
sources.insert(sources.end(), conda_user.begin(), conda_user.end());
sources.insert(sources.end(), mamba_user.begin(), mamba_user.end());
}
if ((level >= RCConfigLevel::kTargetPrefix) && !ctx.prefix_params.target_prefix.empty())
if ((level >= RCConfigLevel::kTargetPrefix) && !context.prefix_params.target_prefix.empty())
{
sources.insert(sources.end(), prefix.begin(), prefix.end());
}
@ -1885,7 +1905,8 @@ namespace mamba
}
m_load_lock = false;
allow_file_locking(Context::instance().use_lockfiles);
allow_file_locking(m_context.use_lockfiles);
set_file_locking_timeout(std::chrono::seconds{ m_context.lock_timeout });
LOG_DEBUG << m_config.size() << " configurables computed";
@ -1897,16 +1918,15 @@ namespace mamba
exit(0);
}
auto& ctx = Context::instance();
ctx.set_log_level(ctx.output_params.logging_level);
m_context.set_log_level(m_context.output_params.logging_level);
spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->flush(); });
spdlog::flush_on(spdlog::level::off);
Context::instance().dump_backtrace_no_guards();
if (ctx.output_params.log_backtrace > 0)
m_context.dump_backtrace_no_guards();
if (m_context.output_params.log_backtrace > 0)
{
spdlog::enable_backtrace(ctx.output_params.log_backtrace);
spdlog::enable_backtrace(m_context.output_params.log_backtrace);
}
else
{
@ -2097,7 +2117,7 @@ namespace mamba
<< YAML::Node(level).as<std::string>();
if (possible_rc_paths.empty())
{
possible_rc_paths = compute_default_rc_sources(level);
possible_rc_paths = compute_default_rc_sources(m_context, level);
}
m_sources = get_existing_rc_sources(possible_rc_paths);

View File

@ -16,7 +16,7 @@ namespace mamba
{
void create(Configuration& config)
{
auto& ctx = Context::instance();
auto& ctx = config.context();
config.at("use_target_prefix_fallback").set_value(false);
config.at("target_prefix_checks")
@ -29,7 +29,7 @@ namespace mamba
auto& create_specs = config.at("specs").value<std::vector<std::string>>();
auto& use_explicit = config.at("explicit_install").value<bool>();
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
bool remove_prefix_on_failure = false;
@ -65,7 +65,7 @@ namespace mamba
}
if (create_specs.empty())
{
detail::create_empty_target(ctx.prefix_params.target_prefix);
detail::create_empty_target(ctx, ctx.prefix_params.target_prefix);
}
if (config.at("platform").configured() && !config.at("platform").rc_configured())
@ -78,9 +78,9 @@ namespace mamba
}
}
if (Context::instance().env_lockfile)
if (ctx.env_lockfile)
{
const auto lockfile_path = Context::instance().env_lockfile.value();
const auto lockfile_path = ctx.env_lockfile.value();
install_lockfile_specs(
channel_context,
lockfile_path,

View File

@ -30,7 +30,7 @@ namespace mamba
);
config.load();
ChannelContext channel_context;
ChannelContext channel_context{ config.context() };
detail::print_info(channel_context, config);
config.operation_teardown();
@ -38,9 +38,12 @@ namespace mamba
namespace detail
{
void info_pretty_print(std::vector<std::tuple<std::string, nlohmann::json>> items)
void info_pretty_print(
std::vector<std::tuple<std::string, nlohmann::json>> items,
const Context::OutputParams& params
)
{
if (Context::instance().output_params.json)
if (params.json)
{
return;
}
@ -86,7 +89,8 @@ namespace mamba
void print_info(ChannelContext& channel_context, const Configuration& config)
{
auto& ctx = Context::instance();
assert(&channel_context.context() == &config.context());
const auto& ctx = config.context();
std::vector<std::tuple<std::string, nlohmann::json>> items;
items.push_back({ "libmamba version", version() });
@ -105,7 +109,7 @@ namespace mamba
std::string name, location;
if (!ctx.prefix_params.target_prefix.empty())
{
name = env_name(ctx.prefix_params.target_prefix);
name = env_name(ctx);
location = ctx.prefix_params.target_prefix.string();
}
else
@ -147,7 +151,7 @@ namespace mamba
items.push_back({ "populated config files", sources });
std::vector<std::string> virtual_pkgs;
for (auto pkg : get_virtual_packages())
for (auto pkg : get_virtual_packages(ctx))
{
virtual_pkgs.push_back(util::concat(pkg.name, "=", pkg.version, "=", pkg.build_string)
);
@ -156,7 +160,7 @@ namespace mamba
std::vector<std::string> channels = ctx.channels;
// Always append context channels
auto& ctx_channels = Context::instance().channels;
auto& ctx_channels = ctx.channels;
std::copy(ctx_channels.begin(), ctx_channels.end(), std::back_inserter(channels));
std::vector<std::string> channel_urls;
for (auto channel : channel_context.get_channels(channels))
@ -173,7 +177,7 @@ namespace mamba
items.push_back({ "platform", ctx.platform });
info_json_print(items);
info_pretty_print(items);
info_pretty_print(items, ctx.output_params);
}
} // detail
} // mamba

View File

@ -104,14 +104,12 @@ namespace mamba
}
}
auto install_for_other_pkgmgr(const detail::other_pkg_mgr_spec& other_spec)
auto install_for_other_pkgmgr(const Context& ctx, const detail::other_pkg_mgr_spec& other_spec)
{
const auto& pkg_mgr = other_spec.pkg_mgr;
const auto& deps = other_spec.deps;
const auto& cwd = other_spec.cwd;
const auto& ctx = Context::instance();
TemporaryFile specs("mambaf", "", cwd);
{
std::ofstream specs_f = open_ofstream(specs.path());
@ -139,6 +137,7 @@ namespace mamba
}();
auto [wrapped_command, tmpfile] = prepare_wrapped_call(
ctx,
ctx.prefix_params.target_prefix,
install_instructions
);
@ -148,7 +147,7 @@ namespace mamba
options.working_directory = cwd.c_str();
Console::stream() << fmt::format(
Context::instance().graphics_params.palette.external,
ctx.graphics_params.palette.external,
"\nInstalling {} packages: {}",
pkg_mgr,
fmt::join(deps, ", ")
@ -163,28 +162,27 @@ namespace mamba
}
}
auto& truthy_values()
const auto& truthy_values(const std::string platform)
{
static std::map<std::string, int> vals{
{ "win", 0 },
{ "unix", 0 },
{ "osx", 0 },
{ "linux", 0 },
static std::unordered_map<std::string, bool> vals{
{ "win", false },
{ "unix", false },
{ "osx", false },
{ "linux", false },
};
const auto& ctx = Context::instance();
if (util::starts_with(ctx.platform, "win"))
if (util::starts_with(platform, "win"))
{
vals["win"] = true;
}
else
{
vals["unix"] = true;
if (util::starts_with(ctx.platform, "linux"))
if (util::starts_with(platform, "linux"))
{
vals["linux"] = true;
}
else if (util::starts_with(ctx.platform, "osx"))
else if (util::starts_with(platform, "osx"))
{
vals["osx"] = true;
}
@ -194,7 +192,7 @@ namespace mamba
namespace detail
{
bool eval_selector(const std::string& selector)
bool eval_selector(const std::string& selector, const std::string& platform)
{
if (!(util::starts_with(selector, "sel(") && selector[selector.size() - 1] == ')'))
{
@ -204,16 +202,18 @@ namespace mamba
}
std::string expr = selector.substr(4, selector.size() - 5);
if (truthy_values().find(expr) == truthy_values().end())
const auto& values = truthy_values(platform);
const auto found_it = values.find(expr);
if (found_it == values.end())
{
throw std::runtime_error("Couldn't parse selector. Value not in [unix, linux, "
"osx, win] or additional whitespaces found.");
}
return truthy_values()[expr];
return found_it->second;
}
yaml_file_contents read_yaml_file(fs::u8path yaml_file)
yaml_file_contents read_yaml_file(fs::u8path yaml_file, const std::string platform)
{
auto file = fs::weakly_canonical(env::expand_user(yaml_file));
if (!fs::exists(file))
@ -262,7 +262,7 @@ namespace mamba
std::string key = map_el.first.as<std::string>();
if (util::starts_with(key, "sel("))
{
bool selected = detail::eval_selector(key);
bool selected = detail::eval_selector(key, platform);
if (selected)
{
const YAML::Node& rest = map_el.second;
@ -390,11 +390,12 @@ namespace mamba
auto& install_specs = config.at("specs").value<std::vector<std::string>>();
auto& use_explicit = config.at("explicit_install").value<bool>();
ChannelContext channel_context;
auto& context = config.context();
ChannelContext channel_context{ context };
if (Context::instance().env_lockfile)
if (context.env_lockfile)
{
const auto lockfile_path = Context::instance().env_lockfile.value();
const auto lockfile_path = context.env_lockfile.value();
LOG_DEBUG << "Lockfile: " << lockfile_path;
install_lockfile_specs(
channel_context,
@ -433,7 +434,8 @@ namespace mamba
int is_retry
)
{
auto& ctx = Context::instance();
assert(&config.context() == &channel_context.context());
Context& ctx = channel_context.context();
auto& no_pin = config.at("no_pin").value<bool>();
auto& no_py_pin = config.at("no_py_pin").value<bool>();
@ -454,7 +456,7 @@ namespace mamba
);
}
MultiPackageCache package_caches(ctx.pkgs_dirs);
MultiPackageCache package_caches{ ctx.pkgs_dirs, ctx.validation_params };
// add channels from specs
for (const auto& s : specs)
@ -500,7 +502,7 @@ namespace mamba
prefix_pkgs.push_back(it.first);
}
prefix_data.add_packages(get_virtual_packages());
prefix_data.add_packages(get_virtual_packages(ctx));
MRepo(pool, prefix_data);
@ -598,9 +600,9 @@ namespace mamba
if (trans.prompt())
{
if (create_env && !Context::instance().dry_run)
if (create_env && !ctx.dry_run)
{
detail::create_target_directory(ctx.prefix_params.target_prefix);
detail::create_target_directory(ctx, ctx.prefix_params.target_prefix);
}
trans.execute(prefix_data);
@ -608,7 +610,7 @@ namespace mamba
for (auto other_spec :
config.at("others_pkg_mgrs_specs").value<std::vector<detail::other_pkg_mgr_spec>>())
{
install_for_other_pkgmgr(other_spec);
install_for_other_pkgmgr(ctx, other_spec);
}
}
else
@ -635,7 +637,7 @@ namespace mamba
)
{
MPool pool{ channel_context };
auto& ctx = Context::instance();
auto& ctx = channel_context.context();
auto exp_prefix_data = PrefixData::create(ctx.prefix_params.target_prefix, channel_context);
if (!exp_prefix_data)
{
@ -644,8 +646,8 @@ namespace mamba
}
PrefixData& prefix_data = exp_prefix_data.value();
MultiPackageCache pkg_caches(ctx.pkgs_dirs);
prefix_data.add_packages(get_virtual_packages());
MultiPackageCache pkg_caches(ctx.pkgs_dirs, ctx.validation_params);
prefix_data.add_packages(get_virtual_packages(ctx));
MRepo(pool, prefix_data); // Potentially re-alloc (moves in memory) Solvables
// in the pool
@ -661,16 +663,16 @@ namespace mamba
if (transaction.prompt())
{
if (create_env && !Context::instance().dry_run)
if (create_env && !ctx.dry_run)
{
detail::create_target_directory(ctx.prefix_params.target_prefix);
detail::create_target_directory(ctx, ctx.prefix_params.target_prefix);
}
transaction.execute(prefix_data);
for (auto other_spec : others)
{
install_for_other_pkgmgr(other_spec);
install_for_other_pkgmgr(ctx, other_spec);
}
}
else
@ -718,7 +720,12 @@ namespace mamba
{
LOG_INFO << "Downloading lockfile";
tmp_lock_file = std::make_unique<TemporaryFile>();
DownloadTarget dt("Environment Lockfile", lockfile, tmp_lock_file->path());
DownloadTarget dt(
channel_context.context(),
"Environment Lockfile",
lockfile,
tmp_lock_file->path()
);
bool success = dt.perform();
if (!success || dt.get_http_status() != 200)
{
@ -746,9 +753,9 @@ namespace mamba
namespace detail
{
void create_empty_target(const fs::u8path& prefix)
void create_empty_target(const Context& context, const fs::u8path& prefix)
{
detail::create_target_directory(prefix);
detail::create_target_directory(context, prefix);
Console::instance().print(util::join(
"",
@ -757,12 +764,12 @@ namespace mamba
Console::instance().json_write({ { "success", true } });
}
void create_target_directory(const fs::u8path prefix)
void create_target_directory(const Context& context, const fs::u8path prefix)
{
path::touch(prefix / "conda-meta" / "history", true);
// Register the environment
EnvironmentsManager env_manager;
EnvironmentsManager env_manager{ context };
env_manager.register_env(prefix);
}
@ -773,6 +780,8 @@ namespace mamba
auto& others_pkg_mgrs_specs = config.at("others_pkg_mgrs_specs");
auto& channels = config.at("channels");
auto& context = config.context();
if (file_specs.size() == 0)
{
return;
@ -793,18 +802,18 @@ namespace mamba
{
if (util::starts_with(file, "http"))
{
Context::instance().env_lockfile = file;
context.env_lockfile = file;
}
else
{
Context::instance().env_lockfile = fs::absolute(file).string();
context.env_lockfile = fs::absolute(file).string();
}
LOG_DEBUG << "File spec Lockfile: " << Context::instance().env_lockfile.value();
LOG_DEBUG << "File spec Lockfile: " << context.env_lockfile.value();
}
else if (is_yaml_file_name(file))
{
const auto parse_result = read_yaml_file(file);
const auto parse_result = read_yaml_file(file, context.platform);
if (parse_result.channels.size() != 0)
{

View File

@ -25,7 +25,7 @@ namespace mamba
);
config.load();
ChannelContext channel_context;
ChannelContext channel_context{ config.context() };
detail::list_packages(regex, channel_context);
}
@ -43,7 +43,7 @@ namespace mamba
void list_packages(std::string regex, ChannelContext& channel_context)
{
auto& ctx = Context::instance();
auto& ctx = channel_context.context();
auto sprefix_data = PrefixData::create(ctx.prefix_params.target_prefix, channel_context);
if (!sprefix_data)

View File

@ -23,7 +23,7 @@ namespace mamba
bool force = flags & MAMBA_REMOVE_FORCE;
bool remove_all = flags & MAMBA_REMOVE_ALL;
auto& ctx = Context::instance();
auto& ctx = config.context();
config.at("use_target_prefix_fallback").set_value(true);
config.at("target_prefix_checks")
@ -35,7 +35,7 @@ namespace mamba
auto remove_specs = config.at("specs").value<std::vector<std::string>>();
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
if (remove_all)
{
@ -71,7 +71,7 @@ namespace mamba
bool force
)
{
auto& ctx = Context::instance();
auto& ctx = channel_context.context();
if (ctx.prefix_params.target_prefix.empty())
{
@ -91,7 +91,7 @@ namespace mamba
MRepo(pool, prefix_data);
const fs::u8path pkgs_dirs(ctx.prefix_params.root_prefix / "pkgs");
MultiPackageCache package_caches({ pkgs_dirs });
MultiPackageCache package_caches({ pkgs_dirs }, ctx.validation_params);
auto execute_transaction = [&](MTransaction& transaction)
{

View File

@ -25,18 +25,18 @@ namespace mamba
const std::string& query
)
{
auto& ctx = Context::instance();
auto& ctx = config.context();
config.at("use_target_prefix_fallback").set_value(true);
config.at("target_prefix_checks")
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX);
config.load();
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
MPool pool{ channel_context };
// bool installed = (type == QueryType::kDepends) || (type == QueryType::kWhoneeds);
MultiPackageCache package_caches(ctx.pkgs_dirs);
MultiPackageCache package_caches(ctx.pkgs_dirs, ctx.validation_params);
if (use_local)
{
if (format != QueryResultFormat::kJSON)
@ -109,7 +109,7 @@ namespace mamba
{
case QueryResultFormat::kTREE:
case QueryResultFormat::kPRETTY:
res.tree(std::cout);
res.tree(std::cout, config.context().graphics_params);
break;
case QueryResultFormat::kJSON:
std::cout << res.json(pool.channel_context()).dump(4);
@ -135,7 +135,7 @@ namespace mamba
{
case QueryResultFormat::kTREE:
case QueryResultFormat::kPRETTY:
res.tree(std::cout);
res.tree(std::cout, config.context().graphics_params);
break;
case QueryResultFormat::kJSON:
std::cout << res.json(pool.channel_context()).dump(4);

View File

@ -23,75 +23,73 @@ namespace mamba
{
namespace
{
auto make_activator(std::string_view name) -> std::unique_ptr<Activator>
auto make_activator(const Context& context, std::string_view name)
-> std::unique_ptr<Activator>
{
if (name == "bash" || name == "zsh" || name == "dash" || name == "posix")
{
return std::make_unique<mamba::PosixActivator>();
return std::make_unique<mamba::PosixActivator>(context);
}
if (name == "csh" || name == "tcsh")
{
return std::make_unique<mamba::CshActivator>();
return std::make_unique<mamba::CshActivator>(context);
}
if (name == "cmd.exe")
{
return std::make_unique<mamba::CmdExeActivator>();
return std::make_unique<mamba::CmdExeActivator>(context);
}
if (name == "powershell")
{
return std::make_unique<mamba::PowerShellActivator>();
return std::make_unique<mamba::PowerShellActivator>(context);
}
if (name == "xonsh")
{
return std::make_unique<mamba::XonshActivator>();
return std::make_unique<mamba::XonshActivator>(context);
}
if (name == "fish")
{
return std::make_unique<mamba::FishActivator>();
return std::make_unique<mamba::FishActivator>(context);
}
throw std::invalid_argument(fmt::format("Shell type not handled: {}", name));
}
}
void shell_init(const std::string& shell_type, const fs::u8path& prefix)
void shell_init(Context& ctx, const std::string& shell_type, const fs::u8path& prefix)
{
auto& ctx = Context::instance();
if (prefix.empty() || prefix == "base")
{
init_shell(shell_type, ctx.prefix_params.root_prefix);
init_shell(ctx, shell_type, ctx.prefix_params.root_prefix);
}
else
{
init_shell(shell_type, fs::weakly_canonical(env::expand_user(prefix)));
init_shell(ctx, shell_type, fs::weakly_canonical(env::expand_user(prefix)));
}
}
void shell_deinit(const std::string& shell_type, const fs::u8path& prefix)
void shell_deinit(Context& ctx, const std::string& shell_type, const fs::u8path& prefix)
{
auto& ctx = Context::instance();
if (prefix.empty() || prefix == "base")
{
deinit_shell(shell_type, ctx.prefix_params.root_prefix);
deinit_shell(ctx, shell_type, ctx.prefix_params.root_prefix);
}
else
{
deinit_shell(shell_type, fs::weakly_canonical(env::expand_user(prefix)));
deinit_shell(ctx, shell_type, fs::weakly_canonical(env::expand_user(prefix)));
}
}
void shell_reinit(const fs::u8path& prefix)
void shell_reinit(Context& ctx, const fs::u8path& prefix)
{
// re-initialize all the shell scripts after update
for (const auto& shell_type : find_initialized_shells())
{
shell_init(shell_type, prefix);
shell_init(ctx, shell_type, prefix);
}
}
void shell_hook(const std::string& shell_type)
void shell_hook(Context& ctx, const std::string& shell_type)
{
auto activator = make_activator(shell_type);
auto& ctx = Context::instance();
auto activator = make_activator(ctx, shell_type);
// TODO do we need to do something wtih `shell_prefix -> root_prefix?`?
if (ctx.output_params.json)
{
@ -107,7 +105,8 @@ namespace mamba
}
}
void shell_activate(const fs::u8path& prefix, const std::string& shell_type, bool stack)
void
shell_activate(Context& ctx, const fs::u8path& prefix, const std::string& shell_type, bool stack)
{
if (!fs::exists(prefix))
{
@ -116,26 +115,26 @@ namespace mamba
);
}
auto activator = make_activator(shell_type);
auto activator = make_activator(ctx, shell_type);
std::cout << activator->activate(prefix, stack);
}
void shell_reactivate(const std::string& shell_type)
void shell_reactivate(Context& ctx, const std::string& shell_type)
{
auto activator = make_activator(shell_type);
auto activator = make_activator(ctx, shell_type);
std::cout << activator->reactivate();
}
void shell_deactivate(const std::string& shell_type)
void shell_deactivate(Context& ctx, const std::string& shell_type)
{
auto activator = make_activator(shell_type);
auto activator = make_activator(ctx, shell_type);
std::cout << activator->deactivate();
}
void shell_enable_long_path_support()
void shell_enable_long_path_support(Palette palette)
{
#ifdef _WIN32
if (const bool success = enable_long_paths_support(/* force= */ true); !success)
if (const bool success = enable_long_paths_support(/* force= */ true, palette); !success)
{
throw std::runtime_error("Error enabling Windows long-path support");
}

View File

@ -18,7 +18,7 @@ namespace mamba
{
void update(Configuration& config, bool update_all, bool prune)
{
auto& ctx = Context::instance();
auto& ctx = config.context();
config.at("use_target_prefix_fallback").set_value(true);
config.at("target_prefix_checks")
@ -30,7 +30,7 @@ namespace mamba
auto update_specs = config.at("specs").value<std::vector<std::string>>();
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
// add channels from specs
for (const auto& s : update_specs)
@ -44,7 +44,7 @@ namespace mamba
int solver_flag = SOLVER_UPDATE;
MPool pool{ channel_context };
MultiPackageCache package_caches(ctx.pkgs_dirs);
MultiPackageCache package_caches(ctx.pkgs_dirs, ctx.validation_params);
auto exp_loaded = load_channels(pool, package_caches, 0);
if (!exp_loaded)
@ -66,7 +66,7 @@ namespace mamba
prefix_pkgs.push_back(it.first);
}
prefix_data.add_packages(get_virtual_packages());
prefix_data.add_packages(get_virtual_packages(ctx));
MRepo(pool, prefix_data);

View File

@ -26,8 +26,9 @@ namespace mamba
* Activator implementation *
****************************/
Activator::Activator()
: m_env(env::copy())
Activator::Activator(const Context& context)
: m_context(context)
, m_env(env::copy())
{
}
@ -50,7 +51,7 @@ namespace mamba
std::string Activator::get_default_env(const fs::u8path& prefix)
{
if (paths_equal(prefix, Context::instance().prefix_params.root_prefix))
if (paths_equal(prefix, m_context.prefix_params.root_prefix))
{
return "base";
}
@ -133,7 +134,7 @@ namespace mamba
int old_conda_shlvl
)
{
if (Context::instance().change_ps1)
if (m_context.change_ps1)
{
std::vector<std::string> env_stack;
std::vector<std::string> prompt_stack;
@ -193,7 +194,7 @@ namespace mamba
auto conda_stacked_env = util::join(";", prompt_stack);
std::string prompt = Context::instance().env_prompt;
std::string prompt = m_context.env_prompt;
util::replace_all(prompt, "{default_env}", conda_default_env);
util::replace_all(prompt, "{stacked_env}", conda_stacked_env);
util::replace_all(prompt, "{prefix}", prefix.string());
@ -255,7 +256,7 @@ namespace mamba
);
if (no_condabin)
{
auto condabin_dir = Context::instance().prefix_params.root_prefix / "condabin";
auto condabin_dir = m_context.prefix_params.root_prefix / "condabin";
path_list.insert(path_list.begin(), condabin_dir);
}
}
@ -384,7 +385,7 @@ namespace mamba
conda_default_env,
conda_shlvl
);
if (Context::instance().change_ps1)
if (m_context.change_ps1)
{
auto res = update_prompt(conda_prompt_modifier);
if (!res.first.empty())
@ -493,7 +494,7 @@ namespace mamba
envt.activate_scripts = get_activate_scripts(new_prefix);
}
if (Context::instance().change_ps1)
if (m_context.change_ps1)
{
auto res = update_prompt(conda_prompt_modifier);
if (!res.first.empty())
@ -644,7 +645,7 @@ namespace mamba
old_conda_prefix });
}
if (Context::instance().change_ps1)
if (m_context.change_ps1)
{
auto res = update_prompt(conda_prompt_modifier);
if (!res.first.empty())
@ -685,7 +686,7 @@ namespace mamba
// special handling for cmd.exe
if (is_cmd(this))
{
get_hook_contents(shell());
get_hook_contents(m_context, shell());
return "";
}
@ -696,10 +697,10 @@ namespace mamba
}
else
{
builder << hook_preamble() << "\n" << get_hook_contents(shell()) << "\n";
builder << hook_preamble() << "\n" << get_hook_contents(m_context, shell()) << "\n";
}
if (Context::instance().shell_completion)
if (m_context.shell_completion)
{
if (shell() == "posix" && (shell_type == "zsh" || shell_type == "bash"))
{
@ -709,7 +710,7 @@ namespace mamba
// if we are in a `mamba shell -n <env>` we don't want to activate base
auto has_prefix = env::get("CONDA_PREFIX");
if (Context::instance().auto_activate_base && !has_prefix.has_value())
if (m_context.auto_activate_base && !has_prefix.has_value())
{
builder << "micromamba activate base\n";
}
@ -833,7 +834,7 @@ namespace mamba
fs::u8path PosixActivator::hook_source_path()
{
return Context::instance().prefix_params.root_prefix / "etc" / "profile.d" / "micromamba.sh";
return m_context.prefix_params.root_prefix / "etc" / "profile.d" / "micromamba.sh";
}
/*********************************
@ -932,7 +933,7 @@ namespace mamba
fs::u8path CshActivator::hook_source_path()
{
return Context::instance().prefix_params.root_prefix / "etc" / "profile.d" / "micromamba.csh";
return m_context.prefix_params.root_prefix / "etc" / "profile.d" / "micromamba.csh";
}
@ -1023,7 +1024,7 @@ namespace mamba
{
return fmt::format(
"$MambaModuleArgs = @{{ChangePs1 = ${}}}",
Context::instance().change_ps1 ? "True" : "False"
m_context.change_ps1 ? "True" : "False"
);
}
@ -1034,7 +1035,7 @@ namespace mamba
fs::u8path PowerShellActivator::hook_source_path()
{
return Context::instance().prefix_params.root_prefix / "condabin" / "mamba_hook.ps1";
return m_context.prefix_params.root_prefix / "condabin" / "mamba_hook.ps1";
}
std::pair<std::string, std::string>
@ -1102,7 +1103,7 @@ namespace mamba
fs::u8path XonshActivator::hook_source_path()
{
return Context::instance().prefix_params.root_prefix / "etc" / "profile.d" / "mamba.xsh";
return m_context.prefix_params.root_prefix / "etc" / "profile.d" / "mamba.xsh";
}
std::pair<std::string, std::string>
@ -1170,8 +1171,7 @@ namespace mamba
fs::u8path FishActivator::hook_source_path()
{
return Context::instance().prefix_params.root_prefix / "etc" / "fish" / "conf.d"
/ "mamba.fish";
return m_context.prefix_params.root_prefix / "etc" / "fish" / "conf.d" / "mamba.fish";
}
std::pair<std::string, std::string>

View File

@ -202,7 +202,7 @@ namespace mamba
};
}
std::vector<std::string> take_platforms(std::string& value)
std::vector<std::string> take_platforms(const Context& context, std::string& value)
{
std::vector<std::string> platforms;
if (!value.empty())
@ -233,13 +233,7 @@ namespace mamba
else
{
std::string platform = "";
util::split_platform(
get_known_platforms(),
value,
Context::instance().platform,
value,
platform
);
util::split_platform(get_known_platforms(), value, context.platform, value, platform);
if (!platform.empty())
{
platforms.push_back(std::move(platform));
@ -249,7 +243,7 @@ namespace mamba
if (platforms.empty())
{
platforms = Context::instance().platforms();
platforms = context.platforms();
}
return platforms;
}
@ -319,13 +313,15 @@ namespace mamba
return m_package_filename;
}
const validation::RepoChecker& Channel::repo_checker(MultiPackageCache& caches) const
const validation::RepoChecker&
Channel::repo_checker(Context& context, MultiPackageCache& caches) const
{
if (p_repo_checker == nullptr)
{
p_repo_checker = std::make_unique<validation::RepoChecker>(
context,
util::rsplit(base_url(), "/", 1).front(),
Context::instance().prefix_params.root_prefix / "etc" / "trusted-repos"
context.prefix_params.root_prefix / "etc" / "trusted-repos"
/ util::cache_name_from_url(base_url()),
caches.first_writable_path() / "cache" / util::cache_name_from_url(base_url())
);
@ -581,7 +577,7 @@ namespace mamba
}
std::string value = in_value;
auto platforms = take_platforms(value);
auto platforms = take_platforms(m_context, value);
auto chan = util::url_has_scheme(value) ? from_url(fix_win_path(value))
: util::is_explicit_path(value) ? from_url(util::path_to_url(value))
@ -609,8 +605,6 @@ namespace mamba
auto res = m_channel_cache.find(value);
if (res == m_channel_cache.end())
{
auto& ctx = Context::instance();
auto chan = from_value(value);
if (!chan.token())
{
@ -621,14 +615,15 @@ namespace mamba
const auto& without_channel = chan.location();
for (const auto& auth : { with_channel, without_channel })
{
auto it = ctx.authentication_info().find(auth);
if (it != ctx.authentication_info().end()
const auto& authentication_info = m_context.authentication_info();
auto it = authentication_info.find(auth);
if (it != authentication_info.end()
&& it->second.type == AuthenticationType::kCondaToken)
{
chan.m_token = it->second.value;
break;
}
else if (it != ctx.authentication_info().end() && it->second.type == AuthenticationType::kBasicHTTPAuthentication)
else if (it != authentication_info.end() && it->second.type == AuthenticationType::kBasicHTTPAuthentication)
{
chan.m_auth = it->second.value;
break;
@ -694,8 +689,9 @@ namespace mamba
return m_custom_multichannels;
}
ChannelContext::ChannelContext()
: m_channel_alias(build_channel_alias())
ChannelContext::ChannelContext(Context& context)
: m_context(context)
, m_channel_alias(build_channel_alias())
{
init_custom_channels();
}
@ -704,8 +700,7 @@ namespace mamba
Channel ChannelContext::build_channel_alias()
{
auto& ctx = Context::instance();
std::string alias = ctx.channel_alias;
const std::string alias = m_context.channel_alias;
std::string location, scheme, auth, token;
util::split_scheme_auth_token(alias, location, scheme, auth, token);
return from_alias(
@ -723,7 +718,7 @@ namespace mamba
******************/
// Default channels
auto& default_channels = Context::instance().default_channels;
auto& default_channels = m_context.default_channels;
std::vector<std::string> default_names(default_channels.size());
auto default_name_iter = default_names.begin();
for (auto& url : default_channels)
@ -737,8 +732,8 @@ namespace mamba
// Local channels
std::vector<std::string> local_channels = {
Context::instance().prefix_params.target_prefix.string() + "/conda-bld",
Context::instance().prefix_params.root_prefix.string() + "/conda-bld",
m_context.prefix_params.target_prefix.string() + "/conda-bld",
m_context.prefix_params.root_prefix.string() + "/conda-bld",
"~/conda-bld"
};
@ -757,7 +752,7 @@ namespace mamba
}
m_custom_multichannels.emplace(LOCAL_CHANNELS_NAME, std::move(local_names));
const auto& context_custom_channels = Context::instance().custom_channels;
const auto& context_custom_channels = m_context.custom_channels;
for (const auto& [n, p] : context_custom_channels)
{
std::string url = p;
@ -770,7 +765,7 @@ namespace mamba
m_custom_channels.emplace(n, std::move(channel));
}
auto& multichannels = Context::instance().custom_multichannels;
auto& multichannels = m_context.custom_multichannels;
for (auto& [multichannelname, urllist] : multichannels)
{
std::vector<std::string> names(urllist.size());

View File

@ -66,11 +66,36 @@ namespace mamba
return static_cast<spdlog::level::level_enum>(l);
}
Context::Context()
void Context::enable_logging_and_signal_handling(Context& context)
{
MainExecutor::instance().on_close(tasksync.synchronized([this] { logger->flush(); }));
set_default_signal_handler();
on_ci = bool(env::get("CI"));
context.logger = std::make_shared<Logger>("libmamba", context.output_params.log_pattern, "\n");
MainExecutor::instance().on_close(
context.tasksync.synchronized([&context] { context.logger->flush(); })
);
std::shared_ptr<spdlog::logger> libcurl_logger = std::make_shared<Logger>(
"libcurl",
context.output_params.log_pattern,
""
);
std::shared_ptr<spdlog::logger> libsolv_logger = std::make_shared<Logger>(
"libsolv",
context.output_params.log_pattern,
""
);
spdlog::register_logger(libcurl_logger);
spdlog::register_logger(libsolv_logger);
spdlog::set_default_logger(context.logger);
spdlog::set_level(convert_log_level(context.output_params.logging_level));
}
Context::Context(const ContextOptions& options)
{
on_ci = static_cast<bool>(env::get("CI"));
prefix_params.root_prefix = env::get("MAMBA_ROOT_PREFIX").value_or("");
prefix_params.conda_prefix = prefix_params.root_prefix;
@ -86,6 +111,9 @@ namespace mamba
keep_temp_files = env::get("MAMBA_KEEP_TEMP") ? true : false;
keep_temp_directories = env::get("MAMBA_KEEP_TEMP_DIRS") ? true : false;
set_persist_temporary_files(keep_temp_files);
set_persist_temporary_directories(keep_temp_directories);
{
const bool cout_is_atty = is_atty(std::cout);
graphics_params.no_progress_bars = (on_ci || !cout_is_atty);
@ -98,29 +126,10 @@ namespace mamba
ascii_only = false;
#endif
set_default_signal_handler();
std::shared_ptr<spdlog::logger> l = std::make_shared<Logger>(
"libmamba",
output_params.log_pattern,
"\n"
);
std::shared_ptr<spdlog::logger> libcurl_logger = std::make_shared<Logger>(
"libcurl",
output_params.log_pattern,
""
);
std::shared_ptr<spdlog::logger> libsolv_logger = std::make_shared<Logger>(
"libsolv",
output_params.log_pattern,
""
);
spdlog::register_logger(libcurl_logger);
spdlog::register_logger(libsolv_logger);
spdlog::set_default_logger(l);
logger = std::dynamic_pointer_cast<Logger>(l);
spdlog::set_level(convert_log_level(output_params.logging_level));
if (options.enable_logging_and_signal_handling)
{
enable_logging_and_signal_handling(*this);
}
}
Context::~Context() = default;
@ -165,12 +174,12 @@ namespace mamba
spdlog::set_level(convert_log_level(level));
}
std::vector<std::string> Context::platforms()
std::vector<std::string> Context::platforms() const
{
return { platform, "noarch" };
}
std::map<std::string, AuthenticationInfo>& Context::authentication_info()
Context::authentication_info_map_t& Context::authentication_info()
{
if (!m_authentication_infos_loaded)
{
@ -179,17 +188,16 @@ namespace mamba
return m_authentication_info;
}
const std::map<std::string, AuthenticationInfo>& Context::authentication_info() const
const Context::authentication_info_map_t& Context::authentication_info() const
{
return const_cast<Context*>(this)->authentication_info();
}
void Context::load_authentication_info()
{
auto& ctx = Context::instance();
std::vector<fs::u8path> found_tokens;
for (const auto& loc : ctx.token_locations)
for (const auto& loc : token_locations)
{
auto px = env::expand_user(loc);
if (!fs::exists(px) || !fs::is_directory(px))
@ -284,18 +292,18 @@ namespace mamba
}
std::string env_name(const fs::u8path& prefix)
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::instance().prefix_params.root_prefix))
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::instance().envs_dirs)
for (const auto& d : context.envs_dirs)
{
if (paths_equal(d, maybe_env_dir))
{
@ -305,6 +313,12 @@ namespace mamba
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)
@ -332,7 +346,7 @@ namespace mamba
PRINT_CTX(out, override_channels_enabled);
PRINT_CTX(out, use_only_tar_bz2);
PRINT_CTX(out, auto_activate_base);
PRINT_CTX(out, extra_safety_checks);
PRINT_CTX(out, validation_params.extra_safety_checks);
PRINT_CTX(out, threads_params.download_threads);
PRINT_CTX(out, output_params.verbosity);
PRINT_CTX(out, channel_alias);
@ -348,7 +362,10 @@ namespace mamba
void Context::dump_backtrace_no_guards()
{
logger->dump_backtrace_no_guards();
if (logger) // REVIEW: is this correct?
{
logger->dump_backtrace_no_guards();
}
}
} // namespace mamba

View File

@ -8,6 +8,7 @@
#include <spdlog/spdlog.h>
#include "mamba/core/context.hpp"
#include "mamba/core/environment.hpp" // for NETRC env var
#include "mamba/core/mamba_fs.hpp" // for fs::exists
#include "mamba/core/util.hpp" // for hide_secrets
@ -45,7 +46,7 @@ namespace mamba
// DO NOT SET TIMEOUT as it will also take into account multi-start time and
// it's just wrong curl_easy_setopt(m_handle, CURLOPT_TIMEOUT,
// Context::instance().remote_fetch_params.read_timeout_secs);
// Context::remote_fetch_params.read_timeout_secs);
// TODO while libcurl in conda now _has_ http2 support we need to fix mamba to
// work properly with it this includes:

View File

@ -165,7 +165,7 @@ namespace mamba
set_low_speed_opt,
context.remote_fetch_params.connect_timeout_secs,
set_ssl_no_revoke,
proxy_match(p_request->url),
proxy_match(p_request->url, context.remote_fetch_params.proxy_servers),
context.remote_fetch_params.ssl_verify
);

View File

@ -21,9 +21,14 @@ namespace mamba
return fs::exists(prefix / PREFIX_MAGIC_FILE);
}
EnvironmentsManager::EnvironmentsManager(const Context& context)
: m_context(context)
{
}
void EnvironmentsManager::register_env(const fs::u8path& location)
{
if (!Context::instance().register_envs)
if (!m_context.register_envs)
{
return;
}
@ -142,7 +147,7 @@ namespace mamba
}
}
}
for (auto& d : Context::instance().envs_dirs)
for (auto& d : m_context.envs_dirs)
{
if (fs::exists(d) && fs::is_directory(d))
{
@ -155,7 +160,7 @@ namespace mamba
}
}
}
all_env_paths.insert(Context::instance().prefix_params.root_prefix);
all_env_paths.insert(m_context.prefix_params.root_prefix);
return all_env_paths;
}

View File

@ -28,6 +28,7 @@ namespace mamba
*****************************/
void get_config(
const Context& context,
bool& set_low_speed_opt,
bool& set_ssl_no_revoke,
long& connect_timeout_secs,
@ -46,29 +47,35 @@ namespace mamba
std::string ssl_no_revoke_env = std::getenv("MAMBA_SSL_NO_REVOKE")
? std::getenv("MAMBA_SSL_NO_REVOKE")
: "0";
set_ssl_no_revoke = (Context::instance().remote_fetch_params.ssl_no_revoke || (ssl_no_revoke_env != "0"));
connect_timeout_secs = Context::instance().remote_fetch_params.connect_timeout_secs;
ssl_verify = Context::instance().remote_fetch_params.ssl_verify;
set_ssl_no_revoke = (context.remote_fetch_params.ssl_no_revoke || (ssl_no_revoke_env != "0"));
connect_timeout_secs = context.remote_fetch_params.connect_timeout_secs;
ssl_verify = context.remote_fetch_params.ssl_verify;
}
std::size_t get_default_retry_timeout()
std::size_t get_default_retry_timeout(const Context& context)
{
return static_cast<std::size_t>(Context::instance().remote_fetch_params.retry_timeout);
return static_cast<std::size_t>(context.remote_fetch_params.retry_timeout);
}
/*********************************
* DownloadTarget implementation *
*********************************/
DownloadTarget::DownloadTarget(const std::string& name, const std::string& url, const std::string& filename)
: m_name(name)
DownloadTarget::DownloadTarget(
Context& context,
const std::string& name,
const std::string& url,
const std::string& filename
)
: m_context(context)
, m_name(name)
, m_filename(filename)
, m_url(util::file_uri_unc2_to_unc4(url))
, m_http_status(10000)
, m_downloaded_size(0)
, m_effective_url(nullptr)
, m_expected_size(0)
, m_retry_wait_seconds(get_default_retry_timeout())
, m_retry_wait_seconds(get_default_retry_timeout(context))
, m_retries(0)
, m_has_progress_bar(false)
, m_ignore_failure(false)
@ -106,7 +113,7 @@ namespace mamba
void DownloadTarget::init_curl_ssl()
{
auto& ctx = Context::instance();
auto& ctx = m_context;
if (!ctx.remote_fetch_params.curl_initialized)
{
@ -183,7 +190,7 @@ namespace mamba
bool set_low_speed_opt, set_ssl_no_revoke;
long connect_timeout_secs;
std::string ssl_verify;
get_config(set_low_speed_opt, set_ssl_no_revoke, connect_timeout_secs, ssl_verify);
get_config(m_context, set_low_speed_opt, set_ssl_no_revoke, connect_timeout_secs, ssl_verify);
// Configure curl handle
m_curl_handle->configure_handle(
@ -191,7 +198,7 @@ namespace mamba
set_low_speed_opt,
connect_timeout_secs,
set_ssl_no_revoke,
proxy_match(url),
proxy_match(url, context().remote_fetch_params.proxy_servers),
ssl_verify
);
@ -233,13 +240,13 @@ namespace mamba
std::string user_agent = fmt::format(
"User-Agent: {} {}",
Context::instance().remote_fetch_params.user_agent,
m_context.remote_fetch_params.user_agent,
curl_version()
);
m_curl_handle->add_header(user_agent);
m_curl_handle->set_opt_header();
m_curl_handle->set_opt(CURLOPT_VERBOSE, Context::instance().output_params.verbosity >= 2);
m_curl_handle->set_opt(CURLOPT_VERBOSE, m_context.output_params.verbosity >= 2);
// get url host
const auto url_parsed = util::URL::parse(url);
@ -250,9 +257,9 @@ namespace mamba
host += ":" + port;
}
if (Context::instance().authentication_info().count(host))
if (m_context.authentication_info().count(host))
{
const auto& auth = Context::instance().authentication_info().at(host);
const auto& auth = m_context.authentication_info().at(host);
if (auth.type == AuthenticationType::kBearerToken)
{
m_curl_handle->add_header(fmt::format("Authorization: Bearer {}", auth.value));
@ -271,7 +278,7 @@ namespace mamba
return false;
}
return m_retries < size_t(Context::instance().remote_fetch_params.max_retries)
return m_retries < size_t(m_context.remote_fetch_params.max_retries)
&& (m_http_status == 413 || m_http_status == 429 || m_http_status >= 500)
&& !util::starts_with(m_url, "file://");
}
@ -296,8 +303,7 @@ namespace mamba
m_curl_handle->set_opt(CURLOPT_XFERINFODATA, this);
}
m_retry_wait_seconds = m_retry_wait_seconds
* static_cast<std::size_t>(
Context::instance().remote_fetch_params.retry_backoff
* static_cast<std::size_t>(m_context.remote_fetch_params.retry_backoff
);
m_next_retry = now + std::chrono::seconds(m_retry_wait_seconds);
m_retries++;
@ -564,14 +570,14 @@ namespace mamba
bool set_low_speed_opt, set_ssl_no_revoke;
long connect_timeout_secs;
std::string ssl_verify;
get_config(set_low_speed_opt, set_ssl_no_revoke, connect_timeout_secs, ssl_verify);
get_config(m_context, set_low_speed_opt, set_ssl_no_revoke, connect_timeout_secs, ssl_verify);
return curl::check_resource_exists(
m_url,
set_low_speed_opt,
connect_timeout_secs,
set_ssl_no_revoke,
proxy_match(m_url),
proxy_match(m_url, context().remote_fetch_params.proxy_servers),
ssl_verify
);
}
@ -646,7 +652,7 @@ namespace mamba
.value_or(0);
if (!m_retry_wait_seconds)
{
m_retry_wait_seconds = get_default_retry_timeout();
m_retry_wait_seconds = get_default_retry_timeout(m_context);
}
m_next_retry = std::chrono::steady_clock::now()
@ -724,16 +730,13 @@ namespace mamba
* MultiDownloadTarget implementation *
**************************************/
MultiDownloadTarget::MultiDownloadTarget()
MultiDownloadTarget::MultiDownloadTarget(const Context& context)
: m_context(context)
{
p_curl_handle = std::make_unique<CURLMultiHandle>(
Context::instance().threads_params.download_threads
);
p_curl_handle = std::make_unique<CURLMultiHandle>(m_context.threads_params.download_threads);
}
MultiDownloadTarget::~MultiDownloadTarget()
{
}
MultiDownloadTarget::~MultiDownloadTarget() = default;
void MultiDownloadTarget::add(DownloadTarget* target)
{
@ -741,6 +744,14 @@ namespace mamba
{
return;
}
if (&target->context() != &m_context)
{
throw std::invalid_argument(
"DownloadTarget's context is not the same instance as MultiDownloadTarget's context"
);
}
p_curl_handle->add_handle(target->get_curl_handle());
m_targets.push_back(target);
}
@ -813,7 +824,7 @@ namespace mamba
bool sort = options & MAMBA_DOWNLOAD_SORT;
bool no_clear_progress_bars = options & MAMBA_NO_CLEAR_PROGRESS_BARS;
auto& ctx = Context::instance();
auto& ctx = m_context;
if (m_targets.empty())
{

View File

@ -22,7 +22,7 @@ namespace mamba
{
}
History::UserRequest History::UserRequest::prefilled()
History::UserRequest History::UserRequest::prefilled(const Context& context)
{
UserRequest ur;
std::time_t t = std::time(nullptr);
@ -31,8 +31,8 @@ namespace mamba
{
ur.date = mbstr;
}
ur.cmd = Context::instance().command_params.current_command;
ur.conda_version = Context::instance().command_params.conda_version;
ur.cmd = context.command_params.current_command;
ur.conda_version = context.command_params.conda_version;
return ur;
}

View File

@ -308,6 +308,7 @@ namespace mamba
failure
*/
bool run_script(
const Context& context,
const fs::u8path& prefix,
const PackageInfo& pkg_info,
const std::string& action = "post-link",
@ -360,11 +361,11 @@ namespace mamba
if (activate)
{
script_file = wrap_call(
Context::instance().prefix_params.root_prefix,
context,
context.prefix_params.root_prefix,
prefix,
Context::instance().dev,
false,
{ "@CALL", path.string() }
{ "@CALL", path.string() },
WrappedCallOptions::from_context(context)
);
command_args = { comspec.value(), "/d", "/c", script_file->path().string() };
@ -388,11 +389,11 @@ namespace mamba
{
// std::string caller
script_file = wrap_call(
Context::instance().prefix_params.root_prefix.string(),
context,
context.prefix_params.root_prefix.string(),
prefix,
Context::instance().dev,
false,
{ ".", path.string() }
{ ".", path.string() },
WrappedCallOptions::from_context(context)
);
command_args.push_back(shell_path.string());
command_args.push_back(script_file->path().string());
@ -405,7 +406,7 @@ namespace mamba
}
}
envmap["ROOT_PREFIX"] = Context::instance().prefix_params.root_prefix.string();
envmap["ROOT_PREFIX"] = context.prefix_params.root_prefix.string();
envmap["PREFIX"] = env_prefix.size() ? env_prefix : prefix.string();
envmap["PKG_NAME"] = pkg_info.name;
envmap["PKG_VERSION"] = pkg_info.version;
@ -438,7 +439,7 @@ namespace mamba
auto [status, ec] = reproc::run(command_args, options);
auto msg = get_prefix_messages(envmap["PREFIX"]);
if (Context::instance().output_params.json)
if (context.output_params.json)
{
// TODO implement cerr also on Console?
std::cerr << msg;
@ -470,17 +471,19 @@ namespace mamba
, m_specifier(m_pkg_info.str())
, m_context(context)
{
assert(m_context != nullptr);
}
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;
LOG_TRACE << "Unlinking '" << dst.string() << "'";
std::error_code err;
if (remove_or_rename(dst) == 0)
if (remove_or_rename(context, dst) == 0)
{
LOG_DEBUG << "Error when removing file '" << dst.string() << "' will be ignored";
}
@ -504,7 +507,7 @@ namespace mamba
}
if (is_empty)
{
remove_or_rename(parent_path);
remove_or_rename(context, parent_path);
}
else
{
@ -522,6 +525,7 @@ 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");
LOG_INFO << "Unlinking package '" << m_specifier << "'";
@ -536,7 +540,7 @@ namespace mamba
std::string fpath = path["_path"];
if (std::regex_match(fpath, MENU_PATH_REGEX))
{
remove_menu_from_json(m_context->target_prefix / fpath, m_context);
remove_menu_from_json(context, m_context->target_prefix / fpath, m_context);
}
unlink_path(path);
@ -565,6 +569,7 @@ namespace mamba
, m_source(cache_path / m_pkg_info.str())
, m_context(context)
{
assert(m_context != nullptr);
}
std::tuple<std::string, std::string>
@ -734,7 +739,7 @@ namespace mamba
#if defined(__APPLE__)
if (binary_changed && m_pkg_info.subdir == "osx-arm64")
{
codesign(dst, Context::instance().output_params.verbosity > 1);
codesign(dst, m_context->context().output_params.verbosity > 1);
}
#endif
return std::make_tuple(validation::sha256sum(dst), rel_dst.string());
@ -833,6 +838,8 @@ 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() << "'";
@ -1053,19 +1060,19 @@ namespace mamba
}
// Create all start menu shortcuts if prefix name doesn't start with underscore
if (util::on_win && Context::instance().shortcuts
if (util::on_win && context.shortcuts
&& m_context->target_prefix.filename().string()[0] != '_')
{
for (auto& path : paths_data)
{
if (std::regex_match(path.path, MENU_PATH_REGEX))
{
create_menu_from_json(m_context->target_prefix / path.path, m_context);
create_menu_from_json(context, m_context->target_prefix / path.path, m_context);
}
}
}
run_script(m_context->target_prefix, m_pkg_info, "post-link", "", true);
run_script(context, m_context->target_prefix, m_pkg_info, "post-link", "", true);
fs::u8path prefix_meta = m_context->target_prefix / "conda-meta";
if (!fs::exists(prefix_meta))

View File

@ -181,7 +181,13 @@ namespace mamba
std::string cleaned_url;
std::string platform;
util::split_platform(get_known_platforms(), channel, Context::instance().platform, channel, platform);
util::split_platform(
get_known_platforms(),
channel,
channel_context.context().platform,
channel,
platform
);
if (!platform.empty())
{
subdir = platform;

View File

@ -21,9 +21,9 @@ namespace mamba
{
namespace detail
{
std::string get_formatted_env_name(const fs::u8path& target_prefix)
std::string get_formatted_env_name(const Context& context, const fs::u8path& target_prefix)
{
std::string name = env_name(target_prefix);
std::string name = env_name(context, target_prefix);
if (name.find_first_of("\\/") != std::string::npos)
{
return "";
@ -215,9 +215,9 @@ namespace mamba
#endif
void replace_variables(std::string& text, TransactionContext* transaction_context)
void
replace_variables(const Context& ctx, std::string& text, TransactionContext* transaction_context)
{
auto& ctx = mamba::Context::instance();
fs::u8path root_prefix = ctx.prefix_params.root_prefix;
fs::u8path target_prefix;
@ -259,7 +259,7 @@ 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(target_prefix) },
{ "${ENV_NAME}", detail::get_formatted_env_name(ctx, target_prefix) },
{ "${PLATFORM}", platform_bitness },
};
@ -277,19 +277,20 @@ namespace mamba
namespace
{
void create_remove_shortcut_impl(
const Context& ctx,
const fs::u8path& json_file,
TransactionContext* transaction_context,
[[maybe_unused]] bool remove
)
{
std::string json_content = mamba::read_contents(json_file);
replace_variables(json_content, transaction_context);
replace_variables(ctx, json_content, transaction_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(transaction_context->target_prefix);
std::string e_name = detail::get_formatted_env_name(ctx, transaction_context->target_prefix);
if (e_name.size())
{
@ -311,7 +312,6 @@ namespace mamba
// ]
// }
auto& ctx = mamba::Context::instance();
const fs::u8path root_prefix = ctx.prefix_params.root_prefix;
const fs::u8path target_prefix = ctx.prefix_params.target_prefix;
@ -458,11 +458,15 @@ namespace mamba
}
}
void remove_menu_from_json(const fs::u8path& json_file, TransactionContext* context)
void remove_menu_from_json(
const Context& context,
const fs::u8path& json_file,
TransactionContext* transaction_context
)
{
try
{
create_remove_shortcut_impl(json_file, context, true);
create_remove_shortcut_impl(context, json_file, transaction_context, true);
}
catch (const std::exception& e)
{
@ -470,11 +474,15 @@ namespace mamba
}
}
void create_menu_from_json(const fs::u8path& json_file, TransactionContext* context)
void create_menu_from_json(
const Context& context,
const fs::u8path& json_file,
TransactionContext* transaction_context
)
{
try
{
create_remove_shortcut_impl(json_file, context, false);
create_remove_shortcut_impl(context, json_file, transaction_context, false);
}
catch (const std::exception& e)
{

View File

@ -267,6 +267,13 @@ namespace mamba
{
public:
ConsoleData(const Context& ctx)
: m_context(ctx)
{
}
const Context& m_context;
std::mutex m_mutex;
std::unique_ptr<ProgressBarManager> p_progress_bar_manager;
@ -277,15 +284,17 @@ namespace mamba
std::vector<std::string> m_buffer;
TaskSynchronizer tasksync;
TaskSynchronizer m_tasksync;
};
Console::Console()
: p_data(new ConsoleData())
Console::Console(const Context& context)
: p_data(new ConsoleData{ context })
{
set_singleton(*this);
init_progress_bar_manager(ProgressBarMode::multi);
MainExecutor::instance().on_close(
p_data->tasksync.synchronized([this] { terminate_progress_bar_manager(); })
p_data->m_tasksync.synchronized([this] { terminate_progress_bar_manager(); })
);
#ifdef _WIN32
// initialize ANSI codes on Win terminals
@ -296,14 +305,18 @@ namespace mamba
Console::~Console()
{
if (!p_data->is_json_print_cancelled && !p_data->json_log.is_null()) // Note: we cannot
// rely on
// Context::instance()
// to still be valid
// at this point.
if (!p_data->is_json_print_cancelled && !p_data->json_log.is_null())
{
this->json_print();
}
clear_singleton();
}
const Context& Console::context() const
{
return p_data->m_context;
}
@ -324,8 +337,7 @@ namespace mamba
void Console::print(std::string_view str, bool force_print)
{
if (force_print
|| !(Context::instance().output_params.quiet || Context::instance().output_params.json))
if (force_print || !(context().output_params.quiet || context().output_params.json))
{
const std::lock_guard<std::mutex> lock(p_data->m_mutex);
@ -361,7 +373,7 @@ namespace mamba
bool Console::prompt(std::string_view message, char fallback, std::istream& input_stream)
{
if (Context::instance().always_yes)
if (instance().context().always_yes)
{
return true;
}
@ -407,13 +419,20 @@ namespace mamba
ProgressProxy Console::add_progress_bar(const std::string& name, size_t expected_total)
{
if (Context::instance().graphics_params.no_progress_bars)
if (context().graphics_params.no_progress_bars)
{
return ProgressProxy();
}
else
{
return p_data->p_progress_bar_manager->add_progress_bar(name, expected_total);
return p_data->p_progress_bar_manager->add_progress_bar(
name,
{
/* .graphics = */ context().graphics_params,
/* .ascii_only = */ context().ascii_only,
},
expected_total
);
}
}
@ -466,7 +485,7 @@ namespace mamba
// is then a JSON object
void Console::json_write(const nlohmann::json& j)
{
if (Context::instance().output_params.json)
if (context().output_params.json)
{
nlohmann::json tmp = j.flatten();
for (auto it = tmp.begin(); it != tmp.end(); ++it)
@ -479,7 +498,7 @@ namespace mamba
// append a value to the current entry, which is then a list
void Console::json_append(const std::string& value)
{
if (Context::instance().output_params.json)
if (context().output_params.json)
{
p_data->json_log[p_data->json_hier + '/' + std::to_string(p_data->json_index)] = value;
p_data->json_index += 1;
@ -489,7 +508,7 @@ namespace mamba
// append a JSON object to the current entry, which is then a list
void Console::json_append(const nlohmann::json& j)
{
if (Context::instance().output_params.json)
if (context().output_params.json)
{
nlohmann::json tmp = j.flatten();
for (auto it = tmp.begin(); it != tmp.end(); ++it)
@ -504,7 +523,7 @@ namespace mamba
// go down in the hierarchy in the "key" entry, create it if it doesn't exist
void Console::json_down(const std::string& key)
{
if (Context::instance().output_params.json)
if (context().output_params.json)
{
p_data->json_hier += '/' + key;
p_data->json_index = 0;
@ -514,7 +533,7 @@ namespace mamba
// go up in the hierarchy
void Console::json_up()
{
if (Context::instance().output_params.json && !p_data->json_hier.empty())
if (context().output_params.json && !p_data->json_hier.empty())
{
p_data->json_hier.erase(p_data->json_hier.rfind('/'));
}
@ -559,7 +578,7 @@ namespace mamba
{
case log_level::critical:
SPDLOG_CRITICAL(prepend(str, "", std::string(4, ' ').c_str()));
if (Context::instance().output_params.logging_level != log_level::off)
if (Console::instance().context().output_params.logging_level != log_level::off)
{
spdlog::dump_backtrace();
}

View File

@ -109,7 +109,7 @@ namespace mamba
}
}
bool PackageCacheData::has_valid_tarball(const PackageInfo& s)
bool PackageCacheData::has_valid_tarball(const PackageInfo& s, const ValidationOptions& options)
{
std::string pkg = s.str();
if (m_valid_tarballs.find(pkg) != m_valid_tarballs.end())
@ -139,13 +139,13 @@ namespace mamba
}
else
{
if (Context::instance().safety_checks == VerificationLevel::kWarn)
if (options.safety_checks == VerificationLevel::kWarn)
{
LOG_WARNING << "Could not validate package '" + tarball_path.string()
+ "': md5 and sha256 sum unknown.\n"
"Set safety_checks to disabled to override this warning.";
}
else if (Context::instance().safety_checks == VerificationLevel::kEnabled)
else if (options.safety_checks == VerificationLevel::kEnabled)
{
// we cannot validate this archive, but we could also not validate a downloaded
// archive since we just don't know the sha256 or md5 sum
@ -173,7 +173,8 @@ namespace mamba
return valid;
}
bool PackageCacheData::has_valid_extracted_dir(const PackageInfo& s)
bool
PackageCacheData::has_valid_extracted_dir(const PackageInfo& s, const ValidationOptions& options)
{
bool valid = false, can_validate = false;
@ -206,14 +207,14 @@ namespace mamba
|| (!s.sha256.empty() && repodata_record.contains("sha256"));
if (!can_validate)
{
if (Context::instance().safety_checks == VerificationLevel::kWarn)
if (options.safety_checks == VerificationLevel::kWarn)
{
LOG_WARNING
<< "Could not validate package '" + repodata_record_path.string()
+ "': md5 and sha256 sum unknown.\n"
"Set safety_checks to disabled to override this warning.";
}
else if (Context::instance().safety_checks == VerificationLevel::kEnabled)
else if (options.safety_checks == VerificationLevel::kEnabled)
{
throw std::runtime_error(
"Could not validate package '" + repodata_record_path.string()
@ -322,7 +323,7 @@ namespace mamba
if (valid)
{
valid = validate(extracted_dir);
valid = validate(extracted_dir, options);
}
}
}
@ -338,7 +339,11 @@ namespace mamba
return valid;
}
MultiPackageCache::MultiPackageCache(const std::vector<fs::u8path>& cache_paths)
MultiPackageCache::MultiPackageCache(
const std::vector<fs::u8path>& cache_paths,
const ValidationOptions& options
)
: m_options(options)
{
m_caches.reserve(cache_paths.size());
for (auto& c : cache_paths)
@ -408,7 +413,7 @@ namespace mamba
for (PackageCacheData& c : m_caches)
{
if (c.has_valid_tarball(s))
if (c.has_valid_tarball(s, m_options))
{
m_cached_tarballs[pkg] = c.path();
return c.path();
@ -438,7 +443,7 @@ namespace mamba
for (auto& c : m_caches)
{
if (c.has_valid_extracted_dir(s))
if (c.has_valid_extracted_dir(s, m_options))
{
m_cached_extracted_dirs[pkg] = c.path();
return c.path();

View File

@ -54,7 +54,7 @@ namespace mamba
m_filename = pkg_info.fn;
// only do this for micromamba for now
if (Context::instance().command_params.is_micromamba)
if (channel_context.context().command_params.is_micromamba)
{
m_url = channel_context.make_channel(pkg_info.url).urls(true)[0];
}
@ -69,7 +69,7 @@ namespace mamba
m_sha256 = pkg_info.sha256;
m_md5 = pkg_info.md5;
auto& ctx = Context::instance();
auto& ctx = channel_context.context();
m_has_progress_bars = !(
ctx.graphics_params.no_progress_bars || ctx.output_params.quiet || ctx.output_params.json
);
@ -185,7 +185,7 @@ namespace mamba
};
}
bool PackageDownloadExtractTarget::extract()
bool PackageDownloadExtractTarget::extract(const Context& context)
{
// Extracting is __not__ yet thread safe it seems...
interruption_point();
@ -230,15 +230,17 @@ namespace mamba
fs::remove_all(extract_path);
}
const auto extract_options = mamba::ExtractOptions::from_context(context);
// Use non-subproc version if concurrency is disabled to avoid
// any potential subprocess issues
if (DownloadExtractSemaphore::get_max() == 1)
{
mamba::extract(m_tarball_path, extract_path);
mamba::extract(m_tarball_path, extract_path, extract_options);
}
else
{
mamba::extract_subproc(m_tarball_path, extract_path);
mamba::extract_subproc(m_tarball_path, extract_path, extract_options);
}
// mamba::extract(m_tarball_path, extract_path);
interruption_point();
@ -269,14 +271,14 @@ namespace mamba
return true;
}
bool PackageDownloadExtractTarget::extract_from_cache()
bool PackageDownloadExtractTarget::extract_from_cache(const Context& context)
{
this->extract();
this->extract(context);
m_finished = true;
return true;
}
bool PackageDownloadExtractTarget::validate_extract()
bool PackageDownloadExtractTarget::validate_extract(const Context& context)
{
using std::chrono::nanoseconds;
@ -306,12 +308,12 @@ namespace mamba
}
LOG_DEBUG << "'" << m_tarball_path.string() << "' successfully validated";
bool result = this->extract();
bool result = this->extract(context);
m_finished = true;
return result;
}
bool PackageDownloadExtractTarget::finalize_callback(const DownloadTarget&)
bool PackageDownloadExtractTarget::finalize_callback(const DownloadTarget& target)
{
if (m_has_progress_bars)
{
@ -328,7 +330,9 @@ namespace mamba
}
LOG_INFO << "Download finished, validating '" << m_tarball_path.string() << "'";
MainExecutor::instance().schedule(&PackageDownloadExtractTarget::validate_extract, this);
MainExecutor::instance().schedule(
m_tasksync.synchronized([&] { validate_extract(target.context()); })
);
return true;
}
@ -364,7 +368,7 @@ namespace mamba
}
// todo remove cache from this interface
DownloadTarget* PackageDownloadExtractTarget::target(MultiPackageCache& caches)
DownloadTarget* PackageDownloadExtractTarget::target(Context& context, MultiPackageCache& caches)
{
// tarball can be removed, it's fine if only the correct dest dir exists
// 1. If there is extracted cache, use it, otherwise next.
@ -396,8 +400,7 @@ namespace mamba
m_tarball_path = tarball_cache / m_filename;
m_validation_result = VALIDATION_RESULT::VALID;
MainExecutor::instance().schedule(
&PackageDownloadExtractTarget::extract_from_cache,
this
m_tasksync.synchronized([&] { extract_from_cache(context); })
);
LOG_DEBUG << "Using cached tarball '" << m_filename << "'";
return nullptr;
@ -409,7 +412,12 @@ namespace mamba
LOG_DEBUG << "Adding '" << m_name << "' to download targets from '" << m_url << "'";
m_tarball_path = m_cache_path / m_filename;
m_target = std::make_unique<DownloadTarget>(m_name, m_url, m_tarball_path.string());
m_target = std::make_unique<DownloadTarget>(
context,
m_name,
m_url,
m_tarball_path.string()
);
m_target->set_finalize_callback(&PackageDownloadExtractTarget::finalize_callback, this);
m_target->set_expected_size(m_expected_size);
if (m_has_progress_bars)

View File

@ -26,6 +26,17 @@
namespace mamba
{
ExtractOptions ExtractOptions::from_context(const Context& context)
{
return {
/* .sparse = */ context.extract_sparse,
/* .subproc_mode = */ context.command_params.is_micromamba
? extract_subproc_mode::micromamba
: extract_subproc_mode::mamba_package,
};
}
class extraction_guard
{
public:
@ -162,7 +173,12 @@ namespace mamba
archive_entry* m_entry;
};
void stream_extract_archive(scoped_archive_read& a, const fs::u8path& destination);
void stream_extract_archive(
scoped_archive_read& a,
const fs::u8path& destination,
const ExtractOptions& options
);
static int copy_data(scoped_archive_read& ar, scoped_archive_write& aw)
{
@ -473,7 +489,8 @@ namespace mamba
}
}
void extract_archive(const fs::u8path& file, const fs::u8path& destination)
void
extract_archive(const fs::u8path& file, const fs::u8path& destination, const ExtractOptions& options)
{
LOG_INFO << "Extracting " << file << " to " << destination;
extraction_guard g(destination);
@ -492,7 +509,7 @@ namespace mamba
throw std::runtime_error(file.string() + " : Could not open archive for reading.");
}
stream_extract_archive(a, destination);
stream_extract_archive(a, destination, options);
}
namespace
@ -510,7 +527,11 @@ namespace mamba
};
}
void stream_extract_archive(scoped_archive_read& a, const fs::u8path& destination)
void stream_extract_archive(
scoped_archive_read& a,
const fs::u8path& destination,
const ExtractOptions& options
)
{
auto prev_path = fs::current_path();
if (!fs::exists(destination))
@ -527,7 +548,7 @@ namespace mamba
flags |= ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS;
flags |= ARCHIVE_EXTRACT_UNLINK;
if (Context::instance().extract_sparse)
if (options.sparse)
{
flags |= ARCHIVE_EXTRACT_SPARSE;
}
@ -616,8 +637,12 @@ namespace mamba
}
void
extract_conda(const fs::u8path& file, const fs::u8path& dest_dir, const std::vector<std::string>& parts)
void extract_conda(
const fs::u8path& file,
const fs::u8path& dest_dir,
const ExtractOptions& options,
const std::vector<std::string>& parts
)
{
scoped_archive_read a;
archive_read_support_format_zip(a);
@ -673,7 +698,7 @@ namespace mamba
archive_read_support_format_tar(inner);
archive_read_open_archive_entry(inner, &extract_context);
stream_extract_archive(inner, dest_dir);
stream_extract_archive(inner, dest_dir, options);
}
else if (p.filename() == "metadata.json")
{
@ -716,18 +741,18 @@ namespace mamba
throw std::runtime_error("Unknown package format.");
}
void extract(const fs::u8path& file, const fs::u8path& dest)
void extract(const fs::u8path& file, const fs::u8path& dest, const ExtractOptions& options)
{
static std::mutex extract_mutex;
std::lock_guard<std::mutex> lock(extract_mutex);
if (util::ends_with(file.string(), ".tar.bz2"))
{
extract_archive(file, dest);
extract_archive(file, dest, options);
}
else if (util::ends_with(file.string(), ".conda"))
{
extract_conda(file, dest);
extract_conda(file, dest, options);
}
else
{
@ -736,17 +761,18 @@ namespace mamba
}
}
fs::u8path extract(const fs::u8path& file)
fs::u8path extract(const fs::u8path& file, const ExtractOptions& options)
{
fs::u8path dest_dir = extract_dest_dir(file);
extract(file, dest_dir);
const fs::u8path dest_dir = extract_dest_dir(file);
extract(file, dest_dir, options);
return dest_dir;
}
void extract_subproc(const fs::u8path& file, const fs::u8path& dest)
void
extract_subproc(const fs::u8path& file, const fs::u8path& dest, const ExtractOptions& options)
{
std::vector<std::string> args;
if (Context::instance().command_params.is_micromamba)
if (options.subproc_mode == extract_subproc_mode::micromamba)
{
args = { get_self_exe_path().string(), "package", "extract", file.string(), dest.string() };
}
@ -769,22 +795,27 @@ namespace mamba
LOG_DEBUG << "Subprocess extraction exited with code " << ec << ", stdout: " << out
<< ", stderr: " << err;
LOG_DEBUG << "Running in-process extraction for '" << file.string() << "'";
extract(file, dest);
extract(file, dest, options);
}
}
bool
transmute(const fs::u8path& pkg_file, const fs::u8path& target, int compression_level, int compression_threads)
bool transmute(
const fs::u8path& pkg_file,
const fs::u8path& target,
int compression_level,
int compression_threads,
const ExtractOptions& options
)
{
TemporaryDirectory extract_dir;
if (util::ends_with(pkg_file.string(), ".tar.bz2"))
{
extract_archive(pkg_file, extract_dir);
extract_archive(pkg_file, extract_dir, options);
}
else if (util::ends_with(pkg_file.string(), ".conda"))
{
extract_conda(pkg_file, extract_dir);
extract_conda(pkg_file, extract_dir, options);
}
else
{
@ -795,9 +826,10 @@ namespace mamba
return true;
}
bool validate(const fs::u8path& pkg_folder)
bool validate(const fs::u8path& pkg_folder, const ValidationOptions& options)
{
auto safety_checks = Context::instance().safety_checks;
auto safety_checks = options.safety_checks;
if (safety_checks == VerificationLevel::kDisabled)
{
return true;
@ -805,7 +837,7 @@ namespace mamba
bool is_warn = safety_checks == VerificationLevel::kWarn;
bool is_fail = safety_checks == VerificationLevel::kEnabled;
bool full_validation = Context::instance().extra_safety_checks;
bool full_validation = options.extra_safety_checks;
try
{

View File

@ -53,6 +53,11 @@ namespace mamba
return m_data->channel_context;
}
Context& MPool::context() const
{
return channel_context().context();
}
solv::ObjPool& MPool::pool()
{
return m_data->pool;
@ -67,11 +72,13 @@ namespace mamba
{
// ensure that debug logging goes to stderr as to not interfere with stdout json output
pool().raw()->debugmask |= SOLV_DEBUG_TO_STDERR;
if (Context::instance().output_params.verbosity > 2)
const auto& context = channel_context().context();
if (context.output_params.verbosity > 2)
{
pool_setdebuglevel(pool().raw(), Context::instance().output_params.verbosity - 1);
pool_setdebuglevel(pool().raw(), context.output_params.verbosity - 1);
pool().set_debug_callback(
[logger = spdlog::get("libsolv")](::Pool*, int type, std::string_view msg) noexcept
[logger = spdlog::get("libsolv"),
&context](::Pool*, int type, std::string_view msg) noexcept
{
if (msg.size() == 0 || msg.back() != '\n')
{
@ -87,7 +94,7 @@ namespace mamba
{
logger->warn(log);
}
else if (Context::instance().output_params.verbosity > 2)
else if (context.output_params.verbosity > 2)
{
logger->info(log);
}
@ -141,7 +148,7 @@ namespace mamba
return true;
}
auto& custom_multichannels = Context::instance().custom_multichannels;
auto& custom_multichannels = channel_context.context().custom_multichannels;
auto x = custom_multichannels.find(needle.name());
if (x != custom_multichannels.end())
{

View File

@ -224,4 +224,9 @@ namespace mamba
{
return p_bar->repr();
}
const ProgressBarOptions& ProgressProxy::options() const
{
return p_bar->options();
}
}

View File

@ -521,16 +521,16 @@ namespace mamba
* ProgressBarRepr *
*******************/
ProgressBarRepr::ProgressBarRepr()
: m_style_none(Context::instance().graphics_params.palette.progress_bar_none)
, m_style_downloaded(Context::instance().graphics_params.palette.progress_bar_downloaded)
, m_style_extracted(Context::instance().graphics_params.palette.progress_bar_extracted)
, m_ascii_only(Context::instance().ascii_only)
ProgressBarRepr::ProgressBarRepr(ProgressBarOptions options)
: m_style_none(options.graphics.palette.progress_bar_none)
, m_style_downloaded(options.graphics.palette.progress_bar_downloaded)
, m_style_extracted(options.graphics.palette.progress_bar_extracted)
, m_ascii_only(options.ascii_only)
{
}
ProgressBarRepr::ProgressBarRepr(ProgressBar* pbar)
: ProgressBarRepr()
: ProgressBarRepr(pbar->options())
{
p_progress_bar = pbar;
}
@ -1278,11 +1278,17 @@ namespace mamba
* ProgressBar *
***************/
ProgressBar::ProgressBar(const std::string& prefix, std::size_t total, int width)
ProgressBar::ProgressBar(
const std::string& prefix,
std::size_t total,
ProgressBarOptions options,
int width
)
: m_progress(0)
, m_total(total)
, m_width(width)
, m_repr(this)
, m_options(options)
, m_is_spinner(false)
{
m_repr.prefix.set_value(prefix);
@ -1294,6 +1300,11 @@ namespace mamba
std::lock_guard<std::mutex> lock(m_mutex);
}
const ProgressBarOptions& ProgressBar::options() const
{
return m_options;
}
ProgressBar& ProgressBar::set_progress(std::size_t current, std::size_t total)
{
m_current = current;
@ -1659,8 +1670,13 @@ namespace mamba
* DefaultProgressBar *
**********************/
DefaultProgressBar::DefaultProgressBar(const std::string& prefix, std::size_t total, int width)
: ProgressBar(prefix, total, width)
DefaultProgressBar::DefaultProgressBar(
const std::string& prefix,
std::size_t total,
ProgressBarOptions options,
int width
)
: ProgressBar(prefix, total, options, width)
{
}
@ -1682,9 +1698,10 @@ namespace mamba
const std::string& prefix,
AggregatedBarManager* /*manager*/,
std::size_t total,
ProgressBarOptions options,
int width
)
: ProgressBar(prefix, total, width)
: ProgressBar(prefix, total, options, width)
{
}
@ -1705,13 +1722,17 @@ namespace mamba
{
}
ProgressProxy
MultiBarManager::add_progress_bar(const std::string& name, std::size_t expected_total)
ProgressProxy MultiBarManager::add_progress_bar(
const std::string& name,
ProgressBarOptions options,
std::size_t expected_total
)
{
std::string prefix = name;
std::lock_guard<std::mutex> lock(m_mutex);
m_progress_bars.push_back(std::make_unique<DefaultProgressBar>(prefix, expected_total));
m_progress_bars.push_back(std::make_unique<DefaultProgressBar>(prefix, expected_total, options)
);
return ProgressProxy(m_progress_bars[m_progress_bars.size() - 1].get());
}
@ -1816,11 +1837,16 @@ namespace mamba
{
}
ProgressProxy
AggregatedBarManager::add_progress_bar(const std::string& prefix, std::size_t expected_total)
ProgressProxy AggregatedBarManager::add_progress_bar(
const std::string& prefix,
ProgressBarOptions options,
std::size_t expected_total
)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_progress_bars.push_back(std::make_unique<DefaultProgressBar>(prefix, expected_total, 100));
m_progress_bars.push_back(
std::make_unique<DefaultProgressBar>(prefix, expected_total, options, 100)
);
return ProgressProxy(m_progress_bars[m_progress_bars.size() - 1].get());
}
@ -1857,6 +1883,7 @@ namespace mamba
std::make_unique<DefaultProgressBar>(
label,
std::numeric_limits<std::size_t>::max(),
progress_bar.options(),
100
) });
}

View File

@ -18,6 +18,7 @@
#include <fmt/color.h>
#include <spdlog/spdlog.h>
#include "mamba/core/context.hpp"
#include "mamba/core/progress_bar.hpp"
namespace mamba
@ -128,8 +129,8 @@ namespace mamba
{
public:
ProgressBarRepr();
ProgressBarRepr(ProgressBar* pbar);
explicit ProgressBarRepr(ProgressBarOptions options);
explicit ProgressBarRepr(ProgressBar* pbar);
FieldRepr prefix, progress, current, separator, total, speed, postfix, elapsed;
void print(std::ostream& ostream, std::size_t width = 0, bool with_endl = true);
@ -169,6 +170,12 @@ namespace mamba
class ProgressBarManager;
struct ProgressBarOptions
{
Context::GraphicsParams graphics;
bool ascii_only = false;
};
/*******************************
* Public API of progress bars *
*******************************/
@ -184,7 +191,11 @@ namespace mamba
ProgressBarManager(ProgressBarManager&&) = delete;
ProgressBarManager& operator=(ProgressBarManager&&) = delete;
virtual ProgressProxy add_progress_bar(const std::string& name, size_t expected_total = 0) = 0;
virtual ProgressProxy add_progress_bar(
const std::string& name,
ProgressBarOptions options,
size_t expected_total = 0
) = 0;
virtual void clear_progress_bars();
virtual void add_label(const std::string& label, const ProgressProxy& progress_bar);
@ -253,7 +264,9 @@ namespace mamba
MultiBarManager(std::size_t width);
virtual ~MultiBarManager() = default;
ProgressProxy add_progress_bar(const std::string& name, size_t expected_total) override;
ProgressProxy
add_progress_bar(const std::string& name, ProgressBarOptions options, size_t expected_total)
override;
std::size_t print(
std::ostream& os,
@ -271,7 +284,11 @@ namespace mamba
AggregatedBarManager(std::size_t width);
virtual ~AggregatedBarManager() = default;
ProgressProxy add_progress_bar(const std::string& name, std::size_t expected_total) override;
ProgressProxy add_progress_bar(
const std::string& name,
ProgressBarOptions options,
std::size_t expected_total
) override;
void update_download_bar(std::size_t current_diff);
void update_extract_bar();
@ -361,9 +378,11 @@ namespace mamba
int width() const;
const ProgressBarOptions& options() const;
protected:
ProgressBar(const std::string& prefix, std::size_t total, int width = 0);
ProgressBar(const std::string& prefix, std::size_t total, ProgressBarOptions options, int width = 0);
double m_progress = 0.;
std::size_t m_current = 0;
@ -378,6 +397,7 @@ namespace mamba
time_point_t m_task_time, m_avg_speed_time;
ProgressBarRepr m_repr;
ProgressBarOptions m_options;
bool m_is_spinner;
bool m_completed = false;
@ -397,7 +417,12 @@ namespace mamba
{
public:
DefaultProgressBar(const std::string& prefix, std::size_t total, int width = 0);
DefaultProgressBar(
const std::string& prefix,
std::size_t total,
ProgressBarOptions options,
int width = 0
);
virtual ~DefaultProgressBar() = default;
void print(std::ostream& stream, std::size_t width = 0, bool with_endl = true) override;
@ -411,6 +436,7 @@ namespace mamba
const std::string& prefix,
AggregatedBarManager* manager,
std::size_t total,
ProgressBarOptions options,
int width = 0
);
virtual ~HiddenProgressBar() = default;

View File

@ -625,6 +625,8 @@ namespace mamba
return printer.print(out);
}
using GraphicsParams = Context::GraphicsParams;
class graph_printer
{
public:
@ -632,9 +634,10 @@ namespace mamba
using graph_type = query_result::dependency_graph;
using node_id = graph_type::node_id;
explicit graph_printer(std::ostream& out)
explicit graph_printer(std::ostream& out, GraphicsParams graphics)
: m_is_last(false)
, m_out(out)
, m_graphics(std::move(graphics))
{
}
@ -679,8 +682,7 @@ namespace mamba
void forward_or_cross_edge(node_id, node_id to, const graph_type& g)
{
print_prefix(to);
m_out << g.node(to).name
<< fmt::format(Context::instance().graphics_params.palette.shown, " already visited\n");
m_out << g.node(to).name << fmt::format(m_graphics.palette.shown, " already visited\n");
}
void finish_edge(node_id /*from*/, node_id to, const graph_type& /*g*/)
@ -719,14 +721,15 @@ namespace mamba
std::vector<std::string> m_prefix_stack;
bool m_is_last;
std::ostream& m_out;
const GraphicsParams m_graphics;
};
std::ostream& query_result::tree(std::ostream& out) const
std::ostream& query_result::tree(std::ostream& out, const GraphicsParams& graphics) const
{
bool use_graph = (m_dep_graph.number_of_nodes() > 0) && !m_dep_graph.successors(0).empty();
if (use_graph)
{
graph_printer printer(out);
graph_printer printer{ out, graphics };
dfs_raw(m_dep_graph, printer, /* start= */ node_id(0));
}
else if (!m_pkg_id_list.empty())

View File

@ -121,7 +121,7 @@ namespace mamba
add_package_info(record);
}
if (Context::instance().add_pip_as_python_dependency)
if (pool.context().add_pip_as_python_dependency)
{
add_pip_as_python_dependency();
}
@ -244,7 +244,7 @@ namespace mamba
{
LOG_INFO << "Reading repodata.json file " << filename << " for repo " << name();
// TODO make this as part of options of the repo/pool
const int flags = Context::instance().use_only_tar_bz2 ? CONDA_ADD_USE_ONLY_TAR_BZ2 : 0;
const int flags = m_pool.context().use_only_tar_bz2 ? CONDA_ADD_USE_ONLY_TAR_BZ2 : 0;
srepo(*this).legacy_read_conda_repodata(filename, flags);
}
@ -322,7 +322,7 @@ namespace mamba
read_json(json_file);
// TODO move this to a more structured approach for repodata patching?
if (Context::instance().add_pip_as_python_dependency)
if (m_pool.context().add_pip_as_python_dependency)
{
add_pip_as_python_dependency();
}

View File

@ -187,6 +187,7 @@ namespace mamba
}
ScopedProcFile::ScopedProcFile(
const Context& context,
const std::string& name,
const std::vector<std::string>& command,
LockFile proc_dir_lock
@ -211,7 +212,7 @@ namespace mamba
nlohmann::json file_json;
file_json["name"] = name;
file_json["command"] = command;
file_json["prefix"] = Context::instance().prefix_params.target_prefix.string();
file_json["prefix"] = context.prefix_params.target_prefix.string();
// TODO: add other info here if necessary
pid_file << file_json;
}
@ -284,6 +285,7 @@ namespace mamba
#endif
int run_in_environment(
const Context& context,
const fs::u8path& prefix,
std::vector<std::string> command,
const std::string& cwd,
@ -319,7 +321,7 @@ namespace mamba
}
#endif
auto [wrapped_command, script_file] = prepare_wrapped_call(prefix, command);
auto [wrapped_command, script_file] = prepare_wrapped_call(context, prefix, command);
fmt::print(LOG_DEBUG, "Running wrapped script: {}", fmt::join(command, " "));
@ -372,7 +374,7 @@ namespace mamba
if (detach)
{
Console::stream() << fmt::format(
Context::instance().graphics_params.palette.success,
context.graphics_params.palette.success,
"Running wrapped script {} in the background\n",
fmt::join(command, " ")
);
@ -419,6 +421,7 @@ namespace mamba
if (fs::is_directory(proc_dir()) && mamba::path::is_writable(proc_dir()))
{
scoped_proc_file = std::make_unique<ScopedProcFile>(
context,
process_name,
raw_command,
std::move(proc_dir_lock)

View File

@ -111,13 +111,17 @@ namespace mamba
return content;
}
void set_autorun_registry_key(const std::wstring& reg_path, const std::wstring& value)
void set_autorun_registry_key(
const std::wstring& reg_path,
const std::wstring& value,
const Context::GraphicsParams& graphics
)
{
auto out = Console::stream();
fmt::print(
out,
"Setting cmd.exe AUTORUN to: {}",
fmt::styled(to_utf8(value), Context::instance().graphics_params.palette.success)
fmt::styled(to_utf8(value), graphics.palette.success)
);
winreg::RegKey key{ HKEY_CURRENT_USER, reg_path };
@ -131,7 +135,8 @@ namespace mamba
+ std::wstring(L"\"");
}
void init_cmd_exe_registry(const std::wstring& reg_path, const fs::u8path& conda_prefix)
void
init_cmd_exe_registry(const Context& context, const std::wstring& reg_path, const fs::u8path& conda_prefix)
{
std::wstring prev_value = get_autorun_registry_key(reg_path);
std::wstring hook_string = get_hook_string(conda_prefix);
@ -166,7 +171,7 @@ namespace mamba
// set modified registry key
if (new_value != prev_value)
{
set_autorun_registry_key(reg_path, new_value);
set_autorun_registry_key(reg_path, new_value, context.graphics_params);
}
else
{
@ -174,15 +179,16 @@ namespace mamba
fmt::print(
out,
"{}",
fmt::styled(
"cmd.exe already initialized.",
Context::instance().graphics_params.palette.success
)
fmt::styled("cmd.exe already initialized.", context.graphics_params.palette.success)
);
}
}
void deinit_cmd_exe_registry(const std::wstring& reg_path, const fs::u8path& conda_prefix)
void deinit_cmd_exe_registry(
const std::wstring& reg_path,
const fs::u8path& conda_prefix,
const Context::GraphicsParams& graphics
)
{
std::wstring prev_value = get_autorun_registry_key(reg_path);
std::wstring hook_string = get_hook_string(conda_prefix);
@ -211,19 +217,12 @@ namespace mamba
// set modified registry key
if (new_value != prev_value)
{
set_autorun_registry_key(reg_path, new_value);
set_autorun_registry_key(reg_path, new_value, graphics);
}
else
{
auto out = Console::stream();
fmt::print(
out,
"{}",
fmt::styled(
"cmd.exe not initialized yet.",
Context::instance().graphics_params.palette.success
)
);
fmt::print(out, "{}", fmt::styled("cmd.exe not initialized yet.", graphics.palette.success));
}
}
#endif // _WIN32
@ -408,6 +407,7 @@ namespace mamba
}
void modify_rc_file(
const Context& context,
const fs::u8path& file_path,
const fs::u8path& conda_prefix,
const std::string& shell,
@ -458,10 +458,10 @@ namespace mamba
out,
"Adding (or replacing) the following in your {} file\n{}",
fmt::streamed(file_path),
fmt::styled(conda_init_content, Context::instance().graphics_params.palette.success)
fmt::styled(conda_init_content, context.graphics_params.palette.success)
);
if (Context::instance().dry_run)
if (context.dry_run)
{
return;
}
@ -480,7 +480,8 @@ namespace mamba
}
}
void reset_rc_file(const fs::u8path& file_path, const std::string&, const fs::u8path&)
void
reset_rc_file(const Context& context, const fs::u8path& file_path, const std::string&, const fs::u8path&)
{
Console::stream() << "Resetting RC file " << file_path << "\nDeleting config for root prefix "
<< "\nClearing mamba executable environment variable";
@ -504,7 +505,7 @@ namespace mamba
fmt::streamed(file_path),
fmt::styled(
"# >>> mamba initialize >>>\n...\n# <<< mamba initialize <<<",
Context::instance().graphics_params.palette.success
context.graphics_params.palette.success
)
);
@ -516,7 +517,7 @@ namespace mamba
std::string result = std::regex_replace(rc_content, MAMBA_INITIALIZE_RE_BLOCK, "");
if (Context::instance().dry_run)
if (context.dry_run)
{
return;
}
@ -525,7 +526,7 @@ namespace mamba
rc_file << result;
}
std::string get_hook_contents(const std::string& shell)
std::string get_hook_contents(const Context& context, const std::string& shell)
{
fs::u8path exe = get_self_exe_path();
@ -563,12 +564,13 @@ namespace mamba
}
else if (shell == "cmd.exe")
{
init_root_prefix_cmdexe(Context::instance().prefix_params.root_prefix);
init_root_prefix_cmdexe(context, context.prefix_params.root_prefix);
LOG_WARNING << "Hook installed, now 'manually' execute:";
LOG_WARNING << " CALL "
<< std::quoted((Context::instance().prefix_params.root_prefix / "condabin"
/ "mamba_hook.bat")
.string());
LOG_WARNING
<< " CALL "
<< std::quoted(
(context.prefix_params.root_prefix / "condabin" / "mamba_hook.bat").string()
);
}
else if (shell == "fish")
{
@ -580,7 +582,7 @@ namespace mamba
return "";
}
void init_root_prefix_cmdexe(const fs::u8path& root_prefix)
void init_root_prefix_cmdexe(const Context&, const fs::u8path& root_prefix)
{
fs::u8path exe = get_self_exe_path();
@ -646,9 +648,9 @@ namespace mamba
mamba_hook_bat_f << hook_content;
}
void deinit_root_prefix_cmdexe(const fs::u8path& root_prefix)
void deinit_root_prefix_cmdexe(const Context& context, const fs::u8path& root_prefix)
{
if (Context::instance().dry_run)
if (context.dry_run)
{
return;
}
@ -689,9 +691,9 @@ namespace mamba
}
}
void init_root_prefix(const std::string& shell, const fs::u8path& root_prefix)
void init_root_prefix(Context& context, const std::string& shell, const fs::u8path& root_prefix)
{
Context::instance().prefix_params.root_prefix = root_prefix;
context.prefix_params.root_prefix = root_prefix;
if (!fs::exists(root_prefix))
{
@ -700,8 +702,8 @@ namespace mamba
if (shell == "zsh" || shell == "bash" || shell == "posix")
{
PosixActivator a;
auto sh_source_path = a.hook_source_path();
PosixActivator activator{ context };
auto sh_source_path = activator.hook_source_path();
try
{
fs::create_directories(sh_source_path.parent_path());
@ -715,8 +717,8 @@ namespace mamba
}
else if (shell == "csh")
{
CshActivator a;
auto sh_source_path = a.hook_source_path();
CshActivator activator{ context };
auto sh_source_path = activator.hook_source_path();
try
{
fs::create_directories(sh_source_path.parent_path());
@ -730,8 +732,8 @@ namespace mamba
}
else if (shell == "xonsh")
{
XonshActivator a;
auto sh_source_path = a.hook_source_path();
XonshActivator activator{ context };
auto sh_source_path = activator.hook_source_path();
try
{
fs::create_directories(sh_source_path.parent_path());
@ -745,8 +747,8 @@ namespace mamba
}
else if (shell == "fish")
{
FishActivator a;
auto sh_source_path = a.hook_source_path();
FishActivator activator{ context };
auto sh_source_path = activator.hook_source_path();
try
{
fs::create_directories(sh_source_path.parent_path());
@ -760,7 +762,7 @@ namespace mamba
}
else if (shell == "cmd.exe")
{
init_root_prefix_cmdexe(root_prefix);
init_root_prefix_cmdexe(context, root_prefix);
}
else if (shell == "powershell")
{
@ -779,50 +781,50 @@ namespace mamba
}
}
void deinit_root_prefix(const std::string& shell, const fs::u8path& root_prefix)
void deinit_root_prefix(Context& context, const std::string& shell, const fs::u8path& root_prefix)
{
if (Context::instance().dry_run)
if (context.dry_run)
{
return;
}
Context::instance().prefix_params.root_prefix = root_prefix;
context.prefix_params.root_prefix = root_prefix;
if (shell == "zsh" || shell == "bash" || shell == "posix")
{
PosixActivator a;
auto sh_source_path = a.hook_source_path();
PosixActivator activator{ context };
auto sh_source_path = activator.hook_source_path();
fs::remove(sh_source_path);
LOG_INFO << "Removed " << sh_source_path << " file.";
}
else if (shell == "csh")
{
CshActivator a;
auto sh_source_path = a.hook_source_path();
CshActivator activator{ context };
auto sh_source_path = activator.hook_source_path();
fs::remove(sh_source_path);
LOG_INFO << "Removed " << sh_source_path << " file.";
}
else if (shell == "xonsh")
{
XonshActivator a;
auto sh_source_path = a.hook_source_path();
XonshActivator activator{ context };
auto sh_source_path = activator.hook_source_path();
fs::remove(sh_source_path);
LOG_INFO << "Removed " << sh_source_path << " file.";
}
else if (shell == "fish")
{
FishActivator a;
auto sh_source_path = a.hook_source_path();
FishActivator activator{ context };
auto sh_source_path = activator.hook_source_path();
fs::remove(sh_source_path);
LOG_INFO << "Removed " << sh_source_path << " file.";
}
else if (shell == "cmd.exe")
{
deinit_root_prefix_cmdexe(root_prefix);
deinit_root_prefix_cmdexe(context, root_prefix);
}
else if (shell == "powershell")
{
@ -857,7 +859,8 @@ namespace mamba
return out.str();
}
void init_powershell(const fs::u8path& profile_path, const fs::u8path& conda_prefix)
void
init_powershell(const Context& context, const fs::u8path& profile_path, const fs::u8path& conda_prefix)
{
// NB: the user may not have created a profile. We need to check
// if the file exists first.
@ -880,7 +883,7 @@ namespace mamba
out,
"Adding (or replacing) the following in your {} file\n{}",
fmt::streamed(profile_path),
fmt::styled(conda_init_content, Context::instance().graphics_params.palette.success)
fmt::styled(conda_init_content, context.graphics_params.palette.success)
);
if (found_mamba_initialize)
@ -896,7 +899,7 @@ namespace mamba
LOG_DEBUG << "Original profile content:\n" << profile_original_content;
LOG_DEBUG << "Profile content:\n" << profile_content;
if (Context::instance().dry_run)
if (context.dry_run)
{
return;
}
@ -925,7 +928,7 @@ namespace mamba
return;
}
void deinit_powershell(const fs::u8path& profile_path, const fs::u8path&)
void deinit_powershell(const Context& context, const fs::u8path& profile_path, const fs::u8path&)
{
if (!fs::exists(profile_path))
{
@ -944,7 +947,7 @@ namespace mamba
fmt::streamed(profile_path),
fmt::styled(
"#region mamba initialize\n...\n#endregion\n",
Context::instance().graphics_params.palette.success
context.graphics_params.palette.success
)
);
}
@ -952,7 +955,7 @@ namespace mamba
profile_content = std::regex_replace(profile_content, MAMBA_INITIALIZE_PS_RE_BLOCK, "");
LOG_DEBUG << "Profile content:\n" << profile_content;
if (Context::instance().dry_run)
if (context.dry_run)
{
return;
}
@ -1011,9 +1014,9 @@ namespace mamba
}
}
void init_shell(const std::string& shell, const fs::u8path& conda_prefix)
void init_shell(Context& context, const std::string& shell, const fs::u8path& conda_prefix)
{
init_root_prefix(shell, conda_prefix);
init_root_prefix(context, shell, conda_prefix);
auto mamba_exe = get_self_exe_path();
fs::u8path home = env::home_directory();
if (shell == "bash")
@ -1027,34 +1030,34 @@ namespace mamba
// Git Bash, Cygwin, and MSYS2 all use .bash_profile by default.
fs::u8path bashrc_path = (util::on_mac || util::on_win) ? home / ".bash_profile"
: home / ".bashrc";
modify_rc_file(bashrc_path, conda_prefix, shell, mamba_exe);
modify_rc_file(context, bashrc_path, conda_prefix, shell, mamba_exe);
}
else if (shell == "zsh")
{
fs::u8path zshrc_path = home / ".zshrc";
modify_rc_file(zshrc_path, conda_prefix, shell, mamba_exe);
modify_rc_file(context, zshrc_path, conda_prefix, shell, mamba_exe);
}
else if (shell == "csh")
{
fs::u8path cshrc_path = home / ".tcshrc";
modify_rc_file(cshrc_path, conda_prefix, shell, mamba_exe);
modify_rc_file(context, cshrc_path, conda_prefix, shell, mamba_exe);
}
else if (shell == "xonsh")
{
fs::u8path xonshrc_path = home / ".xonshrc";
modify_rc_file(xonshrc_path, conda_prefix, shell, mamba_exe);
modify_rc_file(context, xonshrc_path, conda_prefix, shell, mamba_exe);
}
else if (shell == "fish")
{
fs::u8path fishrc_path = home / ".config" / "fish" / "config.fish";
modify_rc_file(fishrc_path, conda_prefix, shell, mamba_exe);
modify_rc_file(context, fishrc_path, conda_prefix, shell, mamba_exe);
}
else if (shell == "cmd.exe")
{
#ifndef _WIN32
throw std::runtime_error("CMD.EXE can only be initialized on Windows.");
#else
init_cmd_exe_registry(L"Software\\Microsoft\\Command Processor", conda_prefix);
init_cmd_exe_registry(context, L"Software\\Microsoft\\Command Processor", conda_prefix);
#endif
}
else if (shell == "powershell")
@ -1074,7 +1077,7 @@ namespace mamba
{
pwsh_profiles.insert(profile_path);
Console::stream() << "Init " << exe << " profile at '" << profile_path << "'";
init_powershell(profile_path, conda_prefix);
init_powershell(context, profile_path, conda_prefix);
}
}
}
@ -1084,11 +1087,11 @@ namespace mamba
throw std::runtime_error("Support for other shells not yet implemented.");
}
#ifdef _WIN32
enable_long_paths_support(false);
enable_long_paths_support(false, context.graphics_params.palette);
#endif
}
void deinit_shell(const std::string& shell, const fs::u8path& conda_prefix)
void deinit_shell(Context& context, const std::string& shell, const fs::u8path& conda_prefix)
{
auto mamba_exe = get_self_exe_path();
fs::u8path home = env::home_directory();
@ -1096,34 +1099,38 @@ namespace mamba
{
fs::u8path bashrc_path = (util::on_mac || util::on_win) ? home / ".bash_profile"
: home / ".bashrc";
reset_rc_file(bashrc_path, shell, mamba_exe);
reset_rc_file(context, bashrc_path, shell, mamba_exe);
}
else if (shell == "zsh")
{
fs::u8path zshrc_path = home / ".zshrc";
reset_rc_file(zshrc_path, shell, mamba_exe);
reset_rc_file(context, zshrc_path, shell, mamba_exe);
}
else if (shell == "xonsh")
{
fs::u8path xonshrc_path = home / ".xonshrc";
reset_rc_file(xonshrc_path, shell, mamba_exe);
reset_rc_file(context, xonshrc_path, shell, mamba_exe);
}
else if (shell == "csh")
{
fs::u8path tcshrc_path = home / ".tcshrc";
reset_rc_file(tcshrc_path, shell, mamba_exe);
reset_rc_file(context, tcshrc_path, shell, mamba_exe);
}
else if (shell == "fish")
{
fs::u8path fishrc_path = home / ".config" / "fish" / "config.fish";
reset_rc_file(fishrc_path, shell, mamba_exe);
reset_rc_file(context, fishrc_path, shell, mamba_exe);
}
else if (shell == "cmd.exe")
{
#ifndef _WIN32
throw std::runtime_error("CMD.EXE can only be deinitialized on Windows.");
#else
deinit_cmd_exe_registry(L"Software\\Microsoft\\Command Processor", conda_prefix);
deinit_cmd_exe_registry(
L"Software\\Microsoft\\Command Processor",
conda_prefix,
context.graphics_params
);
#endif
}
else if (shell == "powershell")
@ -1135,7 +1142,7 @@ namespace mamba
if (!profile_path.empty())
{
Console::stream() << "Deinit " << exe << " profile at '" << profile_path << "'";
deinit_powershell(profile_path, conda_prefix);
deinit_powershell(context, profile_path, conda_prefix);
}
}
}
@ -1144,7 +1151,7 @@ namespace mamba
throw std::runtime_error("Support for other shells not yet implemented.");
}
deinit_root_prefix(shell, conda_prefix);
deinit_root_prefix(context, shell, conda_prefix);
}
fs::u8path config_path_for_shell(const std::string& shell)
@ -1197,7 +1204,7 @@ namespace mamba
#ifdef _WIN32
// cmd.exe
std::wstring reg = get_autorun_registry_key(L"Software\\Microsoft\\Command Processor");
if (std::regex_match(reg, MAMBA_CMDEXE_HOOK_REGEX) != std::wstring::npos)
if (std::regex_match(reg, MAMBA_CMDEXE_HOOK_REGEX))
{
result.push_back("cmd.exe");
}

View File

@ -137,7 +137,10 @@ namespace mamba
MainExecutor* expected = nullptr;
if (!main_executor.compare_exchange_strong(expected, this))
{
throw MainExecutorError("attempted to create multiple main executors");
throw MainExecutorError(
"attempted to create multiple main executors",
mamba_error_code::incorrect_usage
);
}
}
@ -147,49 +150,36 @@ namespace mamba
main_executor = nullptr;
}
//---- Singletons from this library ------------------------------------------------------------
namespace singletons
{
template <typename T>
struct Singleton : public T
{
using T::T;
};
template <typename T, typename D>
T& init_once(std::unique_ptr<T, D>& ptr)
{
static std::once_flag init_flag;
std::call_once(init_flag, [&] { ptr = std::make_unique<T>(); });
// In case the object was already created and destroyed, we make sure it is clearly
// visible (no undefined behavior).
if (!ptr)
{
throw mamba::mamba_error(
fmt::format(
"attempt to use {} singleton instance after destruction",
typeid(T).name()
),
mamba_error_code::internal_failure
);
}
return *ptr;
}
static std::unique_ptr<Singleton<Context>> context;
static std::unique_ptr<Singleton<Console>> console;
}
Context& Context::instance()
{
return singletons::init_once(singletons::context);
}
static std::atomic<Console*> main_console{ nullptr };
Console& Console::instance()
{
return singletons::init_once(singletons::console);
if (!main_console) // NOTE: this is a temptative check, not a perfect one, it is possible
// `main_console` becomes null after the if scope and before returning.
// A perfect check would involve locking a mutex, we want to avoid that
// here.
{
throw mamba_error(
"attempted to access the console but it have not been created yet",
mamba_error_code::incorrect_usage
);
}
return *main_console;
}
void Console::set_singleton(Console& console)
{
Console* expected = nullptr;
if (!main_console.compare_exchange_strong(expected, &console))
{
throw mamba_error("attempted to create multiple consoles", mamba_error_code::incorrect_usage);
}
}
void Console::clear_singleton()
{
main_console = nullptr;
}
}

View File

@ -433,7 +433,7 @@ namespace mamba
std::ostream& MSolver::explain_problems(std::ostream& out) const
{
const auto& ctx = Context::instance();
const auto& ctx = m_pool.context();
out << "Could not solve for environment specs\n";
const auto pbs = problems_graph();
const auto pbs_simplified = simplify_conflicts(pbs);

View File

@ -59,7 +59,7 @@ namespace mamba
}
}
for (const auto& c : Context::instance().repodata_has_zst)
for (const auto& c : channel_context.context().repodata_has_zst)
{
if (channel_context.make_channel(c) == *channel)
{
@ -337,7 +337,9 @@ namespace mamba
, m_name(util::join_url(channel.canonical_name(), platform))
, m_is_noarch(platform == "noarch")
, p_channel(&channel)
, p_context(&channel_context.context())
{
assert(p_context);
m_json_fn = cache_fn_url(m_repodata_url);
m_solv_fn = m_json_fn.substr(0, m_json_fn.size() - 4) + "solv";
load(caches, channel_context);
@ -363,6 +365,7 @@ namespace mamba
, m_metadata(std::move(rhs.m_metadata))
, m_temp_file(std::move(rhs.m_temp_file))
, p_channel(rhs.p_channel)
, p_context(rhs.p_context)
{
if (m_target != nullptr)
{
@ -396,6 +399,7 @@ namespace mamba
swap(m_temp_file, rhs.m_temp_file);
swap(m_check_targets, rhs.m_check_targets);
swap(p_channel, rhs.p_channel);
swap(p_context, rhs.p_context);
if (m_target != nullptr)
{
@ -489,6 +493,9 @@ namespace mamba
bool MSubdirData::load(MultiPackageCache& caches, ChannelContext& channel_context)
{
assert(&channel_context.context() == p_context);
assert(p_context != nullptr);
auto now = fs::file_time_type::clock::now();
m_valid_cache_path = "";
@ -499,6 +506,8 @@ namespace mamba
const auto cache_paths = without_duplicates(caches.paths());
auto& context = *p_context;
for (const auto& cache_path : cache_paths)
{
auto json_file = cache_path / "cache" / m_json_fn;
@ -525,11 +534,11 @@ namespace mamba
{
m_metadata = std::move(metadata_temp.value());
int max_age = 0;
if (Context::instance().local_repodata_ttl > 1)
if (context.local_repodata_ttl > 1)
{
max_age = static_cast<int>(Context::instance().local_repodata_ttl);
max_age = static_cast<int>(context.local_repodata_ttl);
}
else if (Context::instance().local_repodata_ttl == 1)
else if (context.local_repodata_ttl == 1)
{
// TODO error handling if _cache_control key does not exist!
max_age = static_cast<int>(get_cache_control_max_age(m_metadata.cache_control)
@ -538,8 +547,7 @@ namespace mamba
auto cache_age_seconds = std::chrono::duration_cast<std::chrono::seconds>(cache_age)
.count();
if ((max_age > cache_age_seconds || Context::instance().offline
|| Context::instance().use_index_cache))
if ((max_age > cache_age_seconds || context.offline || context.use_index_cache))
{
// valid json cache found
if (!m_loaded)
@ -597,10 +605,9 @@ namespace mamba
<< m_expired_cache_path.string() << "'";
}
auto& ctx = Context::instance();
if (!ctx.offline || forbid_cache())
if (!context.offline || forbid_cache())
{
if (ctx.repodata_use_zst)
if (context.repodata_use_zst)
{
bool has_value = m_metadata.has_zst.has_value();
bool is_expired = m_metadata.has_zst.has_value()
@ -609,6 +616,7 @@ namespace mamba
if (!has_zst && (is_expired || !has_value))
{
m_check_targets.push_back(std::make_unique<DownloadTarget>(
context,
m_name + " (check zst)",
m_repodata_url + ".zst",
""
@ -616,8 +624,8 @@ namespace mamba
m_check_targets.back()->set_head_only(true);
m_check_targets.back()->set_finalize_callback(&MSubdirData::finalize_check, this);
m_check_targets.back()->set_ignore_failure(true);
if (!(ctx.graphics_params.no_progress_bars || ctx.output_params.quiet
|| ctx.output_params.json))
if (!(context.graphics_params.no_progress_bars
|| context.output_params.quiet || context.output_params.json))
{
m_progress_bar_check = Console::instance().add_progress_bar(
m_name + " (check zst)"
@ -854,13 +862,16 @@ namespace mamba
void MSubdirData::create_target()
{
auto& ctx = Context::instance();
assert(p_context != nullptr);
auto& ctx = *p_context;
fs::u8path writable_cache_dir = create_cache_dir(m_writable_pkgs_dir);
auto lock = LockFile(writable_cache_dir);
m_temp_file = std::make_unique<TemporaryFile>("mambaf", "", writable_cache_dir);
bool use_zst = m_metadata.has_zst.has_value() && m_metadata.has_zst.value().value;
m_target = std::make_unique<DownloadTarget>(
ctx,
m_name,
m_repodata_url + (use_zst ? ".zst" : ""),
m_temp_file->path().string()
@ -910,12 +921,13 @@ namespace mamba
expected_t<MRepo> MSubdirData::create_repo(MPool& pool)
{
assert(&pool.context() == p_context);
using return_type = expected_t<MRepo>;
RepoMetadata meta{
/* .url= */ util::rsplit(m_metadata.url, "/", 1).front(),
/* .etag= */ m_metadata.etag,
/* .mod= */ m_metadata.mod,
/* .pip_added= */ Context::instance().add_pip_as_python_dependency,
/* .pip_added= */ p_context->add_pip_as_python_dependency,
};
auto cache = cache_path();

View File

@ -277,20 +277,24 @@ namespace mamba
}
}
MTransaction::MTransaction(MPool& pool, MultiPackageCache& caches)
: m_pool(pool)
, m_multi_cache(caches)
, m_history_entry(History::UserRequest::prefilled(m_pool.context()))
{
}
MTransaction::MTransaction(
MPool& pool,
const std::vector<MatchSpec>& specs_to_remove,
const std::vector<MatchSpec>& specs_to_install,
MultiPackageCache& caches
)
: m_pool(pool)
, m_multi_cache(caches)
: MTransaction(pool, caches)
{
MRepo mrepo = MRepo(
m_pool,
"__explicit_specs__",
make_pkg_info_from_explicit_match_specs(specs_to_install)
);
MRepo mrepo{ m_pool,
"__explicit_specs__",
make_pkg_info_from_explicit_match_specs(specs_to_install) };
m_pool.create_whatprovides();
@ -354,26 +358,27 @@ namespace mamba
m_history_entry.update.push_back(s.str());
}
const auto& context = m_pool.context();
// if no action required, don't even start logging them
if (!empty())
{
Console::instance().json_down("actions");
Console::instance().json_write(
{ { "PREFIX", Context::instance().prefix_params.target_prefix.string() } }
);
Console::instance().json_write({ { "PREFIX",
context.prefix_params.target_prefix.string() } });
}
m_transaction_context = TransactionContext(
Context::instance().prefix_params.target_prefix,
Context::instance().prefix_params.relocate_prefix,
context,
context.prefix_params.target_prefix,
context.prefix_params.relocate_prefix,
find_python_version(m_solution, m_pool.pool()),
specs_to_install
);
}
MTransaction::MTransaction(MPool& p_pool, MSolver& solver, MultiPackageCache& caches)
: m_pool(p_pool)
, m_multi_cache(caches)
: MTransaction(p_pool, caches)
{
if (!solver.is_solved())
{
@ -427,9 +432,11 @@ namespace mamba
);
}
const auto& context = m_pool.context();
m_transaction_context = TransactionContext(
Context::instance().prefix_params.target_prefix,
Context::instance().prefix_params.relocate_prefix,
context,
context.prefix_params.target_prefix,
context.prefix_params.relocate_prefix,
find_python_version(m_solution, m_pool.pool()),
solver.install_specs()
);
@ -522,8 +529,9 @@ namespace mamba
}
m_transaction_context = TransactionContext(
Context::instance().prefix_params.target_prefix,
Context::instance().prefix_params.relocate_prefix,
context,
context.prefix_params.target_prefix,
context.prefix_params.relocate_prefix,
find_python_version(m_solution, m_pool.pool()),
solver.install_specs()
);
@ -533,9 +541,8 @@ namespace mamba
if (!empty())
{
Console::instance().json_down("actions");
Console::instance().json_write(
{ { "PREFIX", Context::instance().prefix_params.target_prefix.string() } }
);
Console::instance().json_write({ { "PREFIX",
context.prefix_params.target_prefix.string() } });
}
}
@ -544,8 +551,7 @@ namespace mamba
const std::vector<PackageInfo>& packages,
MultiPackageCache& caches
)
: m_pool(pool)
, m_multi_cache(caches)
: MTransaction(pool, caches)
{
LOG_INFO << "MTransaction::MTransaction - packages already resolved (lockfile)";
MRepo mrepo = MRepo(m_pool, "__explicit_specs__", packages);
@ -570,9 +576,11 @@ namespace mamba
));
}
const auto& context = m_pool.context();
m_transaction_context = TransactionContext(
Context::instance().prefix_params.target_prefix,
Context::instance().prefix_params.relocate_prefix,
context,
context.prefix_params.target_prefix,
context.prefix_params.relocate_prefix,
find_python_version(m_solution, m_pool.pool()),
specs_to_install
);
@ -597,7 +605,7 @@ namespace mamba
m_link_stack.push(link);
}
void rollback()
void rollback(const Context&)
{
while (!m_link_stack.empty())
{
@ -620,7 +628,7 @@ namespace mamba
bool MTransaction::execute(PrefixData& prefix)
{
auto& ctx = Context::instance();
auto& ctx = m_pool.context();
// JSON output
// back to the top level if any action was required
@ -714,7 +722,7 @@ namespace mamba
if (is_sig_interrupted())
{
Console::stream() << "Transaction interrupted, rollbacking";
rollback.rollback();
rollback.rollback(ctx);
return false;
}
LOG_INFO << "Waiting for pyc compilation to finish";
@ -724,7 +732,7 @@ namespace mamba
const auto executable = ctx.command_params.is_micromamba ? "micromamba" : "mamba";
// Get the name of the environment
const auto environment = env_name(ctx.prefix_params.target_prefix);
const auto environment = env_name(ctx);
Console::stream() << "\nTransaction finished\n\n"
"To activate this environment, use:\n\n"
@ -818,16 +826,17 @@ namespace mamba
bool MTransaction::fetch_extract_packages()
{
std::vector<std::unique_ptr<PackageDownloadExtractTarget>> targets;
MultiDownloadTarget multi_dl;
MultiDownloadTarget multi_dl{ m_pool.context() };
auto& pbar_manager = Console::instance().init_progress_bar_manager(ProgressBarMode::aggregated
);
auto& aggregated_pbar_manager = dynamic_cast<AggregatedBarManager&>(pbar_manager);
auto& ctx = Context::instance();
auto& channel_context = m_pool.channel_context();
auto& ctx = channel_context.context();
DownloadExtractSemaphore::set_max(ctx.threads_params.extract_threads);
if (ctx.experimental && ctx.verify_artifacts)
if (ctx.experimental && ctx.validation_params.verify_artifacts)
{
LOG_INFO << "Content trust is enabled, package(s) signatures will be verified";
}
@ -836,11 +845,10 @@ namespace mamba
m_solution.actions,
[&](const auto& pkg)
{
if (ctx.experimental && ctx.verify_artifacts)
if (ctx.experimental && ctx.validation_params.verify_artifacts)
{
const auto& repo_checker = m_pool.channel_context()
.make_channel(pkg.channel)
.repo_checker(m_multi_cache);
const auto& repo_checker = channel_context.make_channel(pkg.channel)
.repo_checker(ctx, m_multi_cache);
repo_checker.verify_package(
pkg.json_signable(),
nlohmann::json::parse(pkg.signatures)
@ -852,7 +860,7 @@ namespace mamba
targets.emplace_back(
std::make_unique<PackageDownloadExtractTarget>(pkg, m_pool.channel_context())
);
DownloadTarget* download_target = targets.back()->target(m_multi_cache);
DownloadTarget* download_target = targets.back()->target(ctx, m_multi_cache);
if (download_target != nullptr)
{
multi_dl.add(download_target);
@ -860,13 +868,13 @@ namespace mamba
}
);
if (ctx.experimental && ctx.verify_artifacts)
if (ctx.experimental && ctx.validation_params.verify_artifacts)
{
auto out = Console::stream();
fmt::print(
out,
"Content trust verifications successful, {} ",
fmt::styled("package(s) are trusted", Context::instance().graphics_params.palette.safe)
fmt::styled("package(s) are trusted", ctx.graphics_params.palette.safe)
);
LOG_INFO << "All package(s) are trusted";
}
@ -1027,7 +1035,7 @@ namespace mamba
bool MTransaction::prompt()
{
print();
if (Context::instance().dry_run || empty())
if (m_pool.context().dry_run || empty())
{
return true;
}
@ -1037,7 +1045,7 @@ namespace mamba
void MTransaction::print()
{
const auto& ctx = Context::instance();
const auto& ctx = m_pool.context();
if (ctx.output_params.json)
{
@ -1328,11 +1336,12 @@ namespace mamba
std::vector<PackageInfo> conda_packages = {};
std::vector<PackageInfo> pip_packages = {};
const auto& context = pool.context();
for (const auto& category : categories)
{
std::vector<PackageInfo> selected_packages = lockfile_data.get_packages_for(
category,
Context::instance().platform,
context.platform,
"conda"
);
std::copy(
@ -1345,11 +1354,10 @@ namespace mamba
{
LOG_WARNING << "Selected packages for category '" << category << "' are empty. "
<< "The lockfile might not be resolved for your platform ("
<< Context::instance().platform << ").";
<< context.platform << ").";
}
selected_packages = lockfile_data
.get_packages_for(category, Context::instance().platform, "pip");
selected_packages = lockfile_data.get_packages_for(category, context.platform, "pip");
std::copy(
selected_packages.begin(),
selected_packages.end(),

View File

@ -10,6 +10,7 @@
#include <reproc++/drain.hpp>
#include "mamba/core/environment.hpp"
#include "mamba/core/error_handling.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/transaction_context.hpp"
#include "mamba/util/string.hpp"
@ -89,12 +90,16 @@ namespace mamba
}
}
TransactionContext::TransactionContext()
TransactionContext::TransactionContext() = default;
TransactionContext::TransactionContext(const Context& context)
: m_context(&context)
{
compile_pyc = Context::instance().compile_pyc;
compile_pyc = this->context().compile_pyc;
}
TransactionContext::TransactionContext(
const Context& context,
const fs::u8path& ltarget_prefix,
const std::pair<std::string, std::string>& py_versions,
const std::vector<MatchSpec>& lrequested_specs
@ -105,8 +110,9 @@ namespace mamba
, python_version(py_versions.first)
, old_python_version(py_versions.second)
, requested_specs(lrequested_specs)
, m_context(&context)
{
auto& ctx = Context::instance();
const auto& ctx = this->context();
compile_pyc = ctx.compile_pyc;
allow_softlinks = ctx.allow_softlinks;
always_copy = ctx.always_copy;
@ -135,12 +141,13 @@ namespace mamba
}
TransactionContext::TransactionContext(
const Context& context,
const fs::u8path& ltarget_prefix,
const fs::u8path& lrelocate_prefix,
const std::pair<std::string, std::string>& py_versions,
const std::vector<MatchSpec>& lrequested_specs
)
: TransactionContext(ltarget_prefix, py_versions, lrequested_specs)
: TransactionContext(context, ltarget_prefix, py_versions, lrequested_specs)
{
if (lrelocate_prefix.empty())
{
@ -171,6 +178,8 @@ namespace mamba
python_path = other.python_path;
site_packages_path = other.site_packages_path;
relink_noarch = other.relink_noarch;
m_context = other.m_context;
}
return *this;
}
@ -180,8 +189,21 @@ 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;
@ -225,7 +247,7 @@ namespace mamba
options.env.behavior = reproc::env::empty;
#endif
std::map<std::string, std::string> envmap;
auto& ctx = Context::instance();
auto& ctx = context();
envmap["MAMBA_EXTRACT_THREADS"] = std::to_string(ctx.threads_params.extract_threads);
auto qemu_ld_prefix = env::get("QEMU_LD_PREFIX");
if (qemu_ld_prefix)
@ -246,7 +268,7 @@ namespace mamba
const std::string cwd = target_prefix.string();
options.working_directory = cwd.c_str();
auto [wrapped_command, script_file] = prepare_wrapped_call(target_prefix, command);
auto [wrapped_command, script_file] = prepare_wrapped_call(ctx, target_prefix, command);
m_pyc_script_file = std::move(script_file);
LOG_INFO << "Running wrapped python compilation command " << util::join(" ", command);
@ -265,6 +287,8 @@ namespace mamba
bool TransactionContext::try_pyc_compilation(const std::vector<fs::u8path>& py_files)
{
throw_if_not_ready();
static std::mutex pyc_compilation_mutex;
std::lock_guard<std::mutex> lock(pyc_compilation_mutex);
@ -300,6 +324,8 @@ namespace mamba
void TransactionContext::wait_for_pyc_compilation()
{
throw_if_not_ready();
if (m_pyc_process)
{
std::error_code ec;

View File

@ -37,6 +37,7 @@ extern "C"
#include <memory>
#include <mutex>
#include <optional>
#include <regex>
#include <unordered_map>
#include <openssl/evp.h>
@ -55,9 +56,35 @@ extern "C"
#include "mamba/util/compare.hpp"
#include "mamba/util/string.hpp"
#include "mamba/util/url.hpp"
#include "mamba/util/url_manip.hpp"
namespace mamba
{
namespace
{
std::atomic<bool> persist_temporary_files{ false };
std::atomic<bool> persist_temporary_directories{ false };
}
bool must_persist_temporary_files()
{
return persist_temporary_files;
}
bool set_persist_temporary_files(bool new_value)
{
return persist_temporary_files.exchange(new_value);
}
bool must_persist_temporary_directories()
{
return persist_temporary_directories;
}
bool set_persist_temporary_directories(bool new_value)
{
return persist_temporary_directories.exchange(new_value);
}
bool is_package_file(std::string_view fn)
{
return util::ends_with(fn, ".tar.bz2") || util::ends_with(fn, ".conda");
@ -147,7 +174,7 @@ namespace mamba
TemporaryDirectory::~TemporaryDirectory()
{
if (!Context::instance().keep_temp_directories)
if (!must_persist_temporary_directories())
{
fs::remove_all(m_path);
}
@ -206,7 +233,7 @@ namespace mamba
TemporaryFile::~TemporaryFile()
{
if (!Context::instance().keep_temp_files)
if (!must_persist_temporary_files())
{
fs::remove(m_path);
}
@ -504,7 +531,7 @@ namespace mamba
return deleted_files;
}
std::size_t remove_or_rename(const fs::u8path& path)
std::size_t remove_or_rename(const Context& context, const fs::u8path& path)
{
std::error_code ec;
std::size_t result = 0;
@ -559,16 +586,13 @@ namespace mamba
{
// The conda-meta directory is locked by transaction execute
auto trash_index = open_ofstream(
Context::instance().prefix_params.target_prefix / "conda-meta"
/ "mamba_trash.txt",
context.prefix_params.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::instance().prefix_params.target_prefix)
.string()
<< "\n";
trash_index << fs::relative(trash_file, context.prefix_params.target_prefix).string()
<< "\n";
return 1;
}
@ -975,6 +999,15 @@ namespace mamba
return m_is_file_locking_allowed.exchange(allow);
}
std::chrono::seconds default_file_locking_timeout() const
{
return m_default_lock_timeout;
}
std::chrono::seconds set_file_locking_timeout(const std::chrono::seconds& new_timeout)
{
return m_default_lock_timeout.exchange(new_timeout);
}
tl::expected<std::shared_ptr<LockFileOwner>, mamba_error>
acquire_lock(const fs::u8path& file_path, const std::chrono::seconds timeout)
{
@ -1045,6 +1078,7 @@ namespace mamba
private:
std::atomic_bool m_is_file_locking_allowed{ true };
std::atomic<std::chrono::seconds> m_default_lock_timeout{ std::chrono::seconds::zero() };
// TODO: replace by something like boost::multiindex or equivalent to avoid having to
// handle 2 hashmaps
@ -1080,6 +1114,15 @@ namespace mamba
return files_locked_by_this_process.allow_file_locking(allow);
}
std::chrono::seconds default_file_locking_timeout()
{
return files_locked_by_this_process.default_file_locking_timeout();
}
std::chrono::seconds set_file_locking_timeout(const std::chrono::seconds& new_timeout)
{
return files_locked_by_this_process.set_file_locking_timeout(new_timeout);
}
bool LockFileOwner::lock_non_blocking()
{
if (files_locked_by_this_process.is_locked(m_lockfile_path))
@ -1100,7 +1143,7 @@ namespace mamba
}
LockFile::LockFile(const fs::u8path& path)
: LockFile(path, std::chrono::seconds(Context::instance().lock_timeout))
: LockFile(path, files_locked_by_this_process.default_file_locking_timeout())
{
}
@ -1295,12 +1338,21 @@ namespace mamba
}
WrappedCallOptions WrappedCallOptions::from_context(const Context& context)
{
return {
/* .is_micromamba = */ context.command_params.is_micromamba,
/* .dev_mode = */ context.dev,
/* .debug_wrapper_scripts = */ false,
};
}
std::unique_ptr<TemporaryFile> wrap_call(
const Context& context [[maybe_unused]],
const fs::u8path& root_prefix,
const fs::u8path& prefix,
bool dev_mode,
bool debug_wrapper_scripts,
const std::vector<std::string>& arguments
const std::vector<std::string>& arguments,
const WrappedCallOptions options
)
{
// todo add abspath here
@ -1313,10 +1365,9 @@ namespace mamba
// TODO
std::string CONDA_PACKAGE_ROOT = "";
std::string bat_name = Context::instance().command_params.is_micromamba ? "micromamba.bat"
: "conda.bat";
std::string bat_name = options.is_micromamba ? "micromamba.bat" : "conda.bat";
if (dev_mode)
if (options.dev_mode)
{
conda_bat = (fs::u8path(CONDA_PACKAGE_ROOT) / "shell" / "condabin" / "conda.bat").string();
}
@ -1325,17 +1376,17 @@ namespace mamba
conda_bat = env::get("CONDA_BAT")
.value_or((fs::absolute(root_prefix) / "condabin" / bat_name).string());
}
if (!fs::exists(conda_bat) && Context::instance().command_params.is_micromamba)
if (!fs::exists(conda_bat) && options.is_micromamba)
{
// this adds in the needed .bat files for activation
init_root_prefix_cmdexe(Context::instance().prefix_params.root_prefix);
init_root_prefix_cmdexe(context, root_prefix);
}
auto tf = std::make_unique<TemporaryFile>("mamba_bat_", ".bat");
std::ofstream out = open_ofstream(tf->path());
std::string silencer = debug_wrapper_scripts ? "" : "@";
std::string silencer = options.debug_wrapper_scripts ? "" : "@";
out << silencer << "ECHO OFF\n";
out << silencer << "SET PYTHONIOENCODING=utf-8\n";
@ -1345,7 +1396,7 @@ namespace mamba
"do set \"_CONDA_OLD_CHCP=%%B\"\n";
out << silencer << "chcp 65001 > NUL\n";
if (dev_mode)
if (options.dev_mode)
{
// from conda.core.initialize import CONDA_PACKAGE_ROOT
out << silencer << "SET CONDA_DEV=1\n";
@ -1360,7 +1411,7 @@ namespace mamba
out << silencer << "SET _CE_CONDA=conda\n";
}
if (debug_wrapper_scripts)
if (options.debug_wrapper_scripts)
{
out << "echo *** environment before *** 1>&2\n";
out << "SET 1>&2\n";
@ -1369,7 +1420,7 @@ namespace mamba
out << silencer << "CALL \"" << conda_bat << "\" activate " << prefix << "\n";
out << silencer << "IF %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%\n";
if (debug_wrapper_scripts)
if (options.debug_wrapper_scripts)
{
out << "echo *** environment after *** 1>&2\n";
out << "SET 1>&2\n";
@ -1381,12 +1432,12 @@ namespace mamba
std::string shebang, dev_arg;
if (!Context::instance().command_params.is_micromamba)
if (!options.is_micromamba)
{
// 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 (dev_mode)
if (options.dev_mode)
{
shebang += std::string(root_prefix / "bin" / "python");
shebang += " -m conda";
@ -1405,7 +1456,7 @@ namespace mamba
}
}
if (dev_mode)
if (options.dev_mode)
{
// out << ">&2 export PYTHONPATH=" << CONDA_PACKAGE_ROOT << "\n";
}
@ -1417,9 +1468,9 @@ namespace mamba
// Micromamba hook
out << "export MAMBA_EXE=" << std::quoted(get_self_exe_path().string(), '\'') << "\n";
hook_quoted << "$MAMBA_EXE 'shell' 'hook' '-s' 'bash' '-r' "
<< std::quoted(Context::instance().prefix_params.root_prefix.string(), '\'');
<< std::quoted(root_prefix.string(), '\'');
}
if (debug_wrapper_scripts)
if (options.debug_wrapper_scripts)
{
out << "set -x\n";
out << ">&2 echo \"*** environment before ***\"\n"
@ -1428,7 +1479,7 @@ namespace mamba
}
out << "eval \"$(" << hook_quoted.str() << ")\"\n";
if (!Context::instance().command_params.is_micromamba)
if (!options.is_micromamba)
{
out << "conda activate " << dev_arg << " " << std::quoted(prefix.string()) << "\n";
}
@ -1438,7 +1489,7 @@ namespace mamba
}
if (debug_wrapper_scripts)
if (options.debug_wrapper_scripts)
{
out << ">&2 echo \"*** environment after ***\"\n"
<< ">&2 env\n";
@ -1449,8 +1500,11 @@ namespace mamba
return tf;
}
std::tuple<std::vector<std::string>, std::unique_ptr<TemporaryFile>>
prepare_wrapped_call(const fs::u8path& prefix, const std::vector<std::string>& cmd)
PreparedWrappedCall prepare_wrapped_call(
const Context& context,
const fs::u8path& prefix,
const std::vector<std::string>& cmd
)
{
std::vector<std::string> command_args;
std::unique_ptr<TemporaryFile> script_file;
@ -1467,11 +1521,11 @@ namespace mamba
}
script_file = wrap_call(
Context::instance().prefix_params.root_prefix,
context,
context.prefix_params.root_prefix,
prefix,
Context::instance().dev,
false,
cmd
cmd,
WrappedCallOptions::from_context(context)
);
command_args = { comspec.value(), "/D", "/C", script_file->path().string() };
@ -1491,16 +1545,16 @@ namespace mamba
}
script_file = wrap_call(
Context::instance().prefix_params.root_prefix,
context,
context.prefix_params.root_prefix,
prefix,
Context::instance().dev,
false,
cmd
cmd,
WrappedCallOptions::from_context(context)
);
command_args.push_back(shell_path.string());
command_args.push_back(script_file->path().string());
}
return std::make_tuple(command_args, std::move(script_file));
return { command_args, std::move(script_file) };
}
bool is_yaml_file_name(std::string_view filename)
@ -1584,21 +1638,16 @@ namespace mamba
return std::nullopt;
}
std::optional<std::string> proxy_match(const std::string& url)
{
return proxy_match(url, Context::instance().remote_fetch_params.proxy_servers);
}
std::string hide_secrets(std::string_view str)
{
std::string copy(str);
if (util::contains(str, "/t/"))
{
copy = std::regex_replace(copy, Context::instance().token_regex, "/t/*****");
copy = std::regex_replace(copy, util::conda_urls::token_regex, "/t/*****");
}
copy = std::regex_replace(copy, Context::instance().http_basicauth_regex, "$1$2:*****@");
copy = std::regex_replace(copy, util::conda_urls::http_basicauth_regex, "$1$2:*****@");
return copy;
}

View File

@ -134,7 +134,7 @@ namespace mamba
return true;
}
bool enable_long_paths_support(bool force)
bool enable_long_paths_support(bool force, Palette palette)
{
// Needs to be set system-wide & can only be run as admin ...
std::string win_ver = windows_version();
@ -166,10 +166,7 @@ namespace mamba
fmt::print(
out,
"{}",
fmt::styled(
"Windows long-path support already enabled.",
Context::instance().graphics_params.palette.ignored
)
fmt::styled("Windows long-path support already enabled.", palette.ignored)
);
return true;
}
@ -205,14 +202,7 @@ namespace mamba
if (prev_value == 1)
{
auto out = Console::stream();
fmt::print(
out,
"{}",
fmt::styled(
"Windows long-path support enabled.",
Context::instance().graphics_params.palette.success
)
);
fmt::print(out, "{}", fmt::styled("Windows long-path support enabled.", palette.success));
return true;
}
LOG_WARNING << "Changing registry value did not succeed.";

View File

@ -13,6 +13,7 @@
#include <openssl/evp.h>
#include "mamba/core/context.hpp"
#include "mamba/core/fetch.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/validate.hpp"
@ -1213,6 +1214,7 @@ namespace mamba::validation
}
std::unique_ptr<RepoIndexChecker> RootImpl::build_index_checker(
Context&,
const TimeRef& /*time_reference*/,
const std::string& /*url*/,
const fs::u8path& /*cache_path*/
@ -1431,6 +1433,7 @@ namespace mamba::validation
}
std::unique_ptr<RepoIndexChecker> RootImpl::build_index_checker(
Context& context,
const TimeRef& time_reference,
const std::string& base_url,
const fs::u8path& cache_path
@ -1444,6 +1447,7 @@ namespace mamba::validation
const auto url = mamba::util::URL::parse(base_url + "/key_mgr.json");
auto dl_target = std::make_unique<mamba::DownloadTarget>(
context,
"key_mgr.json",
url.str(),
tmp_metadata_path.string()
@ -1475,7 +1479,7 @@ namespace mamba::validation
fs::copy(tmp_metadata_path, metadata_path);
}
return key_mgr.build_index_checker(time_reference, base_url, cache_path);
return key_mgr.build_index_checker(context, time_reference, base_url, cache_path);
}
}
@ -1483,7 +1487,7 @@ namespace mamba::validation
if (fs::exists(metadata_path))
{
KeyMgrRole key_mgr = create_key_mgr(metadata_path);
return key_mgr.build_index_checker(time_reference, base_url, cache_path);
return key_mgr.build_index_checker(context, time_reference, base_url, cache_path);
}
LOG_ERROR << "Error while fetching 'key_mgr' metadata";
@ -1594,6 +1598,7 @@ namespace mamba::validation
}
std::unique_ptr<RepoIndexChecker> KeyMgrRole::build_index_checker(
Context& context,
const TimeRef& time_reference,
const std::string& base_url,
const fs::u8path& cache_path
@ -1607,6 +1612,7 @@ namespace mamba::validation
const auto url = mamba::util::URL::parse(base_url + "/pkg_mgr.json");
auto dl_target = std::make_unique<mamba::DownloadTarget>(
context,
"pkg_mgr.json",
url.str(),
tmp_metadata_path.string()
@ -2004,13 +2010,17 @@ namespace mamba::validation
}
RepoChecker::RepoChecker(
Context& context,
const std::string& base_url,
const fs::u8path& ref_path,
const fs::u8path& cache_path
)
: m_base_url(base_url)
, m_ref_path(ref_path)
, m_cache_path(cache_path){};
, m_cache_path(cache_path)
, m_context(context)
{
}
const fs::u8path& RepoChecker::cache_path()
{
@ -2028,7 +2038,12 @@ namespace mamba::validation
const TimeRef time_reference;
auto root = get_root_role(time_reference);
p_index_checker = root->build_index_checker(time_reference, m_base_url, cache_path());
p_index_checker = root->build_index_checker(
m_context,
time_reference,
m_base_url,
cache_path()
);
LOG_INFO << "Index checker successfully generated for '" << m_base_url << "'";
}
@ -2150,6 +2165,7 @@ namespace mamba::validation
tmp_file_path = tmp_dir_path / f;
auto dl_target = std::make_unique<mamba::DownloadTarget>(
m_context,
f.string(),
url,
tmp_file_path.string()

View File

@ -147,6 +147,7 @@ namespace mamba
PackageInfo make_virtual_package(
const std::string& name,
const std::string& subdir,
const std::string& version,
const std::string& build_string
)
@ -156,19 +157,19 @@ namespace mamba
res.build_string = build_string.size() ? build_string : "0";
res.build_number = 0;
res.channel = "@";
res.subdir = Context::instance().platform;
res.subdir = subdir;
res.md5 = "12345678901234567890123456789012";
res.fn = name;
return res;
}
std::vector<PackageInfo> dist_packages()
std::vector<PackageInfo> dist_packages(const Context& context)
{
LOG_DEBUG << "Loading distribution virtual packages";
std::vector<PackageInfo> res;
auto platform = Context::instance().platform;
auto split_platform = util::split(platform, "-", 1);
const auto platform = context.platform;
const auto split_platform = util::split(platform, "-", 1);
if (split_platform.size() != 2)
{
@ -180,11 +181,11 @@ namespace mamba
if (os == "win")
{
res.push_back(make_virtual_package("__win"));
res.push_back(make_virtual_package("__win", platform));
}
if (os == "linux")
{
res.push_back(make_virtual_package("__unix"));
res.push_back(make_virtual_package("__unix", platform));
std::string linux_ver = linux_version();
if (linux_ver.empty())
@ -192,12 +193,12 @@ namespace mamba
LOG_WARNING << "linux version not found, defaulting to '0'";
linux_ver = "0";
}
res.push_back(make_virtual_package("__linux", linux_ver));
res.push_back(make_virtual_package("__linux", platform, linux_ver));
std::string libc_ver = detail::glibc_version();
if (!libc_ver.empty())
{
res.push_back(make_virtual_package("__glibc", libc_ver));
res.push_back(make_virtual_package("__glibc", platform, libc_ver));
}
else
{
@ -206,12 +207,12 @@ namespace mamba
}
if (os == "osx")
{
res.push_back(make_virtual_package("__unix"));
res.push_back(make_virtual_package("__unix", platform));
std::string osx_ver = macos_version();
if (!osx_ver.empty())
{
res.push_back(make_virtual_package("__osx", osx_ver));
res.push_back(make_virtual_package("__osx", platform, osx_ver));
}
else
{
@ -227,21 +228,21 @@ namespace mamba
{
arch = "x86";
}
res.push_back(make_virtual_package("__archspec", "1", arch));
res.push_back(make_virtual_package("__archspec", platform, "1", arch));
return res;
}
}
std::vector<PackageInfo> get_virtual_packages()
std::vector<PackageInfo> get_virtual_packages(const Context& context)
{
LOG_DEBUG << "Loading virtual packages";
auto res = detail::dist_packages();
auto res = detail::dist_packages(context);
auto cuda_ver = detail::cuda_version();
if (!cuda_ver.empty())
{
res.push_back(detail::make_virtual_package("__cuda", cuda_ver));
res.push_back(detail::make_virtual_package("__cuda", context.platform, cuda_ver));
}
return res;

View File

@ -15,10 +15,11 @@
#include <fmt/format.h>
#include <openssl/evp.h>
#include "mamba/core/context.hpp"
#include "mamba/core/mamba_fs.hpp"
#include "mamba/util/build.hpp"
#include "mamba/util/string.hpp"
#include "mamba/util/url.hpp"
#include "mamba/util/url_manip.hpp"
namespace mamba::util
{
@ -218,13 +219,13 @@ namespace mamba::util
void split_anaconda_token(const std::string& url, std::string& cleaned_url, std::string& token)
{
auto token_begin = std::sregex_iterator(url.begin(), url.end(), Context::instance().token_regex);
auto token_begin = std::sregex_iterator(url.begin(), url.end(), conda_urls::token_regex);
if (token_begin != std::sregex_iterator())
{
token = token_begin->str().substr(3u);
cleaned_url = std::regex_replace(
url,
Context::instance().token_regex,
conda_urls::token_regex,
"",
std::regex_constants::format_first_only
);

View File

@ -11,6 +11,7 @@ mamba_target_add_compile_warnings(testing_libmamba_lock WARNING_AS_ERROR ${MAMBA
set(LIBMAMBA_TEST_SRCS
include/mambatests.hpp
src/test_main.cpp
# C++ wrapping of libsolv
src/solv-cpp/pool_data.cpp
@ -76,7 +77,7 @@ mamba_target_add_compile_warnings(test_libmamba WARNING_AS_ERROR ${MAMBA_WARNING
target_include_directories(
test_libmamba
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src" "${CMAKE_SOURCE_DIR}/libmamba/src"
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/src" "${CMAKE_SOURCE_DIR}/libmamba/src"
)
find_package(doctest REQUIRED)

View File

@ -0,0 +1,41 @@
// Copyright (c) 2023, QuantStack and Mamba Contributors
//
// Distributed under the terms of the BSD 3-Clause License.
//
// The full license is in the file LICENSE, distributed with this software.
#ifndef LIBMAMBATESTS_HPP
#define LIBMAMBATESTS_HPP
#include "mamba/core/context.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/output.hpp"
namespace mambatests
{
struct Singletons
{
// mamba::MainExecutor main_executor; // FIXME: reactivate once the tests are not indirectly
// using this anymore
mamba::Context context{ { /* .enable_logging_and_signal_handling = */ true } };
mamba::Console console{ context };
};
inline Singletons& singletons() // FIXME: instead of this create the objects in main so that
// their lifetime doesnt go beyond main() scope.
{
static Singletons singletons;
return singletons;
}
// Provides the context object to use in all tests needing it.
// Note that this context is setup to handle logigng and signal handling.
inline mamba::Context& context()
{
return singletons().context;
}
}
#endif

View File

@ -29,6 +29,10 @@ is_locked(const fs::u8path& path)
int
main(int argc, char** argv)
{
mamba::Context context{ {
/* .enable_logging_and_signal_handling = */ true,
} };
CLI::App app{};
fs::u8path path;
std::size_t timeout = 1;
@ -39,7 +43,8 @@ main(int argc, char** argv)
lock_com->callback(
[&]()
{
mamba::Context::instance().lock_timeout = timeout;
context.lock_timeout = timeout;
mamba::set_file_locking_timeout(std::chrono::seconds{ timeout });
try
{
auto lock = mamba::LockFile(path);

View File

@ -1,6 +1,9 @@
#include <doctest/doctest.h>
#include "mamba/core/activation.hpp"
#include "mamba/core/context.hpp"
#include "mambatests.hpp"
namespace mamba
{
@ -8,7 +11,7 @@ namespace mamba
{
TEST_CASE("activation")
{
PosixActivator a;
PosixActivator activator{ mambatests::context() };
// std::cout << a.add_prefix_to_path("/home/wolfv/miniconda3", 0) <<
// std::endl; std::cout << a.activate("/home/wolfv/miniconda3/", false) <<
// std::endl;

View File

@ -6,6 +6,8 @@
#include "mamba/core/context.hpp"
#include "mamba/core/output.hpp"
#include "mambatests.hpp"
namespace mamba
{
@ -28,7 +30,7 @@ namespace mamba
{
// ChannelContext builds its custom channels with
// make_simple_channel
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const auto& ch = channel_context.get_channel_alias();
CHECK_EQ(ch.scheme(), "https");
CHECK_EQ(ch.location(), "conda.anaconda.org");
@ -60,10 +62,10 @@ namespace mamba
{
// ChannelContext builds its custom channels with
// make_simple_channel
auto& ctx = Context::instance();
auto& ctx = mambatests::context();
ctx.channel_alias = "https://mydomain.com/channels/";
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const auto& ch = channel_context.get_channel_alias();
CHECK_EQ(ch.scheme(), "https");
@ -94,13 +96,13 @@ namespace mamba
// Regression test for https://github.com/mamba-org/mamba/issues/1671
TEST_CASE("channel_alias_with_custom_default_channels")
{
auto& ctx = Context::instance();
auto& ctx = mambatests::context();
auto old_default_channels = ctx.default_channels;
ctx.channel_alias = "https://ali.as/";
ctx.default_channels = { "prefix" };
ctx.channels = { "prefix-and-more" };
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
auto base = std::string("https://ali.as/prefix-and-more/");
auto& chan = channel_context.make_channel(base);
std::vector<std::string> expected_urls = { base + platform, base + "noarch" };
@ -115,14 +117,14 @@ namespace mamba
{
// ChannelContext builds its custom channels with
// make_simple_channel
auto& ctx = Context::instance();
auto& ctx = mambatests::context();
ctx.channel_alias = "https://mydomain.com/channels/";
ctx.custom_channels = {
{ "test_channel", "file:///tmp" },
{ "some_channel", "https://conda.mydomain.xyz/" },
};
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
const auto& ch = channel_context.get_channel_alias();
CHECK_EQ(ch.scheme(), "https");
CHECK_EQ(ch.location(), "mydomain.com/channels");
@ -165,7 +167,7 @@ namespace mamba
{
// ChannelContext builds its custom channels with
// make_simple_channel
auto& ctx = Context::instance();
auto& ctx = mambatests::context();
ctx.custom_multichannels["xtest"] = std::vector<std::string>{
"https://mydomain.com/conda-forge",
"https://mydomain.com/bioconda",
@ -177,7 +179,7 @@ namespace mamba
"https://otherdomain.com/snakepit"
};
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
auto x = channel_context.get_channels({ "xtest" });
@ -209,7 +211,7 @@ namespace mamba
{
// ChannelContext builds its custom channels with
// make_simple_channel
auto& ctx = Context::instance();
auto& ctx = mambatests::context();
ctx.channel_alias = "https://condaforge.org/channels/";
@ -221,7 +223,7 @@ namespace mamba
"xyz"
};
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
auto x = channel_context.get_channels({ "everything" });
@ -258,8 +260,8 @@ namespace mamba
TEST_CASE("default_channels")
{
auto& ctx = Context::instance();
ChannelContext channel_context;
auto& ctx = mambatests::context();
ChannelContext channel_context{ ctx };
auto x = channel_context.get_channels({ "defaults" });
#if !defined(_WIN32)
@ -289,10 +291,10 @@ namespace mamba
TEST_CASE("custom_default_channels")
{
auto& ctx = Context::instance();
auto& ctx = mambatests::context();
ctx.default_channels = { "https://mamba.com/test/channel",
"https://mamba.com/stable/channel" };
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
auto x = channel_context.get_channels({ "defaults" });
const Channel* c1 = x[0];
@ -319,12 +321,12 @@ namespace mamba
TEST_CASE("custom_channels_with_labels")
{
auto& ctx = Context::instance();
auto& ctx = mambatests::context();
ctx.custom_channels = {
{ "test_channel", "https://server.com/private/channels" },
{ "random/test_channel", "https://server.com/random/channels" },
};
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
{
std::string value = "test_channel";
@ -384,7 +386,7 @@ namespace mamba
TEST_CASE("channel_name")
{
std::string value = "https://repo.mamba.pm/conda-forge";
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const Channel& c = channel_context.make_channel(value);
CHECK_EQ(c.scheme(), "https");
CHECK_EQ(c.location(), "repo.mamba.pm");
@ -396,7 +398,7 @@ namespace mamba
TEST_CASE("make_channel")
{
std::string value = "conda-forge";
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const Channel& c = channel_context.make_channel(value);
CHECK_EQ(c.scheme(), "https");
CHECK_EQ(c.location(), "conda.anaconda.org");
@ -469,7 +471,7 @@ namespace mamba
TEST_CASE("urls")
{
std::string value = "https://conda.anaconda.org/conda-forge[noarch,win-64,arbitrary]";
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const Channel& c = channel_context.make_channel(value);
CHECK_EQ(
c.urls(),
@ -488,13 +490,13 @@ namespace mamba
TEST_CASE("add_token")
{
auto& ctx = Context::instance();
auto& ctx = mambatests::context();
ctx.authentication_info()["conda.anaconda.org"] = AuthenticationInfo{
AuthenticationType::kCondaToken,
"my-12345-token"
};
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
const auto& chan = channel_context.make_channel("conda-forge[noarch]");
CHECK_EQ(chan.token(), "my-12345-token");
@ -511,7 +513,7 @@ namespace mamba
TEST_CASE("add_multiple_tokens")
{
auto& ctx = Context::instance();
auto& ctx = mambatests::context();
ctx.authentication_info()["conda.anaconda.org"] = AuthenticationInfo{
AuthenticationType::kCondaToken,
"base-token"
@ -521,7 +523,7 @@ namespace mamba
"channel-token"
};
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
const auto& chan = channel_context.make_channel("conda-forge[noarch]");
CHECK_EQ(chan.token(), "channel-token");
@ -529,7 +531,7 @@ namespace mamba
TEST_CASE("fix_win_file_path")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
if (platform == "win-64")
{
const Channel& c = channel_context.make_channel("C:\\test\\channel");
@ -552,7 +554,7 @@ namespace mamba
TEST_CASE("trailing_slash")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const Channel& c = channel_context.make_channel("http://localhost:8000/");
CHECK_EQ(c.platform_url("win-64", false), "http://localhost:8000/win-64");
CHECK_EQ(c.base_url(), "http://localhost:8000");
@ -585,7 +587,7 @@ namespace mamba
TEST_CASE("load_tokens")
{
// touch(env::home_directory() / ".continuum" / "anaconda")
// auto& ctx = Context::instance();
// auto& ctx = mambatests::context();
// ctx.channel_tokens["https://conda.anaconda.org"] = "my-12345-token";
// ChannelContext channel_context;

View File

@ -11,6 +11,7 @@
#include "mamba/core/util.hpp"
#include "mamba/util/string.hpp"
#include "mambatests.hpp"
#include "test_data.hpp"
namespace mamba
@ -95,9 +96,9 @@ namespace mamba
".yaml"
);
mamba::Context& ctx = mamba::Context::instance();
mamba::Configuration config;
mamba::Context& ctx = mambatests::context();
mamba::Configuration config{ ctx };
private:
@ -1013,18 +1014,18 @@ namespace mamba
config.at("safety_checks").value<VerificationLevel>(),
VerificationLevel::kEnabled
);
CHECK_EQ(ctx.safety_checks, VerificationLevel::kEnabled);
CHECK_EQ(ctx.validation_params.safety_checks, VerificationLevel::kEnabled);
load_test_config({ rc2, rc1, rc3 });
CHECK_EQ(config.at("safety_checks").value<VerificationLevel>(), VerificationLevel::kWarn);
CHECK_EQ(ctx.safety_checks, VerificationLevel::kWarn);
CHECK_EQ(ctx.validation_params.safety_checks, VerificationLevel::kWarn);
load_test_config({ rc3, rc1, rc3 });
CHECK_EQ(
config.at("safety_checks").value<VerificationLevel>(),
VerificationLevel::kDisabled
);
CHECK_EQ(ctx.safety_checks, VerificationLevel::kDisabled);
CHECK_EQ(ctx.validation_params.safety_checks, VerificationLevel::kDisabled);
env::set("MAMBA_SAFETY_CHECKS", "warn");
load_test_config(rc1);
@ -1038,7 +1039,7 @@ namespace mamba
"safety_checks: warn # 'MAMBA_SAFETY_CHECKS' > '" + src + "'"
);
CHECK_EQ(config.at("safety_checks").value<VerificationLevel>(), VerificationLevel::kWarn);
CHECK_EQ(ctx.safety_checks, VerificationLevel::kWarn);
CHECK_EQ(ctx.validation_params.safety_checks, VerificationLevel::kWarn);
config.at("safety_checks").set_yaml_value("disabled").compute();
CHECK_EQ(
@ -1049,7 +1050,7 @@ namespace mamba
config.at("safety_checks").value<VerificationLevel>(),
VerificationLevel::kDisabled
);
CHECK_EQ(ctx.safety_checks, VerificationLevel::kDisabled);
CHECK_EQ(ctx.validation_params.safety_checks, VerificationLevel::kDisabled);
env::set("MAMBA_SAFETY_CHECKS", "yeap");
REQUIRE_THROWS_AS(load_test_config(rc2), std::runtime_error);
@ -1058,7 +1059,7 @@ namespace mamba
load_test_config(rc2);
}
TEST_BOOL_CONFIGURABLE(extra_safety_checks, ctx.extra_safety_checks);
TEST_BOOL_CONFIGURABLE(extra_safety_checks, ctx.validation_params.extra_safety_checks);
#undef TEST_BOOL_CONFIGURABLE

View File

@ -20,13 +20,14 @@
#include "mamba/core/subdirdata.hpp"
#include "mamba/util/build.hpp"
#include "mambatests.hpp"
#include "test_data.hpp"
namespace mamba
{
// TEST(cpp_install, install)
// {
// Context::instance().output_params.verbosity = 3;
// mambatests::context().output_params.verbosity = 3;
// PackageInfo pkg("wheel", "0.34.2", "py_1", 1);
// fs::u8path prefix = "C:\\Users\\wolfv\\miniconda3\\";
// TransactionContext tc(prefix, "3.8.x");
@ -87,7 +88,7 @@ namespace mamba
TEST_CASE("parse")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
{
MatchSpec ms("xtensor==0.12.3", channel_context);
CHECK_EQ(ms.version, "0.12.3");
@ -264,7 +265,7 @@ namespace mamba
TEST_CASE("is_simple")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
{
MatchSpec ms("libblas", channel_context);
CHECK(ms.is_simple());
@ -292,7 +293,7 @@ namespace mamba
{
TEST_CASE("user_request")
{
auto u = History::UserRequest::prefilled();
auto u = History::UserRequest::prefilled(mambatests::context());
// update in 100 years!
CHECK_EQ(u.date[0], '2');
CHECK_EQ(u.date[1], '0');
@ -367,20 +368,20 @@ namespace mamba
{
if constexpr (util::on_mac || util::on_linux)
{
auto& ctx = Context::instance();
auto& ctx = mambatests::context();
ctx.prefix_params.root_prefix = "/home/user/micromamba/";
ctx.envs_dirs = { ctx.prefix_params.root_prefix / "envs" };
fs::u8path prefix = "/home/user/micromamba/envs/testprefix";
CHECK_EQ(env_name(prefix), "testprefix");
CHECK_EQ(env_name(ctx, prefix), "testprefix");
prefix = "/home/user/micromamba/envs/a.txt";
CHECK_EQ(env_name(prefix), "a.txt");
CHECK_EQ(env_name(ctx, prefix), "a.txt");
prefix = "/home/user/micromamba/envs/a.txt";
CHECK_EQ(env_name(prefix), "a.txt");
CHECK_EQ(env_name(ctx, prefix), "a.txt");
prefix = "/home/user/micromamba/envs/abc/a.txt";
CHECK_EQ(env_name(prefix), "/home/user/micromamba/envs/abc/a.txt");
CHECK_EQ(env_name(ctx, prefix), "/home/user/micromamba/envs/abc/a.txt");
prefix = "/home/user/env";
CHECK_EQ(env_name(prefix), "/home/user/env");
CHECK_EQ(env_name(ctx, prefix), "/home/user/env");
}
}
}

View File

@ -8,6 +8,8 @@
#include "mamba/core/download.hpp"
#include "mambatests.hpp"
namespace mamba
{
TEST_SUITE("downloader")
@ -22,9 +24,13 @@ namespace mamba
false,
true
);
auto& context = mambatests::singletons().context;
const auto previous_quiet = context.output_params.quiet;
auto _ = on_scope_exit([&] { context.output_params.quiet = previous_quiet; });
MultiDownloadRequest dl_request{ std::vector{ std::move(request) } };
Context::instance().output_params.quiet = true;
MultiDownloadResult res = download(dl_request, Context::instance());
context.output_params.quiet = true;
MultiDownloadResult res = download(dl_request, context);
CHECK_EQ(res.results.size(), std::size_t(1));
CHECK(!res.results[0]);
CHECK_EQ(res.results[0].error().attempt_number, std::size_t(1));
@ -40,8 +46,11 @@ namespace mamba
"test_download_repodata.json"
);
MultiDownloadRequest dl_request{ std::vector{ std::move(request) } };
Context::instance().output_params.quiet = true;
CHECK_THROWS_AS(download(dl_request, Context::instance()), std::runtime_error);
auto& context = mambatests::singletons().context;
const auto previous_quiet = context.output_params.quiet;
auto _ = on_scope_exit([&] { context.output_params.quiet = previous_quiet; });
context.output_params.quiet = true;
CHECK_THROWS_AS(download(dl_request, context), std::runtime_error);
#endif
}
}

View File

@ -9,6 +9,7 @@
#include "mamba/api/install.hpp"
#include "mamba/util/build.hpp"
#include "mambatests.hpp"
#include "test_data.hpp"
namespace mamba
@ -17,41 +18,43 @@ namespace mamba
{
TEST_CASE("selector")
{
const auto& context = mambatests::context();
using namespace detail;
if constexpr (util::on_linux || util::on_mac)
{
CHECK(eval_selector("sel(unix)"));
CHECK(eval_selector("sel(unix)", context.platform));
if (util::on_mac)
{
CHECK(eval_selector("sel(osx)"));
CHECK_FALSE(eval_selector("sel(linux)"));
CHECK_FALSE(eval_selector("sel(win)"));
CHECK(eval_selector("sel(osx)", context.platform));
CHECK_FALSE(eval_selector("sel(linux)", context.platform));
CHECK_FALSE(eval_selector("sel(win)", context.platform));
}
else
{
CHECK(eval_selector("sel(linux)"));
CHECK_FALSE(eval_selector("sel(osx)"));
CHECK_FALSE(eval_selector("sel(win)"));
CHECK(eval_selector("sel(linux)", context.platform));
CHECK_FALSE(eval_selector("sel(osx)", context.platform));
CHECK_FALSE(eval_selector("sel(win)", context.platform));
}
}
else if (util::on_win)
{
CHECK(eval_selector("sel(win)"));
CHECK_FALSE(eval_selector("sel(osx)"));
CHECK_FALSE(eval_selector("sel(linux)"));
CHECK(eval_selector("sel(win)", context.platform));
CHECK_FALSE(eval_selector("sel(osx)", context.platform));
CHECK_FALSE(eval_selector("sel(linux)", context.platform));
}
}
TEST_CASE("specs_selection")
{
const auto& context = mambatests::context();
using V = std::vector<std::string>;
auto res = detail::read_yaml_file(test_data_dir / "env_file/env_1.yaml");
auto res = detail::read_yaml_file(test_data_dir / "env_file/env_1.yaml", context.platform);
CHECK_EQ(res.name, "env_1");
CHECK_EQ(res.channels, V({ "conda-forge", "bioconda" }));
CHECK_EQ(res.dependencies, V({ "test1", "test2", "test3" }));
CHECK_FALSE(res.others_pkg_mgrs_specs.size());
auto res2 = detail::read_yaml_file(test_data_dir / "env_file/env_2.yaml");
auto res2 = detail::read_yaml_file(test_data_dir / "env_file/env_2.yaml", context.platform);
CHECK_EQ(res2.name, "env_2");
CHECK_EQ(res2.channels, V({ "conda-forge", "bioconda" }));
#ifdef __linux__
@ -66,8 +69,9 @@ namespace mamba
TEST_CASE("external_pkg_mgrs")
{
const auto& context = mambatests::context();
using V = std::vector<std::string>;
auto res = detail::read_yaml_file(test_data_dir / "env_file/env_3.yaml");
auto res = detail::read_yaml_file(test_data_dir / "env_file/env_3.yaml", context.platform);
CHECK_EQ(res.name, "env_3");
CHECK_EQ(res.channels, V({ "conda-forge", "bioconda" }));
CHECK_EQ(res.dependencies, V({ "test1", "test2", "test3", "pip" }));

View File

@ -12,6 +12,7 @@
#include "mamba/core/fsutil.hpp"
#include "mamba/core/transaction.hpp"
#include "mambatests.hpp"
#include "test_data.hpp"
namespace mamba
@ -20,7 +21,7 @@ namespace mamba
{
TEST_CASE("absent_file_fails")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const auto maybe_lockfile = read_environment_lockfile(
channel_context,
"this/file/does/not/exists"
@ -43,7 +44,7 @@ namespace mamba
TEST_CASE("invalid_version_fails")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const fs::u8path invalid_version_lockfile_path{ test_data_dir
/ "env_lockfile/bad_version-lock.yaml" };
const auto maybe_lockfile = read_environment_lockfile(
@ -59,7 +60,7 @@ namespace mamba
TEST_CASE("valid_no_package_succeed")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const fs::u8path lockfile_path{ test_data_dir / "env_lockfile/good_no_package-lock.yaml" };
const auto maybe_lockfile = read_environment_lockfile(channel_context, lockfile_path);
REQUIRE_MESSAGE(maybe_lockfile, maybe_lockfile.error().what());
@ -69,7 +70,7 @@ namespace mamba
TEST_CASE("invalid_package_fails")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const fs::u8path lockfile_path{ test_data_dir / "env_lockfile/bad_package-lock.yaml" };
const auto maybe_lockfile = read_environment_lockfile(channel_context, lockfile_path);
REQUIRE_FALSE(maybe_lockfile);
@ -81,7 +82,7 @@ namespace mamba
TEST_CASE("valid_one_package_succeed")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const fs::u8path lockfile_path{ test_data_dir
/ "env_lockfile/good_one_package-lock.yaml" };
const auto maybe_lockfile = read_environment_lockfile(channel_context, lockfile_path);
@ -92,7 +93,7 @@ namespace mamba
TEST_CASE("valid_one_package_implicit_category")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const fs::u8path lockfile_path{
test_data_dir / "env_lockfile/good_one_package_missing_category-lock.yaml"
};
@ -104,7 +105,7 @@ namespace mamba
TEST_CASE("valid_multiple_packages_succeed")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const fs::u8path lockfile_path{ test_data_dir
/ "env_lockfile/good_multiple_packages-lock.yaml" };
const auto maybe_lockfile = read_environment_lockfile(channel_context, lockfile_path);
@ -115,7 +116,7 @@ namespace mamba
TEST_CASE("get_specific_packages")
{
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
const fs::u8path lockfile_path{ test_data_dir
/ "env_lockfile/good_multiple_packages-lock.yaml" };
const auto lockfile = read_environment_lockfile(channel_context, lockfile_path).value();
@ -134,13 +135,12 @@ namespace mamba
TEST_CASE("create_transaction_with_categories")
{
auto& ctx = mambatests::context();
const fs::u8path lockfile_path{ test_data_dir
/ "env_lockfile/good_multiple_categories-lock.yaml" };
ChannelContext channel_context;
ChannelContext channel_context{ ctx };
MPool pool{ channel_context };
mamba::MultiPackageCache pkg_cache({ "/tmp/" });
auto& ctx = Context::instance();
mamba::MultiPackageCache pkg_cache({ "/tmp/" }, ctx.validation_params);
ctx.platform = "linux-64";

View File

@ -6,17 +6,20 @@
#include <doctest/doctest.h>
#include "mamba/core/context.hpp"
#include "mamba/core/environment.hpp"
#include "mamba/core/environments_manager.hpp"
#include "mamba/core/mamba_fs.hpp"
#include "mambatests.hpp"
namespace mamba
{
TEST_SUITE("env_manager")
{
TEST_CASE("all_envs")
{
EnvironmentsManager e;
EnvironmentsManager e{ mambatests::context() };
auto prefixes = e.list_all_known_prefixes();
// Test registering env without `conda-meta/history` file
e.register_env(env::expand_user("~/some/env"));

View File

@ -10,6 +10,8 @@
#include <doctest/doctest.h>
#include "mambatests.hpp"
#ifndef _WIN32
#include <sys/types.h>
#include <sys/wait.h>
@ -17,6 +19,7 @@
#endif
#include "mamba/core/channel.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/history.hpp"
#include "test_data.hpp"
@ -49,7 +52,7 @@ namespace mamba
}
} scoped_history_file_backup;
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
// Gather history from current history file.
History history_instance(test_data_dir / "history/parse", channel_context);
@ -93,7 +96,7 @@ namespace mamba
TEST_CASE("parse_segfault")
{
pid_t child = fork();
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
if (child)
{
int wstatus;

View File

@ -9,18 +9,20 @@
#include "mamba/core/context.hpp"
#include "mamba/core/output.hpp"
#include "mambatests.hpp"
namespace mamba
{
TEST_SUITE("output")
{
TEST_CASE("no_progress_bars")
{
Context::instance().graphics_params.no_progress_bars = true;
mambatests::context().graphics_params.no_progress_bars = true;
auto proxy = Console::instance().add_progress_bar("conda-forge");
CHECK_FALSE(proxy.defined());
CHECK_FALSE(proxy);
Context::instance().graphics_params.no_progress_bars = false;
mambatests::context().graphics_params.no_progress_bars = false;
proxy = Console::instance().add_progress_bar("conda-forge");
CHECK(proxy.defined());
CHECK(proxy);

View File

@ -7,9 +7,12 @@
#include <doctest/doctest.h>
#include "mamba/core/channel.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/pinning.hpp"
#include "mamba/core/util.hpp"
#include "mambatests.hpp"
namespace mamba
{
namespace testing
@ -21,7 +24,7 @@ namespace mamba
std::vector<std::string> specs;
std::string pin;
ChannelContext channel_context;
ChannelContext channel_context{ mambatests::context() };
auto sprefix_data = PrefixData::create("", channel_context);
if (!sprefix_data)
{

View File

@ -12,6 +12,8 @@
#include "../src/core/progress_bar_impl.hpp"
#include "mambatests.hpp"
namespace mamba
{
class progress_bar
@ -20,8 +22,12 @@ namespace mamba
progress_bar()
{
const auto& context = mambatests::context();
p_progress_bar_manager = std::make_unique<MultiBarManager>();
proxy = p_progress_bar_manager->add_progress_bar("conda-forge");
proxy = p_progress_bar_manager->add_progress_bar(
"conda-forge",
{ context.graphics_params, context.ascii_only }
);
auto& r = proxy.repr();
r.progress.set_value("??");

View File

@ -27,6 +27,8 @@
#include "mamba/core/util_random.hpp"
#include "mamba/util/string.hpp"
#include "mambatests.hpp"
using namespace mamba;
TEST_SUITE("conflict_map")
@ -140,9 +142,12 @@ namespace
* The underlying packages do not exist, we are onl interested in the conflict.
*/
template <typename PkgRange>
auto create_problem(const PkgRange& packages, const std::vector<std::string>& specs)
auto create_problem(
ChannelContext& channel_context,
const PkgRange& packages,
const std::vector<std::string>& specs
)
{
ChannelContext channel_context = {};
const auto tmp_dir = dir_guard(
fs::temp_directory_path() / "mamba/tests" / generate_random_alphanumeric_string(20)
);
@ -162,16 +167,18 @@ namespace
TEST_CASE("Test create_problem utility")
{
auto solver = create_problem(std::array{ mkpkg("foo", "0.1.0", {}) }, { "foo" });
ChannelContext channel_context{ mambatests::context() };
auto solver = create_problem(channel_context, std::array{ mkpkg("foo", "0.1.0", {}) }, { "foo" });
const auto solved = solver.try_solve();
REQUIRE(solved);
}
namespace
{
auto create_basic_conflict() -> MSolver
auto create_basic_conflict(ChannelContext& channel_context) -> MSolver
{
return create_problem(
channel_context,
std::array{
mkpkg("A", "0.1.0"),
mkpkg("A", "0.2.0"),
@ -187,9 +194,10 @@ namespace
* The example given by Natalie Weizenbaum
* (credits https://nex3.medium.com/pubgrub-2fb6470504f).
*/
auto create_pubgrub() -> MSolver
auto create_pubgrub(ChannelContext& channel_context) -> MSolver
{
return create_problem(
channel_context,
std::array{
mkpkg("menu", "1.5.0", { "dropdown=2.*" }),
mkpkg("menu", "1.4.0", { "dropdown=2.*" }),
@ -212,7 +220,7 @@ namespace
);
}
auto create_pubgrub_hard_(bool missing_package) -> MSolver
auto create_pubgrub_hard_(ChannelContext& channel_context, bool missing_package) -> MSolver
{
auto packages = std::vector{
mkpkg("menu", "2.1.0", { "dropdown>=2.1", "emoji" }),
@ -262,6 +270,7 @@ namespace
packages.push_back(mkpkg("dropdown", "2.9.0", { "libicons>10.0" }));
}
return create_problem(
channel_context,
packages,
{ "menu", "pyicons=1.*", "intl=5.*", "intl-mod", "pretty>=1.0" }
);
@ -270,17 +279,17 @@ namespace
/**
* A harder version of ``create_pubgrub``.
*/
auto create_pubgrub_hard() -> MSolver
auto create_pubgrub_hard(ChannelContext& channel_context) -> MSolver
{
return create_pubgrub_hard_(false);
return create_pubgrub_hard_(channel_context, false);
}
/**
* The hard version of the alternate PubGrub with missing packages.
*/
auto create_pubgrub_missing() -> MSolver
auto create_pubgrub_missing(ChannelContext& channel_context) -> MSolver
{
return create_pubgrub_hard_(true);
return create_pubgrub_hard_(channel_context, true);
}
template <typename T, typename E>
@ -308,7 +317,7 @@ namespace
*/
auto load_channels(MPool& pool, MultiPackageCache& cache, std::vector<std::string>&& channels)
{
auto dlist = MultiDownloadTarget();
MultiDownloadTarget dlist{ mambatests::context() };
auto sub_dirs = std::vector<MSubdirData>();
for (const auto* chan : pool.channel_context().get_channels(channels))
{
@ -332,13 +341,13 @@ namespace
* Create a solver and a pool of a conflict from conda-forge packages.
*/
auto create_conda_forge(
ChannelContext& channel_context,
std::vector<std::string>&& specs,
const std::vector<PackageInfo>& virtual_packages = { mkpkg("__glibc", "2.17.0") },
std::vector<std::string>&& channels = { "conda-forge" },
const std::vector<std::string>& platforms = { "linux-64", "noarch" }
) -> MSolver
{
ChannelContext channel_context = {};
// Reusing the cache for all invocation of this funciton for speedup
static const auto tmp_dir = dir_guard(
fs::temp_directory_path() / "mamba/tests" / generate_random_alphanumeric_string(20)
@ -352,13 +361,16 @@ namespace
auto repo = MRepo{ pool, prefix_data };
repo.set_installed();
auto cache = MultiPackageCache({ tmp_dir.path / "cache" });
auto cache = MultiPackageCache(
{ tmp_dir.path / "cache" },
channel_context.context().validation_params
);
create_cache_dir(cache.first_writable_path());
bool prev_progress_bars_value = Context::instance().graphics_params.no_progress_bars;
Context::instance().graphics_params.no_progress_bars = true;
bool prev_progress_bars_value = channel_context.context().graphics_params.no_progress_bars;
mambatests::context().graphics_params.no_progress_bars = true;
load_channels(pool, cache, make_platform_channels(std::move(channels), platforms));
Context::instance().graphics_params.no_progress_bars = prev_progress_bars_value;
mambatests::context().graphics_params.no_progress_bars = prev_progress_bars_value;
auto solver = MSolver(
std::move(pool),
@ -372,59 +384,63 @@ namespace
TEST_CASE("Test create_conda_forge utility ")
{
auto solver = create_conda_forge({ "xtensor>=0.7" });
ChannelContext channel_context{ mambatests::context() };
auto solver = create_conda_forge(channel_context, { "xtensor>=0.7" });
const auto solved = solver.try_solve();
REQUIRE(solved);
}
namespace
{
auto create_pytorch_cpu() -> MSolver
auto create_pytorch_cpu(ChannelContext& channel_context) -> MSolver
{
return create_conda_forge({ "python=2.7", "pytorch=1.12" });
return create_conda_forge(channel_context, { "python=2.7", "pytorch=1.12" });
}
auto create_pytorch_cuda() -> MSolver
auto create_pytorch_cuda(ChannelContext& channel_context) -> MSolver
{
return create_conda_forge(
channel_context,
{ "python=2.7", "pytorch=1.12" },
{ mkpkg("__glibc", "2.17.0"), mkpkg("__cuda", "10.2.0") }
);
}
auto create_cudatoolkit() -> MSolver
auto create_cudatoolkit(ChannelContext& channel_context) -> MSolver
{
return create_conda_forge(
channel_context,
{ "python=3.7", "cudatoolkit=11.1", "cudnn=8.0", "pytorch=1.8", "torchvision=0.9=*py37_cu111*" },
{ mkpkg("__glibc", "2.17.0"), mkpkg("__cuda", "11.1") }
);
}
auto create_jpeg9b() -> MSolver
auto create_jpeg9b(ChannelContext& channel_context) -> MSolver
{
return create_conda_forge({ "python=3.7", "jpeg=9b" });
return create_conda_forge(channel_context, { "python=3.7", "jpeg=9b" });
}
auto create_r_base() -> MSolver
auto create_r_base(ChannelContext& channel_context) -> MSolver
{
return create_conda_forge(
channel_context,
{ "r-base=3.5.* ", "pandas=0", "numpy<1.20.0", "matplotlib=2", "r-matchit=4.*" }
);
}
auto create_scip() -> MSolver
auto create_scip(ChannelContext& channel_context) -> MSolver
{
return create_conda_forge({ "scip=8.*", "pyscipopt<4.0" });
return create_conda_forge(channel_context, { "scip=8.*", "pyscipopt<4.0" });
}
auto create_double_python() -> MSolver
auto create_double_python(ChannelContext& channel_context) -> MSolver
{
return create_conda_forge({ "python=3.9.*", "python=3.10.*" });
return create_conda_forge(channel_context, { "python=3.9.*", "python=3.10.*" });
}
auto create_numba() -> MSolver
auto create_numba(ChannelContext& channel_context) -> MSolver
{
return create_conda_forge({ "python=3.11", "numba<0.56" });
return create_conda_forge(channel_context, { "python=3.11", "numba<0.56" });
}
template <typename NodeVariant>
@ -499,10 +515,12 @@ TEST_CASE("Create problem graph")
for (const auto& [name, factory] : issues)
{
ChannelContext channel_context{ mambatests::context() };
// Somehow the capture does not work directly on ``name``
std::string_view name_copy = name;
CAPTURE(name_copy);
auto solver = factory();
auto solver = factory(channel_context);
const auto solved = solver.try_solve();
REQUIRE_FALSE(solved);
const auto pbs_init = solver.problems_graph();

View File

@ -13,6 +13,8 @@
#include "mamba/core/output.hpp"
#include "mamba/core/thread_utils.hpp"
#include "mambatests.hpp"
namespace mamba
{
namespace
@ -23,8 +25,8 @@ namespace mamba
int test_interruption_guard(bool interrupt)
{
int res = 0;
// Ensures the compiler doe snot optimize away Context::instance()
std::string current_command = Context::instance().command_params.current_command;
// Ensures the compiler doe snot optimize away mambatests::context()
std::string current_command = mambatests::context().command_params.current_command;
CHECK_EQ(current_command, "mamba");
Console::instance().init_progress_bar_manager(ProgressBarMode::multi);
{

View File

@ -10,6 +10,8 @@
#include "mamba/core/subdirdata.hpp"
#include "mambatests.hpp"
namespace mamba
{
TEST_SUITE("transfer")
@ -17,12 +19,13 @@ namespace mamba
TEST_CASE("file_not_exist")
{
#ifdef __linux__
Context::instance().output_params.quiet = true;
auto& context = mambatests::context();
context.output_params.quiet = true;
{
mamba::ChannelContext channel_context;
mamba::ChannelContext channel_context{ context };
const mamba::Channel& c = channel_context.make_channel("conda-forge");
mamba::MultiDownloadTarget multi_dl;
mamba::MultiPackageCache pkg_cache({ "/tmp/" });
mamba::MultiDownloadTarget multi_dl{ context };
mamba::MultiPackageCache pkg_cache({ "/tmp/" }, context.validation_params);
mamba::MSubdirData cf = mamba::MSubdirData::create(
channel_context,
c,
@ -42,10 +45,10 @@ namespace mamba
CHECK_EQ(cf.target()->get_result(), 37);
}
{
mamba::ChannelContext channel_context;
mamba::ChannelContext channel_context{ context };
const mamba::Channel& c = channel_context.make_channel("conda-forge");
mamba::MultiDownloadTarget multi_dl;
mamba::MultiPackageCache pkg_cache({ "/tmp/" });
mamba::MultiDownloadTarget multi_dl{ channel_context.context() };
mamba::MultiPackageCache pkg_cache({ "/tmp/" }, context.validation_params);
mamba::MSubdirData cf = mamba::MSubdirData::create(
channel_context,
c,
@ -57,7 +60,7 @@ namespace mamba
multi_dl.add(cf.target());
CHECK_THROWS_AS(multi_dl.download(MAMBA_DOWNLOAD_FAILFAST), std::runtime_error);
}
Context::instance().output_params.quiet = false;
context.output_params.quiet = false;
#endif
}
}

View File

@ -15,6 +15,8 @@
#include "mamba/core/util_random.hpp"
#include "mamba/core/util_scope.hpp"
#include "mambatests.hpp"
namespace mamba
{
TEST_SUITE("local_random_generator")
@ -175,33 +177,34 @@ namespace mamba
{
TEST_CASE("proxy_match")
{
Context::instance().remote_fetch_params.proxy_servers = { { "http", "foo" },
{ "https", "bar" },
{ "https://example.net",
"foobar" },
{ "all://example.net", "baz" },
{ "all", "other" } };
auto& context = mambatests::singletons().context;
context.remote_fetch_params.proxy_servers = { { "http", "foo" },
{ "https", "bar" },
{ "https://example.net", "foobar" },
{ "all://example.net", "baz" },
{ "all", "other" } };
CHECK_EQ(*proxy_match("http://example.com/channel"), "foo");
CHECK_EQ(*proxy_match("http://example.net/channel"), "foo");
CHECK_EQ(*proxy_match("https://example.com/channel"), "bar");
CHECK_EQ(*proxy_match("https://example.com:8080/channel"), "bar");
CHECK_EQ(*proxy_match("https://example.net/channel"), "foobar");
CHECK_EQ(*proxy_match("ftp://example.net/channel"), "baz");
CHECK_EQ(*proxy_match("ftp://example.org"), "other");
auto proxy_match_with_context = [&](const char* url)
{ return proxy_match(url, context.remote_fetch_params.proxy_servers); };
Context::instance().remote_fetch_params.proxy_servers = {
{ "http", "foo" },
{ "https", "bar" },
{ "https://example.net", "foobar" },
{ "all://example.net", "baz" }
};
CHECK_EQ(*proxy_match_with_context("http://example.com/channel"), "foo");
CHECK_EQ(*proxy_match_with_context("http://example.net/channel"), "foo");
CHECK_EQ(*proxy_match_with_context("https://example.com/channel"), "bar");
CHECK_EQ(*proxy_match_with_context("https://example.com:8080/channel"), "bar");
CHECK_EQ(*proxy_match_with_context("https://example.net/channel"), "foobar");
CHECK_EQ(*proxy_match_with_context("ftp://example.net/channel"), "baz");
CHECK_EQ(*proxy_match_with_context("ftp://example.org"), "other");
CHECK_FALSE(proxy_match("ftp://example.org").has_value());
context.remote_fetch_params.proxy_servers = { { "http", "foo" },
{ "https", "bar" },
{ "https://example.net", "foobar" },
{ "all://example.net", "baz" } };
Context::instance().remote_fetch_params.proxy_servers = {};
CHECK_FALSE(proxy_match_with_context("ftp://example.org").has_value());
CHECK_FALSE(proxy_match("http://example.com/channel").has_value());
context.remote_fetch_params.proxy_servers = {};
CHECK_FALSE(proxy_match_with_context("http://example.com/channel").has_value());
}
}
}

View File

@ -11,11 +11,13 @@
#include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>
#include "mamba/core/context.hpp"
#include "mamba/core/environment.hpp"
#include "mamba/core/fsutil.hpp"
#include "mamba/core/validate.hpp"
#include "mamba/util/string.hpp"
#include "mambatests.hpp"
#include "test_data.hpp"
namespace mamba::validation
@ -1443,14 +1445,14 @@ namespace mamba::validation
{
TEST_CASE_FIXTURE(RepoCheckerT, "ctor")
{
RepoChecker checker(m_repo_base_url, m_ref_path);
RepoChecker checker(mambatests::context(), m_repo_base_url, m_ref_path);
checker.generate_index_checker();
CHECK_EQ(checker.root_version(), 2);
}
TEST_CASE_FIXTURE(RepoCheckerT, "verify_index")
{
RepoChecker checker(m_repo_base_url, m_ref_path);
RepoChecker checker(mambatests::context(), m_repo_base_url, m_ref_path);
checker.generate_index_checker();
checker.verify_index(signed_repodata_json);
}
@ -1465,7 +1467,7 @@ namespace mamba::validation
])"
);
write_role(create_root_update_json(patch), channel_dir->path() / "2.root.json");
RepoChecker checker(m_repo_base_url, m_ref_path);
RepoChecker checker(mambatests::context(), m_repo_base_url, m_ref_path);
CHECK_THROWS_AS(checker.generate_index_checker(), freeze_error);
}
@ -1478,20 +1480,20 @@ namespace mamba::validation
])"
);
write_role(patched_key_mgr_json(patch), channel_dir->path() / "key_mgr.json");
RepoChecker checker(m_repo_base_url, m_ref_path);
RepoChecker checker(mambatests::context(), m_repo_base_url, m_ref_path);
CHECK_THROWS_AS(checker.generate_index_checker(), freeze_error);
}
TEST_CASE_FIXTURE(RepoCheckerT, "missing_key_mgr_file")
{
fs::remove(channel_dir->path() / "key_mgr.json");
RepoChecker checker(m_repo_base_url, m_ref_path);
RepoChecker checker(mambatests::context(), m_repo_base_url, m_ref_path);
CHECK_THROWS_AS(checker.generate_index_checker(), fetching_error);
}
TEST_CASE_FIXTURE(RepoCheckerT, "corrupted_repodata")
{
RepoChecker checker(m_repo_base_url, m_ref_path);
RepoChecker checker(mambatests::context(), m_repo_base_url, m_ref_path);
json wrong_pkg_patch = R"([
{ "op": "replace", "path": "/packages/test-package1-0.1-0.tar.bz2/version", "value": "0.1.1" }
@ -1505,7 +1507,7 @@ namespace mamba::validation
TEST_CASE_FIXTURE(RepoCheckerT, "illformed_repodata")
{
RepoChecker checker(m_repo_base_url, m_ref_path);
RepoChecker checker(mambatests::context(), m_repo_base_url, m_ref_path);
json illformed_pkg_patch = R"([
{ "op": "remove", "path": "/signatures"}

View File

@ -13,6 +13,8 @@
#include "mamba/core/virtual_packages.hpp"
#include "mamba/util/build.hpp"
#include "mambatests.hpp"
namespace mamba
{
namespace testing
@ -33,22 +35,23 @@ namespace mamba
{
TEST_CASE("make_virtual_package")
{
auto pkg = detail::make_virtual_package("test", "0.1.5", "abcd");
const auto& context = mambatests::context();
const auto pkg = detail::make_virtual_package("test", context.platform, "0.1.5", "abcd");
CHECK_EQ(pkg.name, "test");
CHECK_EQ(pkg.version, "0.1.5");
CHECK_EQ(pkg.build_string, "abcd");
CHECK_EQ(pkg.build_number, 0);
CHECK_EQ(pkg.channel, "@");
// CHECK_EQ(pkg.subdir, "osx-64"); // TODO: fix this
CHECK_EQ(pkg.subdir, context.platform);
CHECK_EQ(pkg.md5, "12345678901234567890123456789012");
CHECK_EQ(pkg.fn, pkg.name);
}
TEST_CASE("dist_packages")
{
auto pkgs = detail::dist_packages();
auto& ctx = Context::instance();
auto& ctx = mambatests::context();
auto pkgs = detail::dist_packages(ctx);
if (util::on_win)
{
@ -80,7 +83,7 @@ namespace mamba
ctx.platform = "osx-arm";
env::set("CONDA_OVERRIDE_OSX", "12.1");
pkgs = detail::dist_packages();
pkgs = detail::dist_packages(ctx);
REQUIRE_EQ(pkgs.size(), 3);
CHECK_EQ(pkgs[0].name, "__unix");
CHECK_EQ(pkgs[1].name, "__osx");
@ -92,7 +95,7 @@ namespace mamba
ctx.platform = "linux-32";
env::set("CONDA_OVERRIDE_LINUX", "5.7");
env::set("CONDA_OVERRIDE_GLIBC", "2.15");
pkgs = detail::dist_packages();
pkgs = detail::dist_packages(ctx);
REQUIRE_EQ(pkgs.size(), 4);
CHECK_EQ(pkgs[0].name, "__unix");
CHECK_EQ(pkgs[1].name, "__linux");
@ -105,14 +108,14 @@ namespace mamba
env::unset("CONDA_OVERRIDE_LINUX");
ctx.platform = "lin-850";
pkgs = detail::dist_packages();
pkgs = detail::dist_packages(ctx);
REQUIRE_EQ(pkgs.size(), 1);
CHECK_EQ(pkgs[0].name, "__archspec");
CHECK_EQ(pkgs[0].build_string, "850");
env::unset("CONDA_SUBDIR");
ctx.platform = "linux";
pkgs = detail::dist_packages();
pkgs = detail::dist_packages(ctx);
REQUIRE_EQ(pkgs.size(), 0);
ctx.platform = ctx.host_platform;
@ -121,8 +124,8 @@ namespace mamba
TEST_CASE("get_virtual_packages")
{
env::set("CONDA_OVERRIDE_CUDA", "9.0");
auto pkgs = get_virtual_packages();
const auto& context = mambatests::context();
auto pkgs = get_virtual_packages(context);
int pkgs_count;
if (util::on_win)
@ -144,7 +147,7 @@ namespace mamba
CHECK_EQ(pkgs.back().version, "9.0");
env::unset("CONDA_OVERRIDE_CUDA");
pkgs = get_virtual_packages();
pkgs = get_virtual_packages(context);
if (!detail::cuda_version().empty())
{

View File

@ -18,6 +18,7 @@
#include "mamba/api/configuration.hpp"
#include "mamba/core/channel.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/package_handling.hpp"
#include "mamba/core/pool.hpp"
@ -113,17 +114,62 @@ bind_NamedList(PyClass pyclass)
namespace mambapy
{
struct Singletons
class Singletons
{
mamba::ChannelContext channel_context;
mamba::Configuration config;
public:
mamba::MainExecutor& main_executor()
{
return m_main_executor;
}
mamba::Context& context()
{
return m_context;
}
mamba::Console& console()
{
return m_console;
}
mamba::ChannelContext& channel_context()
{
return init_once(p_channel_context, m_context);
}
mamba::Configuration& config()
{
return m_config;
}
private:
template <class T, class D>
T& init_once(std::unique_ptr<T, D>& ptr, mamba::Context& context)
{
static std::once_flag init_flag;
std::call_once(init_flag, [&] { ptr = std::make_unique<T>(context); });
if (!ptr)
{
throw mamba::mamba_error(
fmt::format(
"attempt to use {} singleton instance after destruction",
typeid(T).name()
),
mamba::mamba_error_code::internal_failure
);
}
return *ptr;
}
mamba::MainExecutor m_main_executor;
mamba::Context m_context{ { /* .enable_logging_and_signal_handling = */ true } };
mamba::Console m_console{ m_context };
// ChannelContext needs to be lazy initialized, to enusre the Context has been initialized
// before
std::unique_ptr<mamba::ChannelContext> p_channel_context = nullptr;
mamba::Configuration m_config{ m_context };
};
Singletons& singletons()
{
static Singletons singletons;
return singletons;
}
Singletons singletons;
}
PYBIND11_MODULE(bindings, m)
@ -135,7 +181,10 @@ PYBIND11_MODULE(bindings, m)
auto pyPackageInfo = py::class_<PackageInfo>(m, "PackageInfo");
auto pyPrefixData = py::class_<PrefixData>(m, "PrefixData");
auto pySolver = py::class_<MSolver>(m, "Solver");
auto pyMultiDownloadTarget = py::class_<MultiDownloadTarget>(m, "DownloadTargetList");
auto pyMultiDownloadTarget = py::class_<MultiDownloadTarget, std::unique_ptr<MultiDownloadTarget>>(
m,
"DownloadTargetList"
);
// only used in a return type; does it belong in the module?
auto pyRootRole = py::class_<validation::RootRole>(m, "RootRole");
@ -159,13 +208,13 @@ PYBIND11_MODULE(bindings, m)
.def(py::init<>())
.def(py::init<>(
[](const std::string& name) {
return MatchSpec{ name, mambapy::singletons().channel_context };
return MatchSpec{ name, mambapy::singletons.channel_context() };
}
))
.def("conda_build_form", &MatchSpec::conda_build_form);
py::class_<MPool>(m, "Pool")
.def(py::init<>([] { return MPool{ mambapy::singletons().channel_context }; }))
.def(py::init<>([] { return MPool{ mambapy::singletons.channel_context() }; }))
.def("set_debuglevel", &MPool::set_debuglevel)
.def("create_whatprovides", &MPool::create_whatprovides)
.def("select_solvables", &MPool::select_solvables, py::arg("id"), py::arg("sorted") = false)
@ -173,14 +222,22 @@ PYBIND11_MODULE(bindings, m)
.def(
"matchspec2id",
[](MPool& self, std::string_view ms) {
return self.matchspec2id({ ms, mambapy::singletons().channel_context });
return self.matchspec2id({ ms, mambapy::singletons.channel_context() });
},
py::arg("ms")
)
.def("id2pkginfo", &MPool::id2pkginfo, py::arg("id"));
py::class_<MultiPackageCache>(m, "MultiPackageCache")
.def(py::init<std::vector<fs::u8path>>())
.def(py::init<>(
[](const std::vector<fs::u8path>& pkgs_dirs)
{
return MultiPackageCache{
pkgs_dirs,
mambapy::singletons.context().validation_params,
};
}
))
.def("get_tarball_path", &MultiPackageCache::get_tarball_path)
.def_property_readonly("first_writable_path", &MultiPackageCache::first_writable_path);
@ -339,7 +396,7 @@ PYBIND11_MODULE(bindings, m)
py::class_<History>(m, "History")
.def(py::init(
[](const fs::u8path& path) {
return History{ path, mambapy::singletons().channel_context };
return History{ path, mambapy::singletons.channel_context() };
}
))
.def("get_requested_specs_map", &History::get_requested_specs_map);
@ -370,7 +427,7 @@ PYBIND11_MODULE(bindings, m)
{
case query::JSON:
res_stream
<< res.groupby("name").json(mambapy::singletons().channel_context).dump(4);
<< res.groupby("name").json(mambapy::singletons.channel_context()).dump(4);
break;
case query::TREE:
case query::TABLE:
@ -399,10 +456,10 @@ PYBIND11_MODULE(bindings, m)
{
case query::TREE:
case query::PRETTY:
res.tree(res_stream);
res.tree(res_stream, mambapy::singletons.context().graphics_params);
break;
case query::JSON:
res_stream << res.json(mambapy::singletons().channel_context).dump(4);
res_stream << res.json(mambapy::singletons.channel_context()).dump(4);
break;
case query::TABLE:
case query::RECURSIVETABLE:
@ -439,10 +496,10 @@ PYBIND11_MODULE(bindings, m)
{
case query::TREE:
case query::PRETTY:
res.tree(res_stream);
res.tree(res_stream, mambapy::singletons.context().graphics_params);
break;
case query::JSON:
res_stream << res.json(mambapy::singletons().channel_context).dump(4);
res_stream << res.json(mambapy::singletons.channel_context()).dump(4);
break;
case query::TABLE:
case query::RECURSIVETABLE:
@ -468,7 +525,7 @@ PYBIND11_MODULE(bindings, m)
const std::string& repodata_fn) -> MSubdirData
{
auto sres = MSubdirData::create(
mambapy::singletons().channel_context,
mambapy::singletons.channel_context(),
channel,
platform,
url,
@ -505,7 +562,10 @@ PYBIND11_MODULE(bindings, m)
m.def("cache_fn_url", &cache_fn_url);
m.def("create_cache_dir", &create_cache_dir);
pyMultiDownloadTarget.def(py::init<>())
pyMultiDownloadTarget
.def(py::init(
[] { return std::make_unique<MultiDownloadTarget>(mambapy::singletons.context()); }
))
.def(
"add",
[](MultiDownloadTarget& self, MSubdirData& sub) -> void { self.add(sub.target()); }
@ -527,7 +587,9 @@ PYBIND11_MODULE(bindings, m)
.value("OFF", mamba::log_level::off);
py::class_<Context, std::unique_ptr<Context, py::nodelete>> ctx(m, "Context");
ctx.def(py::init([]() { return std::unique_ptr<Context, py::nodelete>(&Context::instance()); }))
ctx.def(py::init(
[] { return std::unique_ptr<Context, py::nodelete>(&mambapy::singletons.context()); }
))
.def_readwrite("offline", &Context::offline)
.def_readwrite("local_repodata_ttl", &Context::local_repodata_ttl)
.def_readwrite("use_index_cache", &Context::use_index_cache)
@ -607,6 +669,14 @@ PYBIND11_MODULE(bindings, m)
.def_readwrite("threads_params", &Context::threads_params)
.def_readwrite("prefix_params", &Context::prefix_params);
// TODO: uncomment these parameters once they are made available to Python api.
// py::class_<ValidationOptions>(ctx, "ValidationOptions")
// .def_readwrite("safety_checks", &ValidationOptions::safety_checks)
// .def_readwrite("extra_safety_checks", &ValidationOptions::extra_safety_checks)
// .def_readwrite("verify_artifacts", &ValidationOptions::verify_artifacts);
// ctx.def_readwrite("validation_params", &Context::validation_params);
////////////////////////////////////////////
// Support the old deprecated API ///
////////////////////////////////////////////
@ -819,7 +889,7 @@ PYBIND11_MODULE(bindings, m)
.def(py::init(
[](const fs::u8path& prefix_path) -> PrefixData
{
auto sres = PrefixData::create(prefix_path, mambapy::singletons().channel_context);
auto sres = PrefixData::create(prefix_path, mambapy::singletons.channel_context());
if (sres.has_value())
{
return std::move(sres.value());
@ -978,7 +1048,7 @@ PYBIND11_MODULE(bindings, m)
pyChannel
.def(py::init(
[](const std::string& value) {
return const_cast<Channel*>(&mambapy::singletons().channel_context.make_channel(value)
return const_cast<Channel*>(&mambapy::singletons.channel_context().make_channel(value)
);
}
))
@ -1014,17 +1084,24 @@ PYBIND11_MODULE(bindings, m)
}
);
m.def("clean", [](int flags) { return clean(mambapy::singletons().config, flags); });
m.def("clean", [](int flags) { return clean(mambapy::singletons.config(), flags); });
m.def(
"get_channels",
[](const std::vector<std::string>& channel_names)
{ return mambapy::singletons().channel_context.get_channels(channel_names); }
{ return mambapy::singletons.channel_context().get_channels(channel_names); }
);
m.def(
"transmute",
&transmute,
+[](const fs::u8path& pkg_file, const fs::u8path& target, int compression_level, int compression_threads
)
{
const auto extract_options = mamba::ExtractOptions::from_context(
mambapy::singletons.context()
);
return transmute(pkg_file, target, compression_level, compression_threads, extract_options);
},
py::arg("source_package"),
py::arg("destination_package"),
py::arg("compression_level"),
@ -1040,7 +1117,7 @@ PYBIND11_MODULE(bindings, m)
// py::arg("out_package"), py::arg("compression_level"), py::arg("compression_threads") = 1);
m.def("get_virtual_packages", &get_virtual_packages);
m.def("get_virtual_packages", [] { return get_virtual_packages(mambapy::singletons.context()); });
m.def("cancel_json_output", [] { Console::instance().cancel_json_print(); });

View File

@ -8,6 +8,7 @@
#include "mamba/api/configuration.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/thread_utils.hpp"
#include "mamba/core/util_os.hpp"
@ -21,13 +22,16 @@ main(int argc, char** argv)
{
using namespace mamba; // NOLINT(build/namespaces)
Configuration config;
MainExecutor main_executor;
Context context{ { /* .enable_blah_blah = */ true } };
Console console{ context };
Configuration config{ context };
// call init console to setup utf8 extraction
init_console();
CLI::App app{ "Version: " + version() + "\n" };
set_package_command(&app);
set_package_command(&app, context);
try
{
@ -44,7 +48,7 @@ main(int argc, char** argv)
if (app.get_subcommands().size() == 0)
{
config.load();
Console::instance().print(app.help());
console.print(app.help());
}
return 0;

View File

@ -4,15 +4,17 @@
//
// The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/context.hpp"
#include "mamba/core/package_handling.hpp"
#include "mamba/util/string.hpp"
#include "package.hpp"
using namespace mamba; // NOLINT(build/namespaces)
void
set_package_command(CLI::App* com)
set_package_command(CLI::App* com, mamba::Context& context)
{
static std::string infile, dest;
static int compression_level = -1;
@ -26,7 +28,7 @@ set_package_command(CLI::App* com)
{
std::cout << "Extracting " << fs::absolute(infile) << " to " << fs::absolute(dest)
<< std::endl;
extract(fs::absolute(infile), fs::absolute(dest));
extract(fs::absolute(infile), fs::absolute(dest), ExtractOptions::from_context(context));
}
);
@ -98,7 +100,13 @@ set_package_command(CLI::App* com)
dest = infile.substr(0, infile.size() - 8) + ".tar.bz2";
}
std::cout << "Transmuting " << fs::absolute(infile) << " to " << dest << std::endl;
transmute(fs::absolute(infile), fs::absolute(dest), compression_level, compression_threads);
transmute(
fs::absolute(infile),
fs::absolute(dest),
compression_level,
compression_threads,
ExtractOptions::from_context(context)
);
}
);
}

Some files were not shown because too many files have changed in this diff Show More