Fine tune clang-format proposal (#2290)

* Fine-tune .clang-format

* Fix missing header and right const

* Fix header order on Windows

* Apply pre-commit
This commit is contained in:
Antoine Prouvost 2023-02-20 16:01:43 +01:00 committed by GitHub
parent 0002794f3c
commit 365342cc04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
155 changed files with 6698 additions and 4273 deletions

View File

@ -1,15 +1,20 @@
BasedOnStyle: Mozilla BasedOnStyle: Mozilla
Language: Cpp
Standard: c++17
AccessModifierOffset: '-4' AccessModifierOffset: '-4'
AlignAfterOpenBracket: Align AlignAfterOpenBracket: BlockIndent
AlignEscapedNewlinesLeft: 'false' AlignEscapedNewlinesLeft: 'false'
AllowAllParametersOfDeclarationOnNextLine: 'true' AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: 'false' AllowShortBlocksOnASingleLine: 'false'
AllowShortCaseLabelsOnASingleLine: 'false' AllowShortCaseLabelsOnASingleLine: 'false'
AllowShortFunctionsOnASingleLine: 'false' AllowShortFunctionsOnASingleLine: 'false'
AllowShortIfStatementsOnASingleLine: 'false' AllowShortIfStatementsOnASingleLine: 'false'
AllowShortLoopsOnASingleLine: 'false' AllowShortLoopsOnASingleLine: 'false'
AlwaysBreakTemplateDeclarations: 'true' AlwaysBreakTemplateDeclarations: 'true'
SpaceAfterTemplateKeyword: 'true' BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: All BreakBeforeBinaryOperators: All
BreakBeforeBraces: Allman BreakBeforeBraces: Allman
BreakBeforeTernaryOperators: 'true' BreakBeforeTernaryOperators: 'true'
@ -22,22 +27,49 @@ ContinuationIndentWidth: '4'
Cpp11BracedListStyle: 'false' Cpp11BracedListStyle: 'false'
DerivePointerAlignment: 'false' DerivePointerAlignment: 'false'
DisableFormat: 'false' DisableFormat: 'false'
EmptyLineAfterAccessModifier: Always
EmptyLineBeforeAccessModifier: Always
ExperimentalAutoDetectBinPacking: 'true' ExperimentalAutoDetectBinPacking: 'true'
IncludeBlocks: Regroup
IncludeCategories:
- Regex: <[^.]+>
Priority: 1
- Regex: <mamba/.+>
Priority: 3
- Regex: <.+>
Priority: 2
- Regex: '"mamba/.+"'
Priority: 4
- Regex: '".+/.+"'
Priority: 5
- Regex: '".+"'
Priority: 6
IndentCaseLabels: 'true' IndentCaseLabels: 'true'
IndentWidth: '4' IndentWidth: '4'
IndentWrappedFunctionNames: 'false' IndentWrappedFunctionNames: 'false'
JavaScriptQuotes: Single InsertBraces: true # Experimental
KeepEmptyLinesAtTheStartOfBlocks: 'false' KeepEmptyLinesAtTheStartOfBlocks: 'false'
Language: Cpp
MaxEmptyLinesToKeep: '2' MaxEmptyLinesToKeep: '2'
NamespaceIndentation: All NamespaceIndentation: All
ObjCBlockIndentWidth: '4' ObjCBlockIndentWidth: '4'
ObjCSpaceAfterProperty: 'false' ObjCSpaceAfterProperty: 'false'
ObjCSpaceBeforeProtocolList: 'false' ObjCSpaceBeforeProtocolList: 'false'
PackConstructorInitializers: Never
PenaltyBreakAssignment: 100000
PenaltyBreakBeforeFirstCallParameter: 0
PenaltyBreakComment: 10
PenaltyBreakOpenParenthesis: 0
PenaltyBreakTemplateDeclaration: 0
PenaltyExcessCharacter: 10
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 10
PointerAlignment: Left PointerAlignment: Left
QualifierAlignment: Custom # Experimental
QualifierOrder: [inline, static, constexpr, const, volatile, type]
ReflowComments: 'true' ReflowComments: 'true'
SortIncludes: 'false' SortIncludes: CaseInsensitive
SpaceAfterCStyleCast: 'true' SpaceAfterCStyleCast: 'true'
SpaceAfterTemplateKeyword: 'true'
SpaceBeforeAssignmentOperators: 'true' SpaceBeforeAssignmentOperators: 'true'
SpaceBeforeParens: ControlStatements SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: 'false' SpaceInEmptyParentheses: 'false'
@ -47,6 +79,5 @@ SpacesInCStyleCastParentheses: 'false'
SpacesInContainerLiterals: 'false' SpacesInContainerLiterals: 'false'
SpacesInParentheses: 'false' SpacesInParentheses: 'false'
SpacesInSquareBrackets: 'false' SpacesInSquareBrackets: 'false'
Standard: c++17
TabWidth: '4' TabWidth: '4'
UseTab: Never UseTab: Never

View File

@ -5,7 +5,6 @@ namespace mamba
class MPool; class MPool;
class MultiPackageCache; class MultiPackageCache;
expected_t<void, mamba_aggregated_error> load_channels(MPool& pool, expected_t<void, mamba_aggregated_error>
MultiPackageCache& package_caches, load_channels(MPool& pool, MultiPackageCache& package_caches, int is_retry);
int is_retry);
} }

View File

@ -7,16 +7,16 @@
#ifndef MAMBA_API_CONFIGURATION_HPP #ifndef MAMBA_API_CONFIGURATION_HPP
#define MAMBA_API_CONFIGURATION_HPP #define MAMBA_API_CONFIGURATION_HPP
#include <functional>
#include <yaml-cpp/yaml.h>
#include "mamba/api/configuration_impl.hpp"
#include "mamba/api/constants.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/environment.hpp" #include "mamba/core/environment.hpp"
#include "mamba/core/mamba_fs.hpp" #include "mamba/core/mamba_fs.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/api/constants.hpp"
#include "mamba/api/configuration_impl.hpp"
#include <yaml-cpp/yaml.h>
#include <functional>
#define CONTEXT_DEBUGGING \ #define CONTEXT_DEBUGGING \
@ -25,13 +25,12 @@
Context::instance().debug_print(); \ Context::instance().debug_print(); \
exit(0); \ exit(0); \
} }
#define CONFIG_DEBUGGING \ #define CONFIG_DEBUGGING \
if (Configuration::instance().at("print_config_only").value<bool>()) \ if (Configuration::instance().at("print_config_only").value<bool>()) \
{ \ { \
int dump_opts \ int dump_opts = MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS | MAMBA_SHOW_ALL_CONFIGS; \
= MAMBA_SHOW_CONFIG_VALUES | MAMBA_SHOW_CONFIG_SRCS | MAMBA_SHOW_ALL_CONFIGS; \ std::cout << Configuration::instance().dump(dump_opts) << std::endl; \
std::cout << Configuration::instance().dump(dump_opts) << std::endl; \ exit(0); \
exit(0); \
} }
namespace mamba namespace mamba
@ -81,20 +80,32 @@ namespace YAML
static bool decode(const Node& node, mamba::RCConfigLevel& rhs) static bool decode(const Node& node, mamba::RCConfigLevel& rhs)
{ {
if (!node.IsScalar()) if (!node.IsScalar())
{
return false; return false;
}
auto str = node.as<std::string>(); auto str = node.as<std::string>();
if (str == "HomeDir") if (str == "HomeDir")
{
rhs = mamba::RCConfigLevel::kHomeDir; rhs = mamba::RCConfigLevel::kHomeDir;
}
else if (str == "RootPrefix") else if (str == "RootPrefix")
{
rhs = mamba::RCConfigLevel::kRootPrefix; rhs = mamba::RCConfigLevel::kRootPrefix;
}
else if (str == "SystemDir") else if (str == "SystemDir")
{
rhs = mamba::RCConfigLevel::kSystemDir; rhs = mamba::RCConfigLevel::kSystemDir;
}
else if (str == "TargetPrefix") else if (str == "TargetPrefix")
{
rhs = mamba::RCConfigLevel::kTargetPrefix; rhs = mamba::RCConfigLevel::kTargetPrefix;
}
else else
{
return false; return false;
}
return true; return true;
} }
@ -120,9 +131,10 @@ namespace mamba
virtual void set_default_value() = 0; virtual void set_default_value() = 0;
virtual void set_rc_yaml_value(const YAML::Node& value, const std::string& source) = 0; virtual void set_rc_yaml_value(const YAML::Node& value, const std::string& source) = 0;
virtual void set_rc_yaml_values(const std::map<std::string, YAML::Node>& values, virtual void set_rc_yaml_values(
const std::vector<std::string>& sources) const std::map<std::string, YAML::Node>& values,
= 0; const std::vector<std::string>& sources
) = 0;
virtual void set_cli_yaml_value(const YAML::Node& value) = 0; virtual void set_cli_yaml_value(const YAML::Node& value) = 0;
virtual void set_cli_yaml_value(const std::string& value) = 0; virtual void set_cli_yaml_value(const std::string& value) = 0;
virtual void set_yaml_value(const YAML::Node& value) = 0; virtual void set_yaml_value(const YAML::Node& value) = 0;
@ -175,8 +187,10 @@ namespace mamba
void set_default_value() override; void set_default_value() override;
void set_rc_yaml_value(const YAML::Node& value, const std::string& source) override; void set_rc_yaml_value(const YAML::Node& value, const std::string& source) override;
void set_rc_yaml_values(const std::map<std::string, YAML::Node>& values, void set_rc_yaml_values(
const std::vector<std::string>& sources) override; const std::map<std::string, YAML::Node>& values,
const std::vector<std::string>& sources
) override;
void set_cli_yaml_value(const YAML::Node& value) override; void set_cli_yaml_value(const YAML::Node& value) override;
void set_cli_yaml_value(const std::string& value) override; void set_cli_yaml_value(const std::string& value) override;
void set_yaml_value(const YAML::Node& value) override; void set_yaml_value(const YAML::Node& value) override;
@ -191,8 +205,10 @@ namespace mamba
void dump_json(nlohmann::json& node, const std::string& name) const override; void dump_json(nlohmann::json& node, const std::string& name) const override;
void set_rc_value(const T& value, const std::string& source); void set_rc_value(const T& value, const std::string& source);
void set_rc_values(const std::map<std::string, T>& mapped_values, void set_rc_values(
const std::vector<std::string>& sources); const std::map<std::string, T>& mapped_values,
const std::vector<std::string>& sources
);
void set_value(const T& value); void set_value(const T& value);
using cli_config_type = detail::cli_config<T>; using cli_config_type = detail::cli_config<T>;
@ -221,6 +237,7 @@ namespace mamba
class Configurable class Configurable
{ {
public: public:
template <class T> template <class T>
Configurable(const std::string& name, T* context); Configurable(const std::string& name, T* context);
@ -284,8 +301,10 @@ namespace mamba
Configurable&& set_rc_value(const T& value, const std::string& source); Configurable&& set_rc_value(const T& value, const std::string& source);
template <class T> template <class T>
Configurable&& set_rc_values(const std::map<std::string, T>& mapped_values, Configurable&& set_rc_values(
const std::vector<std::string>& sources); const std::map<std::string, T>& mapped_values,
const std::vector<std::string>& sources
);
template <class T> template <class T>
Configurable&& set_value(const T& value); Configurable&& set_value(const T& value);
@ -327,15 +346,17 @@ namespace mamba
cli_storage_type<T>& get_cli_config(); cli_storage_type<T>& get_cli_config();
Configurable&& set_rc_yaml_value(const YAML::Node& value, const std::string& source); Configurable&& set_rc_yaml_value(const YAML::Node& value, const std::string& source);
Configurable&& set_rc_yaml_values(const std::map<std::string, YAML::Node>& values, Configurable&& set_rc_yaml_values(
const std::vector<std::string>& sources); const std::map<std::string, YAML::Node>& values,
const std::vector<std::string>& sources
);
Configurable&& set_cli_yaml_value(const YAML::Node& value); Configurable&& set_cli_yaml_value(const YAML::Node& value);
Configurable&& set_cli_yaml_value(const std::string& value); Configurable&& set_cli_yaml_value(const std::string& value);
Configurable&& set_yaml_value(const YAML::Node& value); Configurable&& set_yaml_value(const YAML::Node& value);
Configurable&& set_yaml_value(const std::string& value); Configurable&& set_yaml_value(const std::string& value);
Configurable&& compute(int options = 0, Configurable&&
const ConfigurationLevel& level = ConfigurationLevel::kDefault); compute(int options = 0, const ConfigurationLevel& level = ConfigurationLevel::kDefault);
bool is_valid_serialization(const std::string& value) const; bool is_valid_serialization(const std::string& value) const;
bool is_sequence() const; bool is_sequence() const;
@ -344,6 +365,7 @@ namespace mamba
void dump_json(nlohmann::json& node, const std::string& name) const; void dump_json(nlohmann::json& node, const std::string& name) const;
private: private:
template <class T> template <class T>
detail::ConfigurableImpl<T>& get_wrapped(); detail::ConfigurableImpl<T>& get_wrapped();
@ -353,13 +375,13 @@ namespace mamba
std::unique_ptr<detail::ConfigurableImplBase> p_impl; std::unique_ptr<detail::ConfigurableImplBase> p_impl;
}; };
int const MAMBA_SHOW_CONFIG_VALUES = 1 << 0; const int MAMBA_SHOW_CONFIG_VALUES = 1 << 0;
int const MAMBA_SHOW_CONFIG_SRCS = 1 << 1; const int MAMBA_SHOW_CONFIG_SRCS = 1 << 1;
int const MAMBA_SHOW_CONFIG_DESCS = 1 << 2; const int MAMBA_SHOW_CONFIG_DESCS = 1 << 2;
int const MAMBA_SHOW_CONFIG_LONG_DESCS = 1 << 3; const int MAMBA_SHOW_CONFIG_LONG_DESCS = 1 << 3;
int const MAMBA_SHOW_CONFIG_GROUPS = 1 << 4; const int MAMBA_SHOW_CONFIG_GROUPS = 1 << 4;
int const MAMBA_SHOW_ALL_CONFIGS = 1 << 5; const int MAMBA_SHOW_ALL_CONFIGS = 1 << 5;
int const MAMBA_SHOW_ALL_RC_CONFIGS = 1 << 6; const int MAMBA_SHOW_ALL_RC_CONFIGS = 1 << 6;
/***************** /*****************
* Configuration * * Configuration *
@ -368,6 +390,7 @@ namespace mamba
class Configuration class Configuration
{ {
public: public:
static Configuration& instance(); static Configuration& instance();
std::map<std::string, Configurable>& config(); std::map<std::string, Configurable>& config();
@ -406,10 +429,12 @@ namespace mamba
void reset_configurables(); void reset_configurables();
protected: protected:
Configuration(); Configuration();
~Configuration(); ~Configuration();
protected: protected:
Configuration(const Configuration&) = delete; Configuration(const Configuration&) = delete;
Configuration& operator=(const Configuration&) = delete; Configuration& operator=(const Configuration&) = delete;
Configuration(Configuration&&) = delete; Configuration(Configuration&&) = delete;
@ -423,16 +448,15 @@ namespace mamba
void clear_rc_sources(); void clear_rc_sources();
void add_to_loading_sequence(std::vector<std::string>& seq, void
const std::string& name, add_to_loading_sequence(std::vector<std::string>& seq, const std::string& name, std::vector<std::string>&);
std::vector<std::string>&);
static YAML::Node load_rc_file(const fs::u8path& file); 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 RCConfigLevel& level);
std::vector<fs::u8path> get_existing_rc_sources( std::vector<fs::u8path>
const std::vector<fs::u8path>& possible_rc_paths); get_existing_rc_sources(const std::vector<fs::u8path>& possible_rc_paths);
std::vector<fs::u8path> m_sources; std::vector<fs::u8path> m_sources;
std::vector<fs::u8path> m_valid_sources; std::vector<fs::u8path> m_valid_sources;
@ -477,8 +501,8 @@ namespace mamba
} }
template <class T> template <class T>
void ConfigurableImpl<T>::set_rc_yaml_value(const YAML::Node& value, void
const std::string& source) ConfigurableImpl<T>::set_rc_yaml_value(const YAML::Node& value, const std::string& source)
{ {
try try
{ {
@ -494,7 +518,8 @@ namespace mamba
template <class T> template <class T>
void ConfigurableImpl<T>::set_rc_yaml_values( void ConfigurableImpl<T>::set_rc_yaml_values(
const std::map<std::string, YAML::Node>& values, const std::map<std::string, YAML::Node>& values,
const std::vector<std::string>& sources) const std::vector<std::string>& sources
)
{ {
std::map<std::string, T> converted_values; std::map<std::string, T> converted_values;
for (auto& y : values) for (auto& y : values)
@ -570,21 +595,25 @@ namespace mamba
} }
template <> template <>
inline void ConfigurableImpl<fs::u8path>::dump_json(nlohmann::json& node, inline void
const std::string& name) const ConfigurableImpl<fs::u8path>::dump_json(nlohmann::json& node, const std::string& name) const
{ {
node[name] = m_value.string(); node[name] = m_value.string();
} }
template <> template <>
inline void ConfigurableImpl<std::vector<fs::u8path>>::dump_json( inline void ConfigurableImpl<std::vector<fs::u8path>>::dump_json(
nlohmann::json& node, const std::string& name) const nlohmann::json& node,
const std::string& name
) const
{ {
std::vector<std::string> values(m_value.size()); std::vector<std::string> values(m_value.size());
std::transform(m_value.begin(), std::transform(
m_value.end(), m_value.begin(),
values.begin(), m_value.end(),
[](const auto& value) { return value.string(); }); values.begin(),
[](const auto& value) { return value.string(); }
);
node[name] = values; node[name] = values;
} }
@ -597,8 +626,10 @@ namespace mamba
} }
template <class T> template <class T>
void ConfigurableImpl<T>::set_rc_values(const std::map<std::string, T>& mapped_values, void ConfigurableImpl<T>::set_rc_values(
const std::vector<std::string>& sources) const std::map<std::string, T>& mapped_values,
const std::vector<std::string>& sources
)
{ {
assert(mapped_values.size() == sources.size()); assert(mapped_values.size() == sources.size());
this->m_rc_sources.insert(this->m_rc_sources.end(), sources.begin(), sources.end()); this->m_rc_sources.insert(this->m_rc_sources.end(), sources.begin(), sources.end());
@ -620,14 +651,20 @@ namespace mamba
bool force_compute = options & MAMBA_CONF_FORCE_COMPUTE; bool force_compute = options & MAMBA_CONF_FORCE_COMPUTE;
if (force_compute) if (force_compute)
{
LOG_TRACE << "Update configurable '" << this->m_name << "'"; LOG_TRACE << "Update configurable '" << this->m_name << "'";
}
else else
{
LOG_TRACE << "Compute configurable '" << this->m_name << "'"; LOG_TRACE << "Compute configurable '" << this->m_name << "'";
}
if (!force_compute if (!force_compute && (Configuration::instance().is_loading() && (m_compute_counter > 0)))
&& (Configuration::instance().is_loading() && (m_compute_counter > 0))) {
throw std::runtime_error("Multiple computation of '" + m_name throw std::runtime_error(
+ "' detected during loading sequence."); "Multiple computation of '" + m_name + "' detected during loading sequence."
);
}
auto& ctx = Context::instance(); auto& ctx = Context::instance();
m_sources.clear(); m_sources.clear();
@ -655,7 +692,8 @@ namespace mamba
try try
{ {
m_values.insert( m_values.insert(
{ env_var, detail::Source<T>::deserialize(env_var_value.value()) }); { env_var, detail::Source<T>::deserialize(env_var_value.value()) }
);
m_sources.push_back(env_var); m_sources.push_back(env_var);
} }
catch (const YAML::Exception& e) catch (const YAML::Exception& e)
@ -689,7 +727,9 @@ namespace mamba
} }
if (!m_sources.empty()) if (!m_sources.empty())
{
detail::Source<T>::merge(m_values, m_sources, m_value, m_source); detail::Source<T>::merge(m_values, m_sources, m_value, m_source);
}
else else
{ {
m_value = m_default_value; m_value = m_default_value;
@ -697,7 +737,9 @@ namespace mamba
} }
if (!hook_disabled && (p_post_merge_hook != NULL)) if (!hook_disabled && (p_post_merge_hook != NULL))
{
p_post_merge_hook(m_value); p_post_merge_hook(m_value);
}
++m_compute_counter; ++m_compute_counter;
if (p_context != nullptr) if (p_context != nullptr)
@ -706,7 +748,9 @@ namespace mamba
} }
if (p_post_ctx_hook != nullptr) if (p_post_ctx_hook != nullptr)
{
p_post_ctx_hook(); p_post_ctx_hook();
}
} }
} }
@ -747,7 +791,9 @@ namespace mamba
T& Configurable::value() T& Configurable::value()
{ {
if (Configuration::instance().is_loading() && p_impl->m_compute_counter == 0) if (Configuration::instance().is_loading() && p_impl->m_compute_counter == 0)
{
throw std::runtime_error("Using '" + name() + "' value without previous computation."); throw std::runtime_error("Using '" + name() + "' value without previous computation.");
}
return get_wrapped<T>().m_value; return get_wrapped<T>().m_value;
} }
@ -755,7 +801,9 @@ namespace mamba
const T& Configurable::cli_value() const const T& Configurable::cli_value() const
{ {
if (!cli_configured()) if (!cli_configured())
{
throw std::runtime_error("Trying to get unset CLI value of '" + name() + "'"); throw std::runtime_error("Trying to get unset CLI value of '" + name() + "'");
}
return get_wrapped<T>().m_cli_config.value(); return get_wrapped<T>().m_cli_config.value();
} }
@ -774,8 +822,10 @@ namespace mamba
} }
template <class T> template <class T>
Configurable&& Configurable::set_rc_values(const std::map<std::string, T>& mapped_values, Configurable&& Configurable::set_rc_values(
const std::vector<std::string>& sources) const std::map<std::string, T>& mapped_values,
const std::vector<std::string>& sources
)
{ {
get_wrapped<T>().set_rc_values(mapped_values, sources); get_wrapped<T>().set_rc_values(mapped_values, sources);
return std::move(*this); return std::move(*this);
@ -886,8 +936,7 @@ namespace mamba
{ {
if (!allow_redefinition) if (!allow_redefinition)
{ {
throw std::runtime_error("Redefinition of configurable '" + name throw std::runtime_error("Redefinition of configurable '" + name + "' not allowed.");
+ "' not allowed.");
} }
} }

View File

@ -61,10 +61,12 @@ namespace mamba
return std::vector<std::string>({ "default" }); return std::vector<std::string>({ "default" });
}; };
static void merge(const std::map<std::string, T>& values, static void merge(
const std::vector<std::string>& sources, const std::map<std::string, T>& values,
T& value, const std::vector<std::string>& sources,
std::vector<std::string>& source); T& value,
std::vector<std::string>& source
);
static T deserialize(const std::string& value); static T deserialize(const std::string& value);
@ -79,10 +81,12 @@ namespace mamba
return std::vector<std::string>(init.size(), "default"); return std::vector<std::string>(init.size(), "default");
}; };
static void merge(const std::map<std::string, std::vector<T>>& values, static void merge(
const std::vector<std::string>& sources, const std::map<std::string, std::vector<T>>& values,
std::vector<T>& value, const std::vector<std::string>& sources,
std::vector<std::string>& source); std::vector<T>& value,
std::vector<std::string>& source
);
static std::vector<T> deserialize(const std::string& value); static std::vector<T> deserialize(const std::string& value);
@ -94,10 +98,12 @@ namespace mamba
*************************/ *************************/
template <class T> template <class T>
void Source<T>::merge(const std::map<std::string, T>& values, void Source<T>::merge(
const std::vector<std::string>& sources, const std::map<std::string, T>& values,
T& value, const std::vector<std::string>& sources,
std::vector<std::string>& source) T& value,
std::vector<std::string>& source
)
{ {
source = sources; source = sources;
value = values.at(sources.front()); value = values.at(sources.front());
@ -123,10 +129,12 @@ namespace mamba
} }
template <class T> template <class T>
void Source<std::vector<T>>::merge(const std::map<std::string, std::vector<T>>& values, void Source<std::vector<T>>::merge(
const std::vector<std::string>& sources, const std::map<std::string, std::vector<T>>& values,
std::vector<T>& value, const std::vector<std::string>& sources,
std::vector<std::string>& source) std::vector<T>& value,
std::vector<std::string>& source
)
{ {
value.clear(); value.clear();
source.clear(); source.clear();
@ -234,7 +242,8 @@ namespace YAML
else else
{ {
throw std::runtime_error( throw std::runtime_error(
"Invalid 'VerificationLevel', should be in {'enabled', 'warn', 'disabled'}"); "Invalid 'VerificationLevel', should be in {'enabled', 'warn', 'disabled'}"
);
} }
return true; return true;
@ -318,10 +327,13 @@ namespace YAML
struct convert<mamba::log_level> struct convert<mamba::log_level>
{ {
private: private:
static inline const std::array<std::string, 7> log_level_names
= { "trace", "debug", "info", "warning", "error", "critical", "off" }; inline static const std::array<std::string, 7> log_level_names = {
"trace", "debug", "info", "warning", "error", "critical", "off"
};
public: public:
static Node encode(const mamba::log_level& rhs) static Node encode(const mamba::log_level& rhs)
{ {
return Node(log_level_names[static_cast<size_t>(rhs)]); return Node(log_level_names[static_cast<size_t>(rhs)]);
@ -337,9 +349,8 @@ namespace YAML
return true; return true;
} }
LOG_ERROR LOG_ERROR << "Invalid log level, should be in {'critical', 'error', 'warning', 'info', 'debug', 'trace', 'off'} but is '"
<< "Invalid log level, should be in {'critical', 'error', 'warning', 'info', 'debug', 'trace', 'off'} but is '" << name << "'";
<< name << "'";
return false; return false;
} }
}; };

View File

@ -3,24 +3,24 @@
namespace mamba namespace mamba
{ {
int const MAMBA_NO_PREFIX_CHECK = 1 << 0; const int MAMBA_NO_PREFIX_CHECK = 1 << 0;
int const MAMBA_ALLOW_EXISTING_PREFIX = 1 << 1; const int MAMBA_ALLOW_EXISTING_PREFIX = 1 << 1;
int const MAMBA_ALLOW_MISSING_PREFIX = 1 << 2; const int MAMBA_ALLOW_MISSING_PREFIX = 1 << 2;
int const MAMBA_ALLOW_NOT_ENV_PREFIX = 1 << 3; const int MAMBA_ALLOW_NOT_ENV_PREFIX = 1 << 3;
int const MAMBA_EXPECT_EXISTING_PREFIX = 1 << 4; const int MAMBA_EXPECT_EXISTING_PREFIX = 1 << 4;
int const MAMBA_NOT_ALLOW_EXISTING_PREFIX = 0; const int MAMBA_NOT_ALLOW_EXISTING_PREFIX = 0;
int const MAMBA_NOT_ALLOW_MISSING_PREFIX = 0; const int MAMBA_NOT_ALLOW_MISSING_PREFIX = 0;
int const MAMBA_NOT_ALLOW_NOT_ENV_PREFIX = 0; const int MAMBA_NOT_ALLOW_NOT_ENV_PREFIX = 0;
int const MAMBA_NOT_EXPECT_EXISTING_PREFIX = 0; const int MAMBA_NOT_EXPECT_EXISTING_PREFIX = 0;
int const MAMBA_CONF_FORCE_COMPUTE = 1 << 0; const int MAMBA_CONF_FORCE_COMPUTE = 1 << 0;
int const MAMBA_CONF_DISABLE_HOOK = 1 << 1; const int MAMBA_CONF_DISABLE_HOOK = 1 << 1;
int const MAMBA_FORCE = 1 << 0; const int MAMBA_FORCE = 1 << 0;
int const MAMBA_REMOVE_FORCE = MAMBA_FORCE; const int MAMBA_REMOVE_FORCE = MAMBA_FORCE;
int const MAMBA_REMOVE_PRUNE = 1 << 1; const int MAMBA_REMOVE_PRUNE = 1 << 1;
int const MAMBA_REMOVE_ALL = 1 << 2; const int MAMBA_REMOVE_ALL = 1 << 2;
} }
#endif #endif

View File

@ -7,6 +7,9 @@
#ifndef MAMBA_API_CREATE_HPP #ifndef MAMBA_API_CREATE_HPP
#define MAMBA_API_CREATE_HPP #define MAMBA_API_CREATE_HPP
#include <string>
#include "mamba/core/mamba_fs.hpp"
namespace mamba namespace mamba
{ {

View File

@ -7,12 +7,12 @@
#ifndef MAMBA_API_INFO_HPP #ifndef MAMBA_API_INFO_HPP
#define MAMBA_API_INFO_HPP #define MAMBA_API_INFO_HPP
#include "mamba/core/mamba_fs.hpp"
#include "mamba/core/util.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
#include "mamba/core/mamba_fs.hpp"
#include "mamba/core/util.hpp"
namespace mamba namespace mamba
{ {
@ -21,14 +21,16 @@ namespace mamba
std::string version(); std::string version();
std::string banner(); std::string banner();
const std::string mamba_banner = std::string(strip(R"MAMBARAW( const std::string mamba_banner = std::string(strip(
R"MAMBARAW(
__ __
_____ ___ ____ _____ ___ / /_ ____ _ _____ ___ ____ _____ ___ / /_ ____ _
/ __ `__ \/ __ `/ __ `__ \/ __ \/ __ `/ / __ `__ \/ __ `/ __ `__ \/ __ \/ __ `/
/ / / / / / /_/ / / / / / / /_/ / /_/ / / / / / / / /_/ / / / / / / /_/ / /_/ /
/_/ /_/ /_/\__,_/_/ /_/ /_/_.___/\__,_/ /_/ /_/ /_/\__,_/_/ /_/ /_/_.___/\__,_/
)MAMBARAW", )MAMBARAW",
"\n")); "\n"
));
namespace detail namespace detail
{ {

View File

@ -7,6 +7,12 @@
#ifndef MAMBA_API_INSTALL_HPP #ifndef MAMBA_API_INSTALL_HPP
#define MAMBA_API_INSTALL_HPP #define MAMBA_API_INSTALL_HPP
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
#include <yaml-cpp/yaml.h>
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/mamba_fs.hpp" #include "mamba/core/mamba_fs.hpp"
#include "mamba/core/package_cache.hpp" #include "mamba/core/package_cache.hpp"
@ -15,27 +21,24 @@
#include "mamba/core/repo.hpp" #include "mamba/core/repo.hpp"
#include "mamba/core/solver.hpp" #include "mamba/core/solver.hpp"
#include <yaml-cpp/yaml.h>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
namespace mamba namespace mamba
{ {
void install(); void install();
void install_specs(const std::vector<std::string>& specs, void install_specs(
bool create_env = false, const std::vector<std::string>& specs,
int solver_flag = SOLVER_INSTALL, bool create_env = false,
int is_retry = 0); int solver_flag = SOLVER_INSTALL,
int is_retry = 0
);
void install_explicit_specs(const std::vector<std::string>& specs, bool create_env = false); void install_explicit_specs(const std::vector<std::string>& specs, bool create_env = false);
void install_lockfile_specs(const std::string& lockfile_specs, void install_lockfile_specs(
const std::vector<std::string>& categories, const std::string& lockfile_specs,
bool create_env = false); const std::vector<std::string>& categories,
bool create_env = false
);
namespace detail namespace detail
{ {
@ -69,8 +72,8 @@ namespace mamba
yaml_file_contents read_yaml_file(fs::u8path yaml_file); yaml_file_contents read_yaml_file(fs::u8path yaml_file);
std::tuple<std::vector<PackageInfo>, std::vector<MatchSpec>> parse_urls_to_package_info( std::tuple<std::vector<PackageInfo>, std::vector<MatchSpec>>
const std::vector<std::string>& urls); parse_urls_to_package_info(const std::vector<std::string>& urls);
inline void to_json(nlohmann::json&, const other_pkg_mgr_spec&) inline void to_json(nlohmann::json&, const other_pkg_mgr_spec&)
{ {

View File

@ -8,8 +8,6 @@
namespace mamba namespace mamba
{ {
void repoquery(QueryType type, void
QueryResultFormat format, repoquery(QueryType type, QueryResultFormat format, bool use_local, const std::string& query);
bool use_local,
const std::string& query);
} }

View File

@ -7,20 +7,22 @@
#ifndef MAMBA_API_SHELL_HPP #ifndef MAMBA_API_SHELL_HPP
#define MAMBA_API_SHELL_HPP #define MAMBA_API_SHELL_HPP
#include "mamba/core/mamba_fs.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
#include "mamba/core/mamba_fs.hpp"
namespace mamba namespace mamba
{ {
void detect_shell(std::string& shell_type); void detect_shell(std::string& shell_type);
void shell(const std::string& action, void shell(
std::string& shell_type, const std::string& action,
const std::string& prefix = "", std::string& shell_type,
bool stack = false); const std::string& prefix = "",
bool stack = false
);
} }
#endif #endif

View File

@ -7,12 +7,12 @@
#ifndef MAMBA_API_UPDATE_HPP #ifndef MAMBA_API_UPDATE_HPP
#define MAMBA_API_UPDATE_HPP #define MAMBA_API_UPDATE_HPP
#include "mamba/core/mamba_fs.hpp"
#include "mamba/core/query.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
#include "mamba/core/mamba_fs.hpp"
#include "mamba/core/query.hpp"
namespace mamba namespace mamba
{ {

View File

@ -38,6 +38,7 @@ namespace mamba
class Activator class Activator
{ {
public: public:
virtual ~Activator() = default; virtual ~Activator() = default;
Activator(const Activator&) = delete; Activator(const Activator&) = delete;
@ -46,9 +47,8 @@ namespace mamba
Activator& operator=(Activator&&) = delete; Activator& operator=(Activator&&) = delete;
virtual std::string script(const EnvironmentTransform& env) = 0; virtual std::string script(const EnvironmentTransform& env) = 0;
virtual std::pair<std::string, std::string> update_prompt( virtual std::pair<std::string, std::string>
const std::string& conda_prompt_modifier) update_prompt(const std::string& conda_prompt_modifier) = 0;
= 0;
virtual std::string shell_extension() = 0; virtual std::string shell_extension() = 0;
virtual std::string shell() = 0; virtual std::string shell() = 0;
@ -56,23 +56,26 @@ namespace mamba
std::vector<fs::u8path> get_deactivate_scripts(const fs::u8path& prefix); std::vector<fs::u8path> get_deactivate_scripts(const fs::u8path& prefix);
std::string get_default_env(const fs::u8path& prefix); std::string get_default_env(const fs::u8path& prefix);
std::vector<std::pair<std::string, std::string>> get_environment_vars( std::vector<std::pair<std::string, std::string>>
const fs::u8path& prefix); get_environment_vars(const fs::u8path& prefix);
std::string get_prompt_modifier(const fs::u8path& prefix, std::string get_prompt_modifier(
const std::string& conda_default_env, const fs::u8path& prefix,
int old_conda_shlvl); const std::string& conda_default_env,
int old_conda_shlvl
);
std::vector<fs::u8path> get_clean_dirs(); std::vector<fs::u8path> get_clean_dirs();
std::string add_prefix_to_path(const fs::u8path& prefix, int old_conda_shlvl); std::string add_prefix_to_path(const fs::u8path& prefix, int old_conda_shlvl);
std::string replace_prefix_in_path(const fs::u8path& old_prefix, std::string
const fs::u8path& new_prefix); replace_prefix_in_path(const fs::u8path& old_prefix, const fs::u8path& new_prefix);
std::string remove_prefix_from_path(const fs::u8path& prefix); std::string remove_prefix_from_path(const fs::u8path& prefix);
void get_export_unset_vars( void get_export_unset_vars(
EnvironmentTransform& envt, EnvironmentTransform& envt,
const std::vector<std::pair<std::string, std::string>>& to_export); const std::vector<std::pair<std::string, std::string>>& to_export
);
EnvironmentTransform build_reactivate(); EnvironmentTransform build_reactivate();
EnvironmentTransform build_deactivate(); EnvironmentTransform build_deactivate();
@ -89,6 +92,7 @@ namespace mamba
std::string hook(const std::string& shell_type); std::string hook(const std::string& shell_type);
protected: protected:
Activator(); Activator();
bool m_stack = false; bool m_stack = false;
@ -100,12 +104,13 @@ namespace mamba
class PosixActivator : public Activator class PosixActivator : public Activator
{ {
public: public:
PosixActivator() = default; PosixActivator() = default;
virtual ~PosixActivator() = default; virtual ~PosixActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override; std::string script(const EnvironmentTransform& env_transform) override;
std::pair<std::string, std::string> update_prompt( std::pair<std::string, std::string>
const std::string& conda_prompt_modifier) override; update_prompt(const std::string& conda_prompt_modifier) override;
std::string shell_extension() override; std::string shell_extension() override;
std::string shell() override; std::string shell() override;
@ -117,12 +122,13 @@ namespace mamba
class CshActivator : public Activator class CshActivator : public Activator
{ {
public: public:
CshActivator() = default; CshActivator() = default;
virtual ~CshActivator() = default; virtual ~CshActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override; std::string script(const EnvironmentTransform& env_transform) override;
std::pair<std::string, std::string> update_prompt( std::pair<std::string, std::string>
const std::string& conda_prompt_modifier) override; update_prompt(const std::string& conda_prompt_modifier) override;
std::string shell_extension() override; std::string shell_extension() override;
std::string shell() override; std::string shell() override;
@ -134,12 +140,13 @@ namespace mamba
class CmdExeActivator : public Activator class CmdExeActivator : public Activator
{ {
public: public:
CmdExeActivator() = default; CmdExeActivator() = default;
virtual ~CmdExeActivator() = default; virtual ~CmdExeActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override; std::string script(const EnvironmentTransform& env_transform) override;
std::pair<std::string, std::string> update_prompt( std::pair<std::string, std::string>
const std::string& conda_prompt_modifier) override; update_prompt(const std::string& conda_prompt_modifier) override;
std::string shell_extension() override; std::string shell_extension() override;
std::string shell() override; std::string shell() override;
@ -151,12 +158,13 @@ namespace mamba
class PowerShellActivator : public Activator class PowerShellActivator : public Activator
{ {
public: public:
PowerShellActivator() = default; PowerShellActivator() = default;
virtual ~PowerShellActivator() = default; virtual ~PowerShellActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override; std::string script(const EnvironmentTransform& env_transform) override;
std::pair<std::string, std::string> update_prompt( std::pair<std::string, std::string>
const std::string& conda_prompt_modifier) override; update_prompt(const std::string& conda_prompt_modifier) override;
std::string shell_extension() override; std::string shell_extension() override;
std::string shell() override; std::string shell() override;
@ -168,12 +176,13 @@ namespace mamba
class XonshActivator : public Activator class XonshActivator : public Activator
{ {
public: public:
XonshActivator() = default; XonshActivator() = default;
virtual ~XonshActivator() = default; virtual ~XonshActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override; std::string script(const EnvironmentTransform& env_transform) override;
std::pair<std::string, std::string> update_prompt( std::pair<std::string, std::string>
const std::string& conda_prompt_modifier) override; update_prompt(const std::string& conda_prompt_modifier) override;
std::string shell_extension() override; std::string shell_extension() override;
std::string shell() override; std::string shell() override;
@ -185,12 +194,13 @@ namespace mamba
class FishActivator : public Activator class FishActivator : public Activator
{ {
public: public:
FishActivator() = default; FishActivator() = default;
virtual ~FishActivator() = default; virtual ~FishActivator() = default;
std::string script(const EnvironmentTransform& env_transform) override; std::string script(const EnvironmentTransform& env_transform) override;
std::pair<std::string, std::string> update_prompt( std::pair<std::string, std::string>
const std::string& conda_prompt_modifier) override; update_prompt(const std::string& conda_prompt_modifier) override;
std::string shell_extension() override; std::string shell_extension() override;
std::string shell() override; std::string shell() override;

View File

@ -7,20 +7,21 @@
#ifndef MAMBA_CORE_CHANNEL_HPP #ifndef MAMBA_CORE_CHANNEL_HPP
#define MAMBA_CORE_CHANNEL_HPP #define MAMBA_CORE_CHANNEL_HPP
#include "mamba/core/package_cache.hpp"
#include "mamba/core/validate.hpp"
#include <map> #include <map>
#include <optional> #include <optional>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "mamba/core/package_cache.hpp"
#include "mamba/core/validate.hpp"
namespace mamba namespace mamba
{ {
class Channel class Channel
{ {
public: public:
const std::string& scheme() const; const std::string& scheme() const;
const std::string& location() const; const std::string& location() const;
const std::string& name() const; const std::string& name() const;
@ -34,18 +35,21 @@ namespace mamba
std::string base_url() const; std::string base_url() const;
std::string platform_url(std::string platform, bool with_credential = true) const; std::string platform_url(std::string platform, bool with_credential = true) const;
// The pairs consist of (platform,url) // The pairs consist of (platform,url)
std::vector<std::pair<std::string, std::string>> platform_urls(bool with_credential std::vector<std::pair<std::string, std::string>>
= true) const; platform_urls(bool with_credential = true) const;
std::vector<std::string> urls(bool with_credential = true) const; std::vector<std::string> urls(bool with_credential = true) const;
private: private:
Channel(const std::string& scheme,
const std::string& location, Channel(
const std::string& name, const std::string& scheme,
const std::optional<std::string>& auth = {}, const std::string& location,
const std::optional<std::string>& token = {}, const std::string& name,
const std::optional<std::string>& package_filename = {}, const std::optional<std::string>& auth = {},
const std::optional<std::string>& canonical_name = {}); const std::optional<std::string>& token = {},
const std::optional<std::string>& package_filename = {},
const std::optional<std::string>& canonical_name = {}
);
std::string m_scheme; std::string m_scheme;
std::string m_location; std::string m_location;

View File

@ -16,25 +16,31 @@ namespace mamba
class ChannelBuilder class ChannelBuilder
{ {
public: public:
static Channel make_simple_channel(const Channel& channel_alias,
const std::string& channel_url, static Channel make_simple_channel(
const std::string& channel_name = "", const Channel& channel_alias,
const std::string& multi_name = ""); const std::string& channel_url,
const std::string& channel_name = "",
const std::string& multi_name = ""
);
static const Channel& make_cached_channel(const std::string& value); static const Channel& make_cached_channel(const std::string& value);
static void clear_cache(); static void clear_cache();
private: private:
static ChannelCache& get_cache(); static ChannelCache& get_cache();
static Channel from_url(const std::string& url); static Channel from_url(const std::string& url);
static Channel from_name(const std::string& name); static Channel from_name(const std::string& name);
static Channel from_value(const std::string& value); static Channel from_value(const std::string& value);
static Channel from_alias(const std::string& scheme, static Channel from_alias(
const std::string& location, const std::string& scheme,
const std::optional<std::string>& auth = {}, const std::string& location,
const std::optional<std::string>& token = {}); const std::optional<std::string>& auth = {},
const std::optional<std::string>& token = {}
);
friend class ChannelContext; friend class ChannelContext;
}; };
@ -42,6 +48,7 @@ namespace mamba
class ChannelContext class ChannelContext
{ {
public: public:
using channel_list = std::vector<std::string>; using channel_list = std::vector<std::string>;
using channel_map = std::map<std::string, Channel>; using channel_map = std::map<std::string, Channel>;
using multichannel_map = std::map<std::string, std::vector<std::string>>; using multichannel_map = std::map<std::string, std::vector<std::string>>;
@ -62,10 +69,12 @@ namespace mamba
const channel_list& get_whitelist_channels() const; const channel_list& get_whitelist_channels() const;
protected: protected:
ChannelContext(); ChannelContext();
~ChannelContext(); ~ChannelContext();
private: private:
Channel build_channel_alias(); Channel build_channel_alias();
void init_custom_channels(); void init_custom_channels();

View File

@ -8,15 +8,15 @@
#define MAMBA_CORE_CONTEXT_HPP #define MAMBA_CORE_CONTEXT_HPP
#include <map> #include <map>
#include <string>
#include <vector>
#include <optional> #include <optional>
#include <regex> #include <regex>
#include <string>
#include <vector>
#include "mamba/core/common_types.hpp" #include "mamba/core/common_types.hpp"
#include "mamba/core/mamba_fs.hpp" #include "mamba/core/mamba_fs.hpp"
#include "mamba/core/tasksync.hpp"
#include "mamba/core/palette.hpp" #include "mamba/core/palette.hpp"
#include "mamba/core/tasksync.hpp"
#include "mamba/version.hpp" #include "mamba/version.hpp"
#define ROOT_ENV_NAME "base" #define ROOT_ENV_NAME "base"
@ -113,6 +113,7 @@ namespace mamba
class Context class Context
{ {
public: public:
std::string caller_version = ""; std::string caller_version = "";
std::string conda_version = "3.8.0"; std::string conda_version = "3.8.0";
std::string current_command = "mamba"; std::string current_command = "mamba";
@ -226,7 +227,8 @@ namespace mamba
"https://repo.anaconda.com/pkgs/r", "https://repo.anaconda.com/pkgs/r",
"https://repo.anaconda.com/pkgs/msys2" "https://repo.anaconda.com/pkgs/msys2"
#else #else
"https://repo.anaconda.com/pkgs/main", "https://repo.anaconda.com/pkgs/r" "https://repo.anaconda.com/pkgs/main",
"https://repo.anaconda.com/pkgs/r"
#endif #endif
}; };
@ -261,11 +263,13 @@ namespace mamba
void dump_backtrace_no_guards(); void dump_backtrace_no_guards();
protected: protected:
Context(); Context();
~Context(); ~Context();
private: private:
void load_authentication_info(); void load_authentication_info();
std::map<std::string, AuthenticationInfo> m_authentication_info; std::map<std::string, AuthenticationInfo> m_authentication_info;
bool m_authentication_infos_loaded = false; bool m_authentication_infos_loaded = false;

View File

@ -8,16 +8,16 @@
#ifndef MAMBA_CORE_ENVIRONMENT_LOCKFILE_HPP #ifndef MAMBA_CORE_ENVIRONMENT_LOCKFILE_HPP
#define MAMBA_CORE_ENVIRONMENT_LOCKFILE_HPP #define MAMBA_CORE_ENVIRONMENT_LOCKFILE_HPP
#include <optional>
#include <string> #include <string>
#include <typeindex> #include <typeindex>
#include <optional>
#include <unordered_map> #include <unordered_map>
#include <tl/expected.hpp> #include <tl/expected.hpp>
#include "error_handling.hpp"
#include "fsutil.hpp" #include "fsutil.hpp"
#include "package_info.hpp" #include "package_info.hpp"
#include "error_handling.hpp"
namespace mamba namespace mamba
{ {
@ -43,9 +43,11 @@ namespace mamba
} }
template <typename StringT> template <typename StringT>
static mamba_error make_error(file_parsing_error_code error_code, static mamba_error make_error(
StringT&& msg, file_parsing_error_code error_code,
std::optional<std::type_index> yaml_error_type = std::nullopt) StringT&& msg,
std::optional<std::type_index> yaml_error_type = std::nullopt
)
{ {
return mamba_error{ std::forward<StringT>(msg), return mamba_error{ std::forward<StringT>(msg),
mamba_error_code::env_lockfile_parsing_failed, mamba_error_code::env_lockfile_parsing_failed,
@ -56,6 +58,7 @@ namespace mamba
class EnvironmentLockFile class EnvironmentLockFile
{ {
public: public:
struct Channel struct Channel
{ {
std::string url; std::string url;
@ -85,9 +88,9 @@ namespace mamba
{ {
} }
std::vector<PackageInfo> get_packages_for(std::string_view category, std::vector<PackageInfo>
std::string_view platform, get_packages_for(std::string_view category, std::string_view platform, std::string_view manager)
std::string_view manager) const; const;
const std::vector<Package>& get_all_packages() const const std::vector<Package>& get_all_packages() const
{ {
@ -99,14 +102,15 @@ namespace mamba
} }
private: private:
Meta metadata; Meta metadata;
std::vector<Package> packages; std::vector<Package> packages;
}; };
/// Read an environment lock YAML file and returns it's structured content or an error if /// Read an environment lock YAML file and returns it's structured content or an error if
/// failed. /// failed.
tl::expected<EnvironmentLockFile, mamba_error> read_environment_lockfile( tl::expected<EnvironmentLockFile, mamba_error>
const fs::u8path& lockfile_location); read_environment_lockfile(const fs::u8path& lockfile_location);
/// Returns `true` if the filename matches names of files which should be interpreted as conda /// Returns `true` if the filename matches names of files which should be interpreted as conda

View File

@ -7,11 +7,11 @@
#ifndef MAMBA_CORE_ENVIRONMENT_HPP #ifndef MAMBA_CORE_ENVIRONMENT_HPP
#define MAMBA_CORE_ENVIRONMENT_HPP #define MAMBA_CORE_ENVIRONMENT_HPP
#include <map>
#include <cstdlib>
#include <cassert> #include <cassert>
#include <string_view> #include <cstdlib>
#include <map>
#include <optional> #include <optional>
#include <string_view>
#include "mamba_fs.hpp" #include "mamba_fs.hpp"
@ -20,11 +20,11 @@
#endif #endif
#ifndef _WIN32 #ifndef _WIN32
#include <sys/utsname.h>
#include <wordexp.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h> #include <pwd.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <wordexp.h>
extern "C" extern "C"
{ {
@ -36,7 +36,7 @@ namespace mamba
{ {
namespace env namespace env
{ {
constexpr inline const char* pathsep() inline constexpr const char* pathsep()
{ {
#ifdef _WIN32 #ifdef _WIN32
return ";"; return ";";

View File

@ -7,8 +7,8 @@
#ifndef MAMBA_CORE_ENVIRONMENT_MANAGER #ifndef MAMBA_CORE_ENVIRONMENT_MANAGER
#define MAMBA_CORE_ENVIRONMENT_MANAGER #define MAMBA_CORE_ENVIRONMENT_MANAGER
#include <string>
#include <set> #include <set>
#include <string>
#include "fsutil.hpp" #include "fsutil.hpp"
@ -21,13 +21,15 @@ namespace mamba
class EnvironmentsManager class EnvironmentsManager
{ {
public: public:
void register_env(const fs::u8path& location); void register_env(const fs::u8path& location);
void unregister_env(const fs::u8path& location); void unregister_env(const fs::u8path& location);
std::set<fs::u8path> list_all_known_prefixes(); std::set<fs::u8path> list_all_known_prefixes();
private: private:
std::set<std::string> clean_environments_txt(const fs::u8path& env_txt_file,
const fs::u8path& location); 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); std::string remove_trailing_slash(std::string p);
fs::u8path get_environments_txt_file(const fs::u8path& home) const; fs::u8path get_environments_txt_file(const fs::u8path& home) const;
}; };

View File

@ -36,6 +36,7 @@ namespace mamba
class mamba_error : public std::runtime_error class mamba_error : public std::runtime_error
{ {
public: public:
using base_type = std::runtime_error; using base_type = std::runtime_error;
mamba_error(const std::string& msg, mamba_error_code ec); mamba_error(const std::string& msg, mamba_error_code ec);
@ -47,6 +48,7 @@ namespace mamba
const std::any& data() const noexcept; const std::any& data() const noexcept;
private: private:
mamba_error_code m_error_code; mamba_error_code m_error_code;
std::any m_data; std::any m_data;
}; };
@ -54,6 +56,7 @@ namespace mamba
class mamba_aggregated_error : public mamba_error class mamba_aggregated_error : public mamba_error
{ {
public: public:
using base_type = mamba_error; using base_type = mamba_error;
using error_list_t = std::vector<mamba_error>; using error_list_t = std::vector<mamba_error>;
@ -62,9 +65,10 @@ namespace mamba
const char* what() const noexcept override; const char* what() const noexcept override;
private: private:
error_list_t m_error_list; error_list_t m_error_list;
mutable std::string m_aggregated_message; mutable std::string m_aggregated_message;
constexpr static const char* m_base_message = "Multiple errors occured:\n"; static constexpr const char* m_base_message = "Multiple errors occured:\n";
}; };
/******************************** /********************************
@ -75,6 +79,7 @@ namespace mamba
class expected_ref_wrapper : private tl::expected<std::reference_wrapper<T>, E> class expected_ref_wrapper : private tl::expected<std::reference_wrapper<T>, E>
{ {
public: public:
using value_type = T; using value_type = T;
using self_type = expected_ref_wrapper<T, E>; using self_type = expected_ref_wrapper<T, E>;
using reference = std::reference_wrapper<T>; using reference = std::reference_wrapper<T>;
@ -246,8 +251,8 @@ namespace mamba
} }
template <class T1, class E1, class T2, class E2> template <class T1, class E1, class T2, class E2>
constexpr bool operator==(const expected_ref_wrapper<T1, E1>& x, constexpr bool
const expected_ref_wrapper<T2, E2>& y) operator==(const expected_ref_wrapper<T1, E1>& x, const expected_ref_wrapper<T2, E2>& y)
{ {
using base_type1 = typename expected_ref_wrapper<T1, E1>::base_type; using base_type1 = typename expected_ref_wrapper<T1, E1>::base_type;
using base_type2 = typename expected_ref_wrapper<T2, E2>::base_type; using base_type2 = typename expected_ref_wrapper<T2, E2>::base_type;

View File

@ -7,11 +7,11 @@
#ifndef MAMBA_CORE_EXECUTION_HPP #ifndef MAMBA_CORE_EXECUTION_HPP
#define MAMBA_CORE_EXECUTION_HPP #define MAMBA_CORE_EXECUTION_HPP
#include <vector>
#include <future>
#include <thread>
#include <atomic> #include <atomic>
#include <future>
#include <mutex> #include <mutex>
#include <thread>
#include <vector>
namespace mamba namespace mamba
@ -33,6 +33,7 @@ namespace mamba
class MainExecutor class MainExecutor
{ {
public: public:
// Set itself as the main executor. // Set itself as the main executor.
// Throws `MainExecutorError` if another instance already exists. // Throws `MainExecutorError` if another instance already exists.
MainExecutor(); MainExecutor();
@ -65,7 +66,9 @@ namespace mamba
void schedule(Task&& task, Args&&... args) void schedule(Task&& task, Args&&... args)
{ {
if (!is_open) if (!is_open)
{
return; return;
}
std::scoped_lock lock{ threads_mutex }; std::scoped_lock lock{ threads_mutex };
if (is_open) // Double check necessary for correctness if (is_open) // Double check necessary for correctness
@ -84,7 +87,9 @@ namespace mamba
void take_ownership(std::thread thread) void take_ownership(std::thread thread)
{ {
if (!thread.joinable() || !is_open) if (!thread.joinable() || !is_open)
{
return; return;
}
std::scoped_lock lock{ threads_mutex }; std::scoped_lock lock{ threads_mutex };
if (is_open) // Double check necessary for correctness if (is_open) // Double check necessary for correctness
@ -105,13 +110,17 @@ namespace mamba
{ {
bool expected = true; bool expected = true;
if (!is_open.compare_exchange_strong(expected, false)) if (!is_open.compare_exchange_strong(expected, false))
{
return; return;
}
invoke_close_handlers(); invoke_close_handlers();
std::scoped_lock lock{ threads_mutex }; std::scoped_lock lock{ threads_mutex };
for (auto&& t : threads) for (auto&& t : threads)
{
t.join(); t.join();
}
threads.clear(); threads.clear();
} }
@ -120,7 +129,9 @@ namespace mamba
void on_close(on_close_handler handler) void on_close(on_close_handler handler)
{ {
if (!is_open) if (!is_open)
{
return; return;
}
std::scoped_lock lock{ handlers_mutex }; std::scoped_lock lock{ handlers_mutex };
if (is_open) // Double check needed to avoid adding new handles while closing. if (is_open) // Double check needed to avoid adding new handles while closing.
@ -130,6 +141,7 @@ namespace mamba
} }
private: private:
std::atomic<bool> is_open{ true }; std::atomic<bool> is_open{ true };
std::vector<std::thread> threads; std::vector<std::thread> threads;
std::recursive_mutex threads_mutex; // TODO: replace by synchronized_value once available std::recursive_mutex threads_mutex; // TODO: replace by synchronized_value once available

View File

@ -15,8 +15,9 @@ extern "C"
#include <string> #include <string>
#include <vector> #include <vector>
#include <zstd.h>
#include <bzlib.h> #include <bzlib.h>
#include <zstd.h>
#include "progress_bar.hpp" #include "progress_bar.hpp"
#include "validate.hpp" #include "validate.hpp"
@ -27,7 +28,7 @@ namespace mamba
struct ZstdStream struct ZstdStream
{ {
constexpr static size_t BUFFER_SIZE = 256000; static constexpr size_t BUFFER_SIZE = 256000;
ZstdStream(curl_write_callback write_callback, void* write_callback_data) ZstdStream(curl_write_callback write_callback, void* write_callback_data)
: stream(ZSTD_createDCtx()) : stream(ZSTD_createDCtx())
, m_write_callback(write_callback) , m_write_callback(write_callback)
@ -58,7 +59,7 @@ namespace mamba
struct Bzip2Stream struct Bzip2Stream
{ {
constexpr static size_t BUFFER_SIZE = 256000; static constexpr size_t BUFFER_SIZE = 256000;
Bzip2Stream(curl_write_callback write_callback, void* write_callback_data) Bzip2Stream(curl_write_callback write_callback, void* write_callback_data)
: m_write_callback(write_callback) : m_write_callback(write_callback)
@ -100,10 +101,9 @@ namespace mamba
class DownloadTarget class DownloadTarget
{ {
public: public:
DownloadTarget() = default; DownloadTarget() = default;
DownloadTarget(const std::string& name, DownloadTarget(const std::string& name, const std::string& url, const std::string& filename);
const std::string& url,
const std::string& filename);
~DownloadTarget(); ~DownloadTarget();
DownloadTarget(const DownloadTarget&) = delete; DownloadTarget(const DownloadTarget&) = delete;
@ -116,7 +116,12 @@ namespace mamba
static size_t header_callback(char* buffer, size_t size, size_t nitems, void* self); static size_t header_callback(char* buffer, size_t size, size_t nitems, void* self);
static int progress_callback( static int progress_callback(
void*, curl_off_t total_to_download, curl_off_t now_downloaded, curl_off_t, curl_off_t); void*,
curl_off_t total_to_download,
curl_off_t now_downloaded,
curl_off_t,
curl_off_t
);
void set_mod_etag_headers(const std::string& mod, const std::string& etag); void set_mod_etag_headers(const std::string& mod, const std::string& etag);
void set_progress_bar(ProgressProxy progress_proxy); void set_progress_bar(ProgressProxy progress_proxy);
void set_expected_size(std::size_t size); void set_expected_size(std::size_t size);
@ -174,6 +179,7 @@ namespace mamba
std::string etag, mod, cache_control; std::string etag, mod, cache_control;
private: private:
std::unique_ptr<ZstdStream> m_zstd_stream; std::unique_ptr<ZstdStream> m_zstd_stream;
std::unique_ptr<Bzip2Stream> m_bzip2_stream; std::unique_ptr<Bzip2Stream> m_bzip2_stream;
std::function<bool(const DownloadTarget&)> m_finalize_callback; std::function<bool(const DownloadTarget&)> m_finalize_callback;
@ -209,6 +215,7 @@ namespace mamba
class MultiDownloadTarget class MultiDownloadTarget
{ {
public: public:
MultiDownloadTarget(); MultiDownloadTarget();
~MultiDownloadTarget(); ~MultiDownloadTarget();
@ -217,6 +224,7 @@ namespace mamba
bool download(int options); bool download(int options);
private: private:
std::vector<DownloadTarget*> m_targets; std::vector<DownloadTarget*> m_targets;
std::vector<DownloadTarget*> m_retry_targets; std::vector<DownloadTarget*> m_retry_targets;
CURLM* m_handle; CURLM* m_handle;

View File

@ -12,9 +12,9 @@
#include "mamba/core/environment.hpp" #include "mamba/core/environment.hpp"
#include "mamba/core/mamba_fs.hpp" #include "mamba/core/mamba_fs.hpp"
#include "mamba/core/output.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/core/util_scope.hpp" #include "mamba/core/util_scope.hpp"
#include "mamba/core/output.hpp"
namespace mamba namespace mamba
{ {
@ -31,7 +31,9 @@ namespace mamba
inline void create_directories_sudo_safe(const fs::u8path& path) inline void create_directories_sudo_safe(const fs::u8path& path)
{ {
if (fs::is_directory(path)) if (fs::is_directory(path))
{
return; return;
}
fs::u8path base_dir = path.parent_path(); fs::u8path base_dir = path.parent_path();
if (!fs::is_directory(base_dir)) if (!fs::is_directory(base_dir))
@ -42,9 +44,11 @@ namespace mamba
#ifndef _WIN32 #ifndef _WIN32
// set permissions to 0o2775 // set permissions to 0o2775
fs::permissions(path, fs::permissions(
fs::perms::set_gid | fs::perms::owner_all | fs::perms::group_all path,
| fs::perms::others_read | fs::perms::others_exec); fs::perms::set_gid | fs::perms::owner_all | fs::perms::group_all
| fs::perms::others_read | fs::perms::others_exec
);
#endif #endif
} }
@ -75,11 +79,17 @@ namespace mamba
std::ofstream outfile{ path.std_path(), std::ios::out }; std::ofstream outfile{ path.std_path(), std::ios::out };
if (!outfile.good()) if (!outfile.good())
{
LOG_INFO << "Could not touch file at " << path; LOG_INFO << "Could not touch file at " << path;
}
if (outfile.fail()) if (outfile.fail())
throw fs::filesystem_error("File creation failed", {
std::make_error_code(std::errc::permission_denied)); throw fs::filesystem_error(
"File creation failed",
std::make_error_code(std::errc::permission_denied)
);
}
return false; return false;
} }
@ -95,28 +105,34 @@ namespace mamba
{ {
const auto& path_to_write_in = fs::exists(path) ? path : path.parent_path(); const auto& path_to_write_in = fs::exists(path) ? path : path.parent_path();
static constexpr auto writable_flags static constexpr auto writable_flags = fs::perms::owner_write | fs::perms::group_write
= fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write; | fs::perms::others_write;
std::error_code ec; std::error_code ec;
const auto status = fs::status(path_to_write_in, ec); const auto status = fs::status(path_to_write_in, ec);
const bool should_be_writable const bool should_be_writable = !ec && status.type() != fs::file_type::not_found
= !ec && status.type() != fs::file_type::not_found && (status.permissions() & writable_flags)
&& (status.permissions() & writable_flags) != fs::perms::none; != fs::perms::none;
// If it should not be writable, stop there. // If it should not be writable, stop there.
if (!should_be_writable) if (!should_be_writable)
{
return false; return false;
}
// If it should be, check that it's true by creating or editing a file. // If it should be, check that it's true by creating or editing a file.
const bool is_directory const bool is_directory = fs::exists(path)
= fs::exists(path) && fs::is_directory(path, ec); // fs::is_directory
&& fs::is_directory(path, ec); // fs::is_directory fails if path does not exist // fails if
// path does
// not exist
if (ec) if (ec)
{
return false; return false;
}
const auto& test_file_path const auto& test_file_path = is_directory ? path / ".mamba-is-writable-check-delete-me"
= is_directory ? path / ".mamba-is-writable-check-delete-me" : path; : path;
const auto _ = on_scope_exit( const auto _ = on_scope_exit(
[&] [&]
{ {
@ -125,7 +141,8 @@ namespace mamba
std::error_code ec; std::error_code ec;
fs::remove(test_file_path, ec); fs::remove(test_file_path, ec);
} }
}); }
);
std::ofstream test_file{ test_file_path.std_path(), std::ofstream test_file{ test_file_path.std_path(),
std::ios_base::out | std::ios_base::app }; std::ios_base::out | std::ios_base::app };
return test_file.is_open(); return test_file.is_open();
@ -140,9 +157,7 @@ namespace mamba
// if both rename and move fail, the error code is set to the error code of the // if both rename and move fail, the error code is set to the error code of the
// copy_file operation and the `to` file is removed. You will have to handle removal // copy_file operation and the `to` file is removed. You will have to handle removal
// of the `from` file yourself. // of the `from` file yourself.
inline void rename_or_move(const fs::u8path& from, inline void rename_or_move(const fs::u8path& from, const fs::u8path& to, std::error_code& ec)
const fs::u8path& to,
std::error_code& ec)
{ {
fs::rename(from, to, ec); fs::rename(from, to, ec);
if (ec) if (ec)

View File

@ -20,6 +20,7 @@ namespace mamba
class History class History
{ {
public: public:
History(const fs::u8path& prefix); History(const fs::u8path& prefix);
struct ParseResult struct ParseResult

View File

@ -10,9 +10,7 @@ namespace mamba
template <typename Func, typename... Args> template <typename Func, typename... Args>
auto safe_invoke(Func&& func, Args&&... args) auto safe_invoke(Func&& func, Args&&... args)
-> tl::expected<decltype(std::invoke(std::forward<Func>(func), -> tl::expected<decltype(std::invoke(std::forward<Func>(func), std::forward<Args>(args)...)), mamba_error>
std::forward<Args>(args)...)),
mamba_error>
{ {
try try
{ {
@ -34,13 +32,17 @@ namespace mamba
} }
catch (const std::runtime_error& err) catch (const std::runtime_error& err)
{ {
return make_unexpected(std::string("callback invocation failed : ") + err.what(), return make_unexpected(
mamba_error_code::unknown); std::string("callback invocation failed : ") + err.what(),
mamba_error_code::unknown
);
} }
catch (...) catch (...)
{ {
return make_unexpected("callback invocation failed : unknown error", return make_unexpected(
mamba_error_code::unknown); "callback invocation failed : unknown error",
mamba_error_code::unknown
);
} }
} }

View File

@ -25,12 +25,15 @@ namespace mamba
std::string replace_long_shebang(const std::string& shebang); std::string replace_long_shebang(const std::string& shebang);
std::string python_shebang(const std::string& python_exe); std::string python_shebang(const std::string& python_exe);
static const std::regex shebang_regex( static const std::regex shebang_regex("^(#!" // pretty much the whole match string
"^(#!" // pretty much the whole match string "(?:[ ]*)" // allow spaces between #! and beginning of
"(?:[ ]*)" // allow spaces between #! and beginning of the executable path // the executable path
"(/(?:\\\\ |[^ \n\r\t])*)" // the executable is the next text block without an escaped "(/(?:\\\\ |[^ \n\r\t])*)" // the executable is the next
// space or non-space whitespace character // text block without an
"(.*))$"); // the rest of the line can contain option flags and end whole_shebang group // escaped space or non-space
// whitespace character
"(.*))$"); // the rest of the line can contain option
// flags and end whole_shebang group
constexpr size_t MAX_SHEBANG_LENGTH = on_linux ? 127 : 512; constexpr size_t MAX_SHEBANG_LENGTH = on_linux ? 127 : 512;
@ -42,14 +45,14 @@ namespace mamba
class UnlinkPackage class UnlinkPackage
{ {
public: public:
UnlinkPackage(const PackageInfo& pkg_info,
const fs::u8path& cache_path, UnlinkPackage(const PackageInfo& pkg_info, const fs::u8path& cache_path, TransactionContext* context);
TransactionContext* context);
bool execute(); bool execute();
bool undo(); bool undo();
private: private:
bool unlink_path(const nlohmann::json& path_data); bool unlink_path(const nlohmann::json& path_data);
PackageInfo m_pkg_info; PackageInfo m_pkg_info;
@ -61,22 +64,23 @@ namespace mamba
class LinkPackage class LinkPackage
{ {
public: public:
LinkPackage(const PackageInfo& pkg_info,
const fs::u8path& cache_path, LinkPackage(const PackageInfo& pkg_info, const fs::u8path& cache_path, TransactionContext* context);
TransactionContext* context);
bool execute(); bool execute();
bool undo(); bool undo();
private: private:
std::tuple<std::string, std::string> link_path(const PathData& path_data,
bool noarch_python); std::tuple<std::string, std::string> link_path(const PathData& path_data, bool noarch_python);
std::vector<fs::u8path> compile_pyc_files(const std::vector<fs::u8path>& py_files); std::vector<fs::u8path> compile_pyc_files(const std::vector<fs::u8path>& py_files);
auto create_python_entry_point(const fs::u8path& path, auto
const python_entry_point_parsed& entry_point); create_python_entry_point(const fs::u8path& path, const python_entry_point_parsed& entry_point);
void create_application_entry_point(const fs::u8path& source_full_path, void create_application_entry_point(
const fs::u8path& target_full_path, const fs::u8path& source_full_path,
const fs::u8path& python_full_path); const fs::u8path& target_full_path,
const fs::u8path& python_full_path
);
PackageInfo m_pkg_info; PackageInfo m_pkg_info;
fs::u8path m_cache_path; fs::u8path m_cache_path;

View File

@ -4,13 +4,14 @@
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <fmt/format.h> #include <fmt/format.h>
#include "mamba/core/util_string.hpp" #include "mamba/core/util_string.hpp"
#if !defined(_WIN32) #if !defined(_WIN32)
#include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h>
// We can use the presence of UTIME_OMIT to detect platforms that provide // We can use the presence of UTIME_OMIT to detect platforms that provide
// utimensat. // utimensat.
@ -125,6 +126,7 @@ namespace fs
class u8path class u8path
{ {
public: public:
u8path() = default; u8path() = default;
// Copy is allowed. // Copy is allowed.
@ -633,12 +635,14 @@ namespace fs
} }
private: private:
std::filesystem::path m_path; std::filesystem::path m_path;
}; };
class directory_entry : private std::filesystem::directory_entry class directory_entry : private std::filesystem::directory_entry
{ {
public: public:
using std::filesystem::directory_entry::exists; using std::filesystem::directory_entry::exists;
using std::filesystem::directory_entry::file_size; using std::filesystem::directory_entry::file_size;
using std::filesystem::directory_entry::hard_link_count; using std::filesystem::directory_entry::hard_link_count;
@ -720,6 +724,7 @@ namespace fs
class directory_iterator : private std::filesystem::directory_iterator class directory_iterator : private std::filesystem::directory_iterator
{ {
public: public:
using iterator_category = std::input_iterator_tag; using iterator_category = std::input_iterator_tag;
using value_type = directory_entry; using value_type = directory_entry;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
@ -772,11 +777,11 @@ namespace fs
} }
private: private:
mutable directory_entry current_entry; mutable directory_entry current_entry;
}; };
static_assert(std::is_same_v<std::decay_t<decltype(*std::declval<directory_iterator>())>, static_assert(std::is_same_v<std::decay_t<decltype(*std::declval<directory_iterator>())>, directory_entry>);
directory_entry>);
inline directory_iterator begin(directory_iterator iter) noexcept inline directory_iterator begin(directory_iterator iter) noexcept
{ {
@ -790,6 +795,7 @@ namespace fs
class recursive_directory_iterator : private std::filesystem::recursive_directory_iterator class recursive_directory_iterator : private std::filesystem::recursive_directory_iterator
{ {
public: public:
using iterator_category = std::input_iterator_tag; using iterator_category = std::input_iterator_tag;
using value_type = directory_entry; using value_type = directory_entry;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
@ -810,8 +816,10 @@ namespace fs
template <typename... OtherArgs> template <typename... OtherArgs>
explicit recursive_directory_iterator(const u8path& path, OtherArgs&&... args) explicit recursive_directory_iterator(const u8path& path, OtherArgs&&... args)
: std::filesystem::recursive_directory_iterator(path.std_path(), : std::filesystem::recursive_directory_iterator(
std::forward<OtherArgs>(args)...) path.std_path(),
std::forward<OtherArgs>(args)...
)
{ {
} }
@ -840,22 +848,20 @@ namespace fs
bool operator==(const recursive_directory_iterator& other) const noexcept bool operator==(const recursive_directory_iterator& other) const noexcept
{ {
return static_cast<const std::filesystem::recursive_directory_iterator&>(*this) return static_cast<const std::filesystem::recursive_directory_iterator&>(*this) == other;
== other;
} }
bool operator!=(const recursive_directory_iterator& other) const noexcept bool operator!=(const recursive_directory_iterator& other) const noexcept
{ {
return static_cast<const std::filesystem::recursive_directory_iterator&>(*this) return static_cast<const std::filesystem::recursive_directory_iterator&>(*this) != other;
!= other;
} }
private: private:
mutable directory_entry current_entry; mutable directory_entry current_entry;
}; };
static_assert(std::is_same_v<std::decay_t<decltype(*std::declval<directory_iterator>())>, static_assert(std::is_same_v<std::decay_t<decltype(*std::declval<directory_iterator>())>, directory_entry>);
directory_entry>);
inline recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept inline recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept
{ {
@ -923,12 +929,9 @@ namespace fs
// const path& new_symlink, // const path& new_symlink,
// error_code& ec) noexcept; // error_code& ec) noexcept;
template <typename... OtherArgs> template <typename... OtherArgs>
void copy_symlink(const u8path& existing_symlink, void copy_symlink(const u8path& existing_symlink, const u8path& new_symlink, OtherArgs&&... args)
const u8path& new_symlink,
OtherArgs&&... args)
{ {
std::filesystem::copy_symlink( std::filesystem::copy_symlink(existing_symlink, new_symlink, std::forward<OtherArgs>(args)...);
existing_symlink, new_symlink, std::forward<OtherArgs>(args)...);
} }
// bool create_directories(const path& p); // bool create_directories(const path& p);
@ -952,8 +955,7 @@ namespace fs
template <typename... OtherArgs> template <typename... OtherArgs>
bool create_directory(const u8path& path, const u8path& attributes, OtherArgs&&... args) bool create_directory(const u8path& path, const u8path& attributes, OtherArgs&&... args)
{ {
return std::filesystem::create_directory( return std::filesystem::create_directory(path, attributes, std::forward<OtherArgs>(args)...);
path, attributes, std::forward<OtherArgs>(args)...);
} }
@ -963,8 +965,7 @@ namespace fs
template <typename... OtherArgs> template <typename... OtherArgs>
void create_directory_symlink(const u8path& to, const u8path& new_symlink, OtherArgs&&... args) void create_directory_symlink(const u8path& to, const u8path& new_symlink, OtherArgs&&... args)
{ {
std::filesystem::create_directory_symlink( std::filesystem::create_directory_symlink(to, new_symlink, std::forward<OtherArgs>(args)...);
to, new_symlink, std::forward<OtherArgs>(args)...);
} }
// void create_hard_link(const path& to, const path& new_hard_link); // void create_hard_link(const path& to, const path& new_hard_link);
@ -1279,13 +1280,17 @@ namespace fs
{ {
#if defined(WIN32) && _MSC_VER < 1930 // Workaround https://github.com/microsoft/STL/issues/1511 #if defined(WIN32) && _MSC_VER < 1930 // Workaround https://github.com/microsoft/STL/issues/1511
if (!fs::exists(path)) if (!fs::exists(path))
{
return 0; return 0;
}
uintmax_t counter = 0; uintmax_t counter = 0;
for (const auto& entry : fs::recursive_directory_iterator(path, args...)) for (const auto& entry : fs::recursive_directory_iterator(path, args...))
{ {
if (fs::is_directory(entry.path())) // Skip directories, we'll delete them later. if (fs::is_directory(entry.path()))
{ // Skip directories, we'll delete them later.
continue; continue;
}
if (fs::remove(entry.path(), args...)) if (fs::remove(entry.path(), args...))
{ {
@ -1375,9 +1380,9 @@ struct std::hash<::fs::u8path>
{ {
std::size_t operator()(const ::fs::u8path& path) const noexcept std::size_t operator()(const ::fs::u8path& path) const noexcept
{ {
return std::filesystem::hash_value( return std::filesystem::hash_value(path.std_path()
path.std_path()); // TODO: once we stop using gcc < 12 we can properly use ); // TODO: once we stop using gcc < 12 we can properly use
// std::hash<std::filesystem::path>{}(path.std_path()); // std::hash<std::filesystem::path>{}(path.std_path());
} }
}; };
@ -1388,7 +1393,9 @@ struct fmt::formatter<::fs::u8path>
{ {
// make sure that range is empty // make sure that range is empty
if (ctx.begin() != ctx.end() && *ctx.begin() != '}') if (ctx.begin() != ctx.end() && *ctx.begin() != '}')
{
throw format_error("invalid format"); throw format_error("invalid format");
}
return ctx.begin(); return ctx.begin();
} }

View File

@ -16,6 +16,7 @@ namespace mamba
class MatchSpec class MatchSpec
{ {
public: public:
MatchSpec() = default; MatchSpec() = default;
MatchSpec(const std::string& i_spec); MatchSpec(const std::string& i_spec);

View File

@ -13,8 +13,8 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#include <nlohmann/json.hpp>
#include <fmt/color.h> #include <fmt/color.h>
#include <nlohmann/json.hpp>
#include "mamba/core/common_types.hpp" #include "mamba/core/common_types.hpp"
#include "mamba/core/progress_bar.hpp" #include "mamba/core/progress_bar.hpp"
@ -57,17 +57,19 @@ namespace mamba
class Table class Table
{ {
public: public:
Table(const std::vector<FormattedString>& header); Table(const std::vector<FormattedString>& header);
void set_alignment(const std::vector<alignment>& a); void set_alignment(const std::vector<alignment>& a);
void set_padding(const std::vector<int>& p); void set_padding(const std::vector<int>& p);
void add_row(const std::vector<FormattedString>& r); void add_row(const std::vector<FormattedString>& r);
void add_rows(const std::string& header, void
const std::vector<std::vector<FormattedString>>& rs); add_rows(const std::string& header, const std::vector<std::vector<FormattedString>>& rs);
std::ostream& print(std::ostream& out); std::ostream& print(std::ostream& out);
private: private:
std::vector<FormattedString> m_header; std::vector<FormattedString> m_header;
std::vector<alignment> m_align; std::vector<alignment> m_align;
std::vector<int> m_padding; std::vector<int> m_padding;
@ -82,6 +84,7 @@ namespace mamba
class ConsoleStream : public std::stringstream class ConsoleStream : public std::stringstream
{ {
public: public:
ConsoleStream() = default; ConsoleStream() = default;
~ConsoleStream(); ~ConsoleStream();
}; };
@ -92,6 +95,7 @@ namespace mamba
class Console class Console
{ {
public: public:
Console(const Console&) = delete; Console(const Console&) = delete;
Console& operator=(const Console&) = delete; Console& operator=(const Console&) = delete;
@ -101,14 +105,12 @@ namespace mamba
static Console& instance(); static Console& instance();
static ConsoleStream stream(); static ConsoleStream stream();
static bool prompt(const std::string_view& message, char fallback = '_'); static bool prompt(const std::string_view& message, char fallback = '_');
static bool prompt(const std::string_view& message, static bool
char fallback, prompt(const std::string_view& message, char fallback, std::istream& input_stream);
std::istream& input_stream);
ProgressProxy add_progress_bar(const std::string& name, size_t expected_total = 0); ProgressProxy add_progress_bar(const std::string& name, size_t expected_total = 0);
void clear_progress_bars(); void clear_progress_bars();
ProgressBarManager& init_progress_bar_manager(ProgressBarMode mode ProgressBarManager& init_progress_bar_manager(ProgressBarMode mode = ProgressBarMode::multi);
= ProgressBarMode::multi);
void terminate_progress_bar_manager(); void terminate_progress_bar_manager();
ProgressBarManager& progress_bar_manager(); ProgressBarManager& progress_bar_manager();
@ -126,10 +128,12 @@ namespace mamba
void cancel_json_print(); void cancel_json_print();
protected: protected:
Console(); Console();
~Console(); ~Console();
private: private:
void json_print(); void json_print();
void deactivate_progress_bar(std::size_t idx, const std::string_view& msg = ""); void deactivate_progress_bar(std::size_t idx, const std::string_view& msg = "");
@ -141,6 +145,7 @@ namespace mamba
class MessageLogger class MessageLogger
{ {
public: public:
MessageLogger(const char* file, int line, log_level level); MessageLogger(const char* file, int line, log_level level);
~MessageLogger(); ~MessageLogger();
@ -151,6 +156,7 @@ namespace mamba
static void print_buffer(std::ostream& ostream); static void print_buffer(std::ostream& ostream);
private: private:
std::string m_file; std::string m_file;
int m_line; int m_line;
log_level m_level; log_level m_level;

View File

@ -30,6 +30,7 @@ namespace mamba
class PackageCacheData class PackageCacheData
{ {
public: public:
PackageCacheData(const fs::u8path& path); PackageCacheData(const fs::u8path& path);
bool create_directory(); bool create_directory();
@ -42,6 +43,7 @@ namespace mamba
bool has_valid_extracted_dir(const PackageInfo& s); bool has_valid_extracted_dir(const PackageInfo& s);
private: private:
void check_writable(); void check_writable();
std::map<std::string, bool> m_valid_tarballs; std::map<std::string, bool> m_valid_tarballs;
@ -53,6 +55,7 @@ namespace mamba
class MultiPackageCache class MultiPackageCache
{ {
public: public:
MultiPackageCache(const std::vector<fs::u8path>& pkgs_dirs); MultiPackageCache(const std::vector<fs::u8path>& pkgs_dirs);
std::vector<fs::u8path> paths() const; std::vector<fs::u8path> paths() const;
@ -67,6 +70,7 @@ namespace mamba
void clear_query_cache(const PackageInfo& s); void clear_query_cache(const PackageInfo& s);
private: private:
std::vector<PackageCacheData> m_caches; std::vector<PackageCacheData> m_caches;
std::map<std::string, fs::u8path> m_cached_tarballs; std::map<std::string, fs::u8path> m_cached_tarballs;
std::map<std::string, fs::u8path> m_cached_extracted_dirs; std::map<std::string, fs::u8path> m_cached_extracted_dirs;

View File

@ -23,28 +23,36 @@ namespace mamba
zstd zstd
}; };
void create_archive(const fs::u8path& directory, void create_archive(
const fs::u8path& destination, const fs::u8path& directory,
compression_algorithm, const fs::u8path& destination,
int compression_level, compression_algorithm,
int compression_threads, int compression_level,
bool (*filter)(const fs::u8path&)); int compression_threads,
void create_package(const fs::u8path& directory, bool (*filter)(const fs::u8path&)
const fs::u8path& out_file, );
int compression_threads, void create_package(
int compression_level); const fs::u8path& directory,
const fs::u8path& out_file,
int compression_threads,
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);
void extract_conda(const fs::u8path& file, void extract_conda(
const fs::u8path& dest_dir, const fs::u8path& file,
const std::vector<std::string>& parts = { "info", "pkg" }); const fs::u8path& dest_dir,
const std::vector<std::string>& parts = { "info", "pkg" }
);
void extract(const fs::u8path& file, const fs::u8path& destination); void extract(const fs::u8path& file, const fs::u8path& destination);
fs::u8path extract(const fs::u8path& file); fs::u8path extract(const fs::u8path& file);
void extract_subproc(const fs::u8path& file, const fs::u8path& dest); void extract_subproc(const fs::u8path& file, const fs::u8path& dest);
bool transmute(const fs::u8path& pkg_file, bool transmute(
const fs::u8path& target, const fs::u8path& pkg_file,
int compression_level, const fs::u8path& target,
int compression_threads); int compression_level,
int compression_threads
);
bool validate(const fs::u8path& pkg_folder); bool validate(const fs::u8path& pkg_folder);
} // namespace mamba } // namespace mamba

View File

@ -15,9 +15,9 @@ extern "C"
#include <solv/solvable.h> #include <solv/solvable.h>
} }
#include <set>
#include <string> #include <string>
#include <vector> #include <vector>
#include <set>
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
@ -26,6 +26,7 @@ namespace mamba
class PackageInfo class PackageInfo
{ {
public: public:
using field_getter = std::function<std::string(const PackageInfo&)>; using field_getter = std::function<std::string(const PackageInfo&)>;
using compare_fun = std::function<bool(const PackageInfo&, const PackageInfo&)>; using compare_fun = std::function<bool(const PackageInfo&, const PackageInfo&)>;
@ -37,17 +38,19 @@ namespace mamba
PackageInfo(nlohmann::json&& j); PackageInfo(nlohmann::json&& j);
PackageInfo(const std::string& name); PackageInfo(const std::string& name);
PackageInfo(std::string&& name); PackageInfo(std::string&& name);
PackageInfo(const std::string& name, PackageInfo(
const std::string& version, const std::string& name,
const std::string build_string, const std::string& version,
std::size_t build_number); const std::string build_string,
std::size_t build_number
);
PackageInfo(PackageInfo const&) = default; PackageInfo(const PackageInfo&) = default;
PackageInfo(PackageInfo&&) noexcept = default; PackageInfo(PackageInfo&&) noexcept = default;
PackageInfo& operator=(PackageInfo const&) = default; PackageInfo& operator=(const PackageInfo&) = default;
PackageInfo& operator=(PackageInfo&&) noexcept = default; PackageInfo& operator=(PackageInfo&&) noexcept = default;
bool operator==(PackageInfo const& other) const; bool operator==(const PackageInfo& other) const;
nlohmann::json json_record() const; nlohmann::json json_record() const;
nlohmann::json json_signable() const; nlohmann::json json_signable() const;

View File

@ -7,10 +7,10 @@
#ifndef MAMBA_CORE_PINNING_HPP #ifndef MAMBA_CORE_PINNING_HPP
#define MAMBA_CORE_PINNING_HPP #define MAMBA_CORE_PINNING_HPP
#include "prefix_data.hpp"
#include <vector>
#include <string> #include <string>
#include <vector>
#include "prefix_data.hpp"
namespace mamba namespace mamba

View File

@ -7,13 +7,13 @@
#ifndef MAMBA_CORE_POOL_HPP #ifndef MAMBA_CORE_POOL_HPP
#define MAMBA_CORE_POOL_HPP #define MAMBA_CORE_POOL_HPP
#include <optional>
#include <memory> #include <memory>
#include <optional>
#include <solv/pooltypes.h> #include <solv/pooltypes.h>
#include "mamba/core/repo.hpp"
#include "mamba/core/package_info.hpp" #include "mamba/core/package_info.hpp"
#include "mamba/core/repo.hpp"
namespace mamba namespace mamba
{ {
@ -28,6 +28,7 @@ namespace mamba
class MPool class MPool
{ {
public: public:
MPool(); MPool();
~MPool(); ~MPool();
@ -40,16 +41,17 @@ namespace mamba
std::optional<PackageInfo> id2pkginfo(Id id); std::optional<PackageInfo> id2pkginfo(Id id);
operator Pool*(); operator Pool*();
operator Pool const*() const; operator const Pool*() const;
MRepo& add_repo(MRepo&& repo); MRepo& add_repo(MRepo&& repo);
void remove_repo(Id repo_id); void remove_repo(Id repo_id);
private: private:
struct MPoolData; struct MPoolData;
Pool* pool(); Pool* pool();
Pool const* pool() const; const Pool* pool() const;
/** /**
* Make MPool behave like a shared_ptr (with move and copy). * Make MPool behave like a shared_ptr (with move and copy).

View File

@ -7,8 +7,8 @@
#ifndef MAMBA_CORE_PREFIX_DATA_HPP #ifndef MAMBA_CORE_PREFIX_DATA_HPP
#define MAMBA_CORE_PREFIX_DATA_HPP #define MAMBA_CORE_PREFIX_DATA_HPP
#include <string>
#include <map> #include <map>
#include <string>
#include "error_handling.hpp" #include "error_handling.hpp"
#include "history.hpp" #include "history.hpp"
@ -19,6 +19,7 @@ namespace mamba
class PrefixData class PrefixData
{ {
public: public:
using package_map = std::map<std::string, PackageInfo>; using package_map = std::map<std::string, PackageInfo>;
static expected_t<PrefixData> create(const fs::u8path& prefix_path); static expected_t<PrefixData> create(const fs::u8path& prefix_path);
@ -32,6 +33,7 @@ namespace mamba
std::vector<PackageInfo> sorted_records() const; std::vector<PackageInfo> sorted_records() const;
private: private:
PrefixData(const fs::u8path& prefix_path); PrefixData(const fs::u8path& prefix_path);
void load(); void load();

View File

@ -7,8 +7,8 @@
#ifndef MAMBA_CORE_PROGRESS_BAR_HPP #ifndef MAMBA_CORE_PROGRESS_BAR_HPP
#define MAMBA_CORE_PROGRESS_BAR_HPP #define MAMBA_CORE_PROGRESS_BAR_HPP
#include <cstddef>
#include <chrono> #include <chrono>
#include <cstddef>
#include <functional> #include <functional>
#include <string> #include <string>
@ -28,6 +28,7 @@ namespace mamba
class ProgressProxy class ProgressProxy
{ {
public: public:
ProgressProxy() = default; ProgressProxy() = default;
ProgressProxy(ProgressBar* ptr); ProgressProxy(ProgressBar* ptr);
~ProgressProxy() = default; ~ProgressProxy() = default;
@ -57,8 +58,8 @@ namespace mamba
std::size_t in_progress() const; std::size_t in_progress() const;
std::size_t total() const; std::size_t total() const;
std::size_t speed() const; std::size_t speed() const;
std::size_t avg_speed(const std::chrono::milliseconds& ref_duration std::size_t
= std::chrono::milliseconds::max()); avg_speed(const std::chrono::milliseconds& ref_duration = std::chrono::milliseconds::max());
double progress() const; double progress() const;
bool completed() const; bool completed() const;
@ -66,8 +67,8 @@ namespace mamba
ProgressProxy& set_postfix(const std::string& text); ProgressProxy& set_postfix(const std::string& text);
ProgressProxy& set_repr_hook(std::function<void(ProgressBarRepr&)> f); ProgressProxy& set_repr_hook(std::function<void(ProgressBarRepr&)> f);
ProgressProxy& set_progress_hook(std::function<void(ProgressProxy&)> f); ProgressProxy& set_progress_hook(std::function<void(ProgressProxy&)> f);
ProgressProxy& mark_as_completed(const std::chrono::milliseconds& delay ProgressProxy&
= std::chrono::milliseconds::zero()); mark_as_completed(const std::chrono::milliseconds& delay = std::chrono::milliseconds::zero());
std::string elapsed_time_to_str() const; std::string elapsed_time_to_str() const;
std::string prefix() const; std::string prefix() const;
@ -87,6 +88,7 @@ namespace mamba
int width() const; int width() const;
private: private:
ProgressBar* p_bar = nullptr; ProgressBar* p_bar = nullptr;
friend class ProgressBarManager; friend class ProgressBarManager;

View File

@ -11,9 +11,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "mamba/core/util_graph.hpp"
#include "mamba/core/package_info.hpp" #include "mamba/core/package_info.hpp"
#include "mamba/core/pool.hpp" #include "mamba/core/pool.hpp"
#include "mamba/core/util_graph.hpp"
extern "C" extern "C"
{ {
@ -26,19 +26,22 @@ extern "C"
namespace mamba namespace mamba
{ {
void print_dep_graph(std::ostream& out, void print_dep_graph(
Solvable* s, std::ostream& out,
const std::string& solv_str, Solvable* s,
int level, const std::string& solv_str,
int max_level, int level,
bool last, int max_level,
const std::string& prefix); bool last,
const std::string& prefix
);
class query_result; class query_result;
class Query class Query
{ {
public: public:
Query(MPool& pool); Query(MPool& pool);
query_result find(const std::string& query) const; query_result find(const std::string& query) const;
@ -46,6 +49,7 @@ namespace mamba
query_result depends(const std::string& query, bool tree) const; query_result depends(const std::string& query, bool tree) const;
private: private:
std::reference_wrapper<MPool> m_pool; std::reference_wrapper<MPool> m_pool;
}; };
@ -68,6 +72,7 @@ namespace mamba
class query_result class query_result
{ {
public: public:
using dependency_graph = DiGraph<PackageInfo>; using dependency_graph = DiGraph<PackageInfo>;
using package_list = dependency_graph::node_list; using package_list = dependency_graph::node_list;
using package_view_list = std::vector<package_list::const_iterator>; using package_view_list = std::vector<package_list::const_iterator>;
@ -96,6 +101,7 @@ namespace mamba
std::ostream& pretty(std::ostream&) const; std::ostream& pretty(std::ostream&) const;
private: private:
void reset_pkg_view_list(); void reset_pkg_view_list();
std::string get_package_repr(const PackageInfo& pkg) const; std::string get_package_repr(const PackageInfo& pkg) const;

View File

@ -19,13 +19,16 @@ namespace mamba
class MQueue class MQueue
{ {
public: public:
MQueue() MQueue()
: p_queue(new Queue) : p_queue(new Queue)
{ {
queue_init(p_queue); queue_init(p_queue);
if (!p_queue) if (!p_queue)
{
throw std::runtime_error("libsolv error: could not initialize Queue"); throw std::runtime_error("libsolv error: could not initialize Queue");
}
} }
~MQueue() ~MQueue()
@ -95,6 +98,7 @@ namespace mamba
} }
private: private:
Queue* p_queue; Queue* p_queue;
}; };
} // namespace mamba } // namespace mamba

View File

@ -52,6 +52,7 @@ namespace mamba
class MRepo class MRepo
{ {
public: public:
~MRepo(); ~MRepo();
MRepo(const MRepo&) = delete; MRepo(const MRepo&) = delete;
@ -85,10 +86,8 @@ namespace mamba
* @param filename Name of the index file * @param filename Name of the index file
* @param url Subdirectory URL * @param url Subdirectory URL
*/ */
static MRepo& create(MPool& pool, static MRepo&
const std::string& name, create(MPool& pool, const std::string& name, const std::string& filename, const std::string& url);
const std::string& filename,
const std::string& url);
/** /**
* Static constructor. * Static constructor.
@ -98,11 +97,13 @@ namespace mamba
* @param meta Metadata of the repo * @param meta Metadata of the repo
* @param channel Channel of the repo * @param channel Channel of the repo
*/ */
static MRepo& create(MPool& pool, static MRepo& create(
const std::string& name, MPool& pool,
const fs::u8path& filename, const std::string& name,
const RepoMetadata& meta, const fs::u8path& filename,
const Channel& channel); const RepoMetadata& meta,
const Channel& channel
);
/** /**
* Static constructor. * Static constructor.
@ -117,21 +118,20 @@ namespace mamba
* @param name Name * @param name Name
* @param uris Matchspecs pointing to unique resources (URL or files) * @param uris Matchspecs pointing to unique resources (URL or files)
*/ */
static MRepo& create(MPool& pool, static MRepo&
const std::string& name, create(MPool& pool, const std::string& name, const std::vector<PackageInfo>& uris);
const std::vector<PackageInfo>& uris);
private: private:
MRepo(MPool& pool,
const std::string& name,
const std::string& filename,
const std::string& url);
MRepo(MPool& pool, MRepo(MPool& pool, const std::string& name, const std::string& filename, const std::string& url);
const std::string& name,
const fs::u8path& filename, MRepo(
const RepoMetadata& meta, MPool& pool,
const Channel& channel); const std::string& name,
const fs::u8path& filename,
const RepoMetadata& meta,
const Channel& channel
);
MRepo(MPool& pool, const PrefixData& prefix_data); MRepo(MPool& pool, const PrefixData& prefix_data);

View File

@ -1,5 +1,6 @@
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "mamba/core/mamba_fs.hpp" #include "mamba/core/mamba_fs.hpp"
@ -18,9 +19,12 @@ namespace mamba
const fs::u8path location; const fs::u8path location;
public: public:
ScopedProcFile(const std::string& name,
const std::vector<std::string>& command, ScopedProcFile(
LockFile proc_dir_lock = lock_proc_dir()); const std::string& name,
const std::vector<std::string>& command,
LockFile proc_dir_lock = lock_proc_dir()
);
~ScopedProcFile(); ~ScopedProcFile();
}; };
@ -32,16 +36,19 @@ namespace mamba
SINKIN = 1 << 2, SINKIN = 1 << 2,
}; };
int run_in_environment(std::vector<std::string> command, int run_in_environment(
const std::string& cwd, std::vector<std::string> command,
int stream_options, const std::string& cwd,
bool clean_env, int stream_options,
bool detach, bool clean_env,
const std::vector<std::string>& env_vars, bool detach,
const std::string& specific_process_name); const std::vector<std::string>& env_vars,
const std::string& specific_process_name
);
nlohmann::json get_all_running_processes_info( nlohmann::json get_all_running_processes_info(
const std::function<bool(const nlohmann::json&)>& filter const std::function<bool(const nlohmann::json&)>& filter = std::function<
= std::function<bool(const nlohmann::json&)>()); bool(const nlohmann::json&)>()
);
bool is_process_name_running(const std::string& name); bool is_process_name_running(const std::string& name);
} }

View File

@ -8,21 +8,21 @@
#define MAMBA_PROBLEMS_GRAPH_HPP #define MAMBA_PROBLEMS_GRAPH_HPP
#include <array> #include <array>
#include <string> #include <functional>
#include <optional>
#include <ostream> #include <ostream>
#include <string>
#include <string_view> #include <string_view>
#include <unordered_map>
#include <utility> #include <utility>
#include <variant> #include <variant>
#include <unordered_map>
#include <optional>
#include <vector> #include <vector>
#include <functional>
#include <solv/solver.h>
#include <fmt/color.h> #include <fmt/color.h>
#include <solv/solver.h>
#include "mamba/core/util_graph.hpp"
#include "mamba/core/package_info.hpp" #include "mamba/core/package_info.hpp"
#include "mamba/core/util_graph.hpp"
namespace mamba namespace mamba
{ {
@ -36,11 +36,12 @@ namespace mamba
class DependencyInfo class DependencyInfo
{ {
public: public:
DependencyInfo(const std::string& dependency); DependencyInfo(const std::string& dependency);
DependencyInfo(DependencyInfo const&) = default; DependencyInfo(const DependencyInfo&) = default;
DependencyInfo(DependencyInfo&&) noexcept = default; DependencyInfo(DependencyInfo&&) noexcept = default;
DependencyInfo& operator=(DependencyInfo const&) = default; DependencyInfo& operator=(const DependencyInfo&) = default;
DependencyInfo& operator=(DependencyInfo&&) noexcept = default; DependencyInfo& operator=(DependencyInfo&&) noexcept = default;
const std::string& name() const; const std::string& name() const;
@ -48,9 +49,10 @@ namespace mamba
const std::string& build_string() const; const std::string& build_string() const;
std::string str() const; std::string str() const;
bool operator==(DependencyInfo const& other) const; bool operator==(const DependencyInfo& other) const;
private: private:
std::string m_name; std::string m_name;
std::string m_version_range; std::string m_version_range;
std::string m_build_range; std::string m_build_range;
@ -60,6 +62,7 @@ namespace mamba
class conflict_map : private std::unordered_map<T, vector_set<T>> class conflict_map : private std::unordered_map<T, vector_set<T>>
{ {
public: public:
using Base = std::unordered_map<T, vector_set<T>>; using Base = std::unordered_map<T, vector_set<T>>;
using typename Base::const_iterator; using typename Base::const_iterator;
using typename Base::key_type; using typename Base::key_type;
@ -69,9 +72,9 @@ namespace mamba
using Base::empty; using Base::empty;
using Base::size; using Base::size;
bool has_conflict(key_type const& a) const; bool has_conflict(const key_type& a) const;
auto conflicts(key_type const& a) const -> vector_set<T> const&; auto conflicts(const key_type& a) const -> const vector_set<T>&;
bool in_conflict(key_type const& a, key_type const& b) const; bool in_conflict(const key_type& a, const key_type& b) const;
using Base::cbegin; using Base::cbegin;
using Base::cend; using Base::cend;
@ -79,7 +82,7 @@ namespace mamba
const_iterator end() const noexcept; const_iterator end() const noexcept;
using Base::clear; using Base::clear;
void add(key_type const& a, key_type const& b); void add(const key_type& a, const key_type& b);
}; };
/** /**
@ -88,6 +91,7 @@ namespace mamba
class ProblemsGraph class ProblemsGraph
{ {
public: public:
struct RootNode struct RootNode
{ {
}; };
@ -95,31 +99,30 @@ namespace mamba
{ {
std::optional<SolverRuleinfo> problem_type; std::optional<SolverRuleinfo> problem_type;
PackageNode(PackageNode const&) = default; PackageNode(const PackageNode&) = default;
PackageNode(PackageNode&&) noexcept = default; PackageNode(PackageNode&&) noexcept = default;
PackageNode& operator=(PackageNode const&) = default; PackageNode& operator=(const PackageNode&) = default;
PackageNode& operator=(PackageNode&&) noexcept = default; PackageNode& operator=(PackageNode&&) noexcept = default;
}; };
struct UnresolvedDependencyNode : DependencyInfo struct UnresolvedDependencyNode : DependencyInfo
{ {
SolverRuleinfo problem_type; SolverRuleinfo problem_type;
UnresolvedDependencyNode(UnresolvedDependencyNode const&) = default; UnresolvedDependencyNode(const UnresolvedDependencyNode&) = default;
UnresolvedDependencyNode(UnresolvedDependencyNode&&) noexcept = default; UnresolvedDependencyNode(UnresolvedDependencyNode&&) noexcept = default;
UnresolvedDependencyNode& operator=(UnresolvedDependencyNode const&) = default; UnresolvedDependencyNode& operator=(const UnresolvedDependencyNode&) = default;
UnresolvedDependencyNode& operator=(UnresolvedDependencyNode&&) noexcept = default; UnresolvedDependencyNode& operator=(UnresolvedDependencyNode&&) noexcept = default;
}; };
struct ConstraintNode : DependencyInfo struct ConstraintNode : DependencyInfo
{ {
static SolverRuleinfo constexpr problem_type = SOLVER_RULE_PKG_CONSTRAINS; static constexpr SolverRuleinfo problem_type = SOLVER_RULE_PKG_CONSTRAINS;
ConstraintNode(ConstraintNode const&) = default; ConstraintNode(const ConstraintNode&) = default;
ConstraintNode(ConstraintNode&&) noexcept = default; ConstraintNode(ConstraintNode&&) noexcept = default;
ConstraintNode& operator=(ConstraintNode const&) = default; ConstraintNode& operator=(const ConstraintNode&) = default;
ConstraintNode& operator=(ConstraintNode&&) noexcept = default; ConstraintNode& operator=(ConstraintNode&&) noexcept = default;
}; };
using node_t using node_t = std::variant<RootNode, PackageNode, UnresolvedDependencyNode, ConstraintNode>;
= std::variant<RootNode, PackageNode, UnresolvedDependencyNode, ConstraintNode>;
using edge_t = DependencyInfo; using edge_t = DependencyInfo;
@ -127,15 +130,16 @@ namespace mamba
using node_id = graph_t::node_id; using node_id = graph_t::node_id;
using conflicts_t = conflict_map<node_id>; using conflicts_t = conflict_map<node_id>;
static ProblemsGraph from_solver(MSolver const& solver, MPool const& pool); static ProblemsGraph from_solver(const MSolver& solver, const MPool& pool);
ProblemsGraph(graph_t graph, conflicts_t conflicts, node_id root_node); ProblemsGraph(graph_t graph, conflicts_t conflicts, node_id root_node);
graph_t const& graph() const noexcept; const graph_t& graph() const noexcept;
conflicts_t const& conflicts() const noexcept; const conflicts_t& conflicts() const noexcept;
node_id root_node() const noexcept; node_id root_node() const noexcept;
private: private:
graph_t m_graph; graph_t m_graph;
conflicts_t m_conflicts; conflicts_t m_conflicts;
node_id m_root_node; node_id m_root_node;
@ -144,6 +148,7 @@ namespace mamba
class CompressedProblemsGraph class CompressedProblemsGraph
{ {
public: public:
using RootNode = ProblemsGraph::RootNode; using RootNode = ProblemsGraph::RootNode;
/** /**
@ -159,7 +164,7 @@ namespace mamba
template <typename T> template <typename T>
struct RoughCompare struct RoughCompare
{ {
bool operator()(T const& a, T const& b); bool operator()(const T& a, const T& b);
}; };
/** /**
@ -172,6 +177,7 @@ namespace mamba
class NamedList : private vector_set<T, RoughCompare<T>, Allocator> class NamedList : private vector_set<T, RoughCompare<T>, Allocator>
{ {
public: public:
using Base = vector_set<T, RoughCompare<T>, Allocator>; using Base = vector_set<T, RoughCompare<T>, Allocator>;
using typename Base::allocator_type; using typename Base::allocator_type;
using typename Base::const_iterator; using typename Base::const_iterator;
@ -184,8 +190,8 @@ namespace mamba
using Base::empty; using Base::empty;
using Base::size; using Base::size;
value_type const& front() const noexcept; const value_type& front() const noexcept;
value_type const& back() const noexcept; const value_type& back() const noexcept;
using Base::cbegin; using Base::cbegin;
using Base::cend; using Base::cend;
using Base::crbegin; using Base::crbegin;
@ -195,30 +201,35 @@ namespace mamba
const_reverse_iterator rbegin() const noexcept; const_reverse_iterator rbegin() const noexcept;
const_reverse_iterator rend() const noexcept; const_reverse_iterator rend() const noexcept;
std::string const& name() const; const std::string& name() const;
std::pair<std::string, std::size_t> versions_trunc(std::string_view sep = "|", std::pair<std::string, std::size_t> versions_trunc(
std::string_view etc = "...", std::string_view sep = "|",
std::size_t threshold = 5, std::string_view etc = "...",
bool remove_duplicates = true) const; std::size_t threshold = 5,
std::pair<std::string, std::size_t> build_strings_trunc(std::string_view sep = "|", bool remove_duplicates = true
std::string_view etc = "...", ) const;
std::size_t threshold = 5, std::pair<std::string, std::size_t> build_strings_trunc(
bool remove_duplicates std::string_view sep = "|",
= true) const; std::string_view etc = "...",
std::size_t threshold = 5,
bool remove_duplicates = true
) const;
std::pair<std::string, std::size_t> versions_and_build_strings_trunc( std::pair<std::string, std::size_t> versions_and_build_strings_trunc(
std::string_view sep = "|", std::string_view sep = "|",
std::string_view etc = "...", std::string_view etc = "...",
std::size_t threshold = 5, std::size_t threshold = 5,
bool remove_duplicates = true) const; bool remove_duplicates = true
) const;
using Base::clear; using Base::clear;
using Base::reserve; using Base::reserve;
void insert(value_type const& e); void insert(const value_type& e);
void insert(value_type&& e); void insert(value_type&& e);
template <typename InputIterator> template <typename InputIterator>
void insert(InputIterator first, InputIterator last); void insert(InputIterator first, InputIterator last);
private: private:
template <typename T_> template <typename T_>
void insert_impl(T_&& e); void insert_impl(T_&& e);
}; };
@ -226,10 +237,11 @@ namespace mamba
using PackageListNode = NamedList<ProblemsGraph::PackageNode>; using PackageListNode = NamedList<ProblemsGraph::PackageNode>;
using UnresolvedDependencyListNode = NamedList<ProblemsGraph::UnresolvedDependencyNode>; using UnresolvedDependencyListNode = NamedList<ProblemsGraph::UnresolvedDependencyNode>;
using ConstraintListNode = NamedList<ProblemsGraph::ConstraintNode>; using ConstraintListNode = NamedList<ProblemsGraph::ConstraintNode>;
using node_t = std::variant<RootNode, // using node_t = std::variant<
PackageListNode, RootNode, //
UnresolvedDependencyListNode, PackageListNode,
ConstraintListNode>; UnresolvedDependencyListNode,
ConstraintListNode>;
using edge_t = NamedList<DependencyInfo>; using edge_t = NamedList<DependencyInfo>;
@ -237,20 +249,21 @@ namespace mamba
using node_id = graph_t::node_id; using node_id = graph_t::node_id;
using conflicts_t = conflict_map<node_id>; using conflicts_t = conflict_map<node_id>;
using merge_criteria_t = std::function<bool( using merge_criteria_t = std::function<
ProblemsGraph const&, ProblemsGraph::node_id, ProblemsGraph::node_id)>; bool(const ProblemsGraph&, ProblemsGraph::node_id, ProblemsGraph::node_id)>;
static auto from_problems_graph(ProblemsGraph const& pbs, static auto
merge_criteria_t const& merge_criteria = {}) from_problems_graph(const ProblemsGraph& pbs, const merge_criteria_t& merge_criteria = {})
-> CompressedProblemsGraph; -> CompressedProblemsGraph;
CompressedProblemsGraph(graph_t graph, conflicts_t conflicts, node_id root_node); CompressedProblemsGraph(graph_t graph, conflicts_t conflicts, node_id root_node);
graph_t const& graph() const noexcept; const graph_t& graph() const noexcept;
conflicts_t const& conflicts() const noexcept; const conflicts_t& conflicts() const noexcept;
node_id root_node() const noexcept; node_id root_node() const noexcept;
private: private:
graph_t m_graph; graph_t m_graph;
conflicts_t m_conflicts; conflicts_t m_conflicts;
node_id m_root_node; node_id m_root_node;
@ -266,33 +279,35 @@ namespace mamba
std::array<std::string_view, 4> indents = { "", " ", "├─ ", "└─ " }; std::array<std::string_view, 4> indents = { "", " ", "├─ ", "└─ " };
}; };
std::ostream& print_problem_summary_msg(std::ostream& out, CompressedProblemsGraph const& pbs); std::ostream& print_problem_summary_msg(std::ostream& out, const CompressedProblemsGraph& pbs);
std::string problem_summary_msg(CompressedProblemsGraph const& pbs); std::string problem_summary_msg(const CompressedProblemsGraph& pbs);
std::ostream& print_problem_tree_msg(std::ostream& out, std::ostream& print_problem_tree_msg(
CompressedProblemsGraph const& pbs, std::ostream& out,
ProblemsMessageFormat const& format = {}); const CompressedProblemsGraph& pbs,
std::string problem_tree_msg(CompressedProblemsGraph const& pbs, const ProblemsMessageFormat& format = {}
ProblemsMessageFormat const& format = {}); );
std::string
problem_tree_msg(const CompressedProblemsGraph& pbs, const ProblemsMessageFormat& format = {});
/************************************ /************************************
* Implementation of conflict_map * * Implementation of conflict_map *
************************************/ ************************************/
template <typename T> template <typename T>
bool conflict_map<T>::has_conflict(key_type const& a) const bool conflict_map<T>::has_conflict(const key_type& a) const
{ {
return Base::find(a) != end(); return Base::find(a) != end();
} }
template <typename T> template <typename T>
auto conflict_map<T>::conflicts(key_type const& a) const -> vector_set<T> const& auto conflict_map<T>::conflicts(const key_type& a) const -> const vector_set<T>&
{ {
return Base::at(a); return Base::at(a);
} }
template <typename T> template <typename T>
bool conflict_map<T>::in_conflict(key_type const& a, key_type const& b) const bool conflict_map<T>::in_conflict(const key_type& a, const key_type& b) const
{ {
return has_conflict(a) && Base::at(a).contains(b); return has_conflict(a) && Base::at(a).contains(b);
} }
@ -310,7 +325,7 @@ namespace mamba
} }
template <typename T> template <typename T>
void conflict_map<T>::add(key_type const& a, key_type const& b) void conflict_map<T>::add(const key_type& a, const key_type& b)
{ {
Base::operator[](a).insert(b); Base::operator[](a).insert(b);
Base::operator[](b).insert(a); Base::operator[](b).insert(a);

View File

@ -37,22 +37,21 @@ namespace mamba
// this function calls cygpath to convert win path to unix // 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); std::string native_path_to_unix(const std::string& path, bool is_a_path_env = false);
std::string rcfile_content(const fs::u8path& env_prefix, std::string
const std::string& shell, rcfile_content(const fs::u8path& env_prefix, const std::string& shell, const fs::u8path& mamba_exe);
const fs::u8path& mamba_exe);
std::string xonsh_content(const fs::u8path& env_prefix, std::string
const std::string& shell, xonsh_content(const fs::u8path& env_prefix, const std::string& shell, const fs::u8path& mamba_exe);
const fs::u8path& mamba_exe);
void modify_rc_file(const fs::u8path& file_path, void modify_rc_file(
const fs::u8path& conda_prefix, const fs::u8path& file_path,
const std::string& shell, const fs::u8path& conda_prefix,
const fs::u8path& mamba_exe); const std::string& shell,
const fs::u8path& mamba_exe
);
void reset_rc_file(const fs::u8path& file_path, void
const std::string& shell, reset_rc_file(const fs::u8path& file_path, const std::string& shell, const fs::u8path& mamba_exe);
const fs::u8path& mamba_exe);
// we need this function during linking... // we need this function during linking...
void init_root_prefix_cmdexe(const fs::u8path& root_prefix); void init_root_prefix_cmdexe(const fs::u8path& root_prefix);

View File

@ -7,18 +7,18 @@
#ifndef MAMBA_CORE_SOLVER_HPP #ifndef MAMBA_CORE_SOLVER_HPP
#define MAMBA_CORE_SOLVER_HPP #define MAMBA_CORE_SOLVER_HPP
#include <string>
#include <iosfwd> #include <iosfwd>
#include <memory>
#include <optional>
#include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <optional>
#include <memory>
#include <solv/queue.h> #include <solv/queue.h>
#include <solv/solver.h> #include <solv/solver.h>
#include "mamba/core/pool.hpp"
#include "mamba/core/package_info.hpp" #include "mamba/core/package_info.hpp"
#include "mamba/core/pool.hpp"
#include "match_spec.hpp" #include "match_spec.hpp"
@ -29,7 +29,7 @@
namespace mamba namespace mamba
{ {
char const* solver_ruleinfo_name(SolverRuleinfo rule); const char* solver_ruleinfo_name(SolverRuleinfo rule);
struct MSolverProblem struct MSolverProblem
{ {
@ -46,6 +46,7 @@ namespace mamba
class MSolver class MSolver
{ {
public: public:
MSolver(MPool pool, std::vector<std::pair<int, int>> flags = {}); MSolver(MPool pool, std::vector<std::pair<int, int>> flags = {});
~MSolver() = default; ~MSolver() = default;
@ -72,7 +73,7 @@ namespace mamba
std::ostream& explain_problems(std::ostream& out) const; std::ostream& explain_problems(std::ostream& out) const;
[[nodiscard]] std::string explain_problems() const; [[nodiscard]] std::string explain_problems() const;
[[nodiscard]] MPool const& pool() const&; [[nodiscard]] const MPool& pool() const&;
[[nodiscard]] MPool& pool() &; [[nodiscard]] MPool& pool() &;
[[nodiscard]] MPool&& pool() &&; [[nodiscard]] MPool&& pool() &&;
@ -89,6 +90,7 @@ namespace mamba
bool force_reinstall = false; bool force_reinstall = false;
private: private:
void add_channel_specific_job(const MatchSpec& ms, int job_flag); void add_channel_specific_job(const MatchSpec& ms, int job_flag);
void add_reinstall_job(MatchSpec& ms, int job_flag); void add_reinstall_job(MatchSpec& ms, int job_flag);

View File

@ -20,6 +20,7 @@
#include "mamba/core/pool.hpp" #include "mamba/core/pool.hpp"
#include "mamba/core/repo.hpp" #include "mamba/core/repo.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "package_handling.hpp" #include "package_handling.hpp"
namespace decompress namespace decompress
@ -77,11 +78,14 @@ namespace mamba
class MSubdirData class MSubdirData
{ {
public: public:
static expected_t<MSubdirData> create(const Channel& channel,
const std::string& platform, static expected_t<MSubdirData> create(
const std::string& url, const Channel& channel,
MultiPackageCache& caches, const std::string& platform,
const std::string& repodata_fn = "repodata.json"); const std::string& url,
MultiPackageCache& caches,
const std::string& repodata_fn = "repodata.json"
);
~MSubdirData() = default; ~MSubdirData() = default;
@ -92,8 +96,8 @@ namespace mamba
MSubdirData& operator=(MSubdirData&&); MSubdirData& operator=(MSubdirData&&);
// TODO return seconds as double // TODO return seconds as double
fs::file_time_type::duration check_cache( fs::file_time_type::duration
const fs::u8path& cache_file, const fs::file_time_type::clock::time_point& ref) const; check_cache(const fs::u8path& cache_file, const fs::file_time_type::clock::time_point& ref) const;
bool loaded() const; bool loaded() const;
bool forbid_cache(); bool forbid_cache();
@ -111,11 +115,14 @@ namespace mamba
expected_t<MRepo&> create_repo(MPool& pool); expected_t<MRepo&> create_repo(MPool& pool);
private: private:
MSubdirData(const Channel& channel,
const std::string& platform, MSubdirData(
const std::string& url, const Channel& channel,
MultiPackageCache& caches, const std::string& platform,
const std::string& repodata_fn = "repodata.json"); const std::string& url,
MultiPackageCache& caches,
const std::string& repodata_fn = "repodata.json"
);
bool load(MultiPackageCache& caches); bool load(MultiPackageCache& caches);
void check_repodata_existence(); void check_repodata_existence();

View File

@ -6,12 +6,12 @@
#pragma once #pragma once
#include <cassert>
#include <atomic> #include <atomic>
#include <mutex> #include <cassert>
#include <memory>
#include <functional>
#include <condition_variable> #include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include "mamba/core/util_scope.hpp" #include "mamba/core/util_scope.hpp"
@ -75,6 +75,7 @@ namespace mamba
} }
public: public:
TaskSynchronizer() = default; TaskSynchronizer() = default;
/** Destructor, joining tasks synchronized with this object. /** Destructor, joining tasks synchronized with this object.
@ -114,10 +115,9 @@ namespace mamba
{ {
// If status is alive then we know the TaskSynchronizer is alive too. // If status is alive then we know the TaskSynchronizer is alive too.
auto status = remote_status.lock(); auto status = remote_status.lock();
if (status if (status && !status->join_requested) // Don't add running tasks while join was
&& !status // requested.
->join_requested) // Don't add running tasks while join was requested. { // We can use 'this' safely in this scope.
{ // We can use 'this' safely in this scope.
notify_begin_execution(); notify_begin_execution();
on_scope_exit _{ [&, this] on_scope_exit _{ [&, this]
{ {
@ -175,6 +175,7 @@ namespace mamba
} }
private: private:
struct Status struct Status
{ {
std::atomic<bool> join_requested{ false }; std::atomic<bool> join_requested{ false };
@ -204,7 +205,9 @@ namespace mamba
void wait_all_running_tasks() void wait_all_running_tasks()
{ {
if (!m_status) if (!m_status)
{
return; return;
}
std::unique_lock exit_lock{ m_mutex }; std::unique_lock exit_lock{ m_mutex };
@ -213,7 +216,9 @@ namespace mamba
m_status.reset(); m_status.reset();
m_task_end_condition.wait( m_task_end_condition.wait(
exit_lock, [&] { return m_running_tasks == 0 && remote_status.expired(); }); exit_lock,
[&] { return m_running_tasks == 0 && remote_status.expired(); }
);
} }
}; };

View File

@ -40,6 +40,7 @@ namespace mamba
class thread_interrupted : public std::exception class thread_interrupted : public std::exception
{ {
public: public:
thread_interrupted() = default; thread_interrupted() = default;
const char* what() const throw() const char* what() const throw()
{ {
@ -71,6 +72,7 @@ namespace mamba
class thread class thread
{ {
public: public:
thread() = default; thread() = default;
~thread() = default; ~thread() = default;
@ -96,6 +98,7 @@ namespace mamba
} }
private: private:
std::thread m_thread; std::thread m_thread;
}; };
@ -116,7 +119,8 @@ namespace mamba
errno = EINTR; errno = EINTR;
} }
decrease_thread_count(); decrease_thread_count();
}); }
);
} }
/********************** /**********************
@ -126,6 +130,7 @@ namespace mamba
class interruption_guard class interruption_guard
{ {
public: public:
template <class Function, class... Args> template <class Function, class... Args>
interruption_guard(Function&& func, Args&&... args); interruption_guard(Function&& func, Args&&... args);
~interruption_guard(); ~interruption_guard();
@ -137,6 +142,7 @@ namespace mamba
interruption_guard& operator=(interruption_guard&&) = delete; interruption_guard& operator=(interruption_guard&&) = delete;
private: private:
static std::function<void()> m_cleanup_function; static std::function<void()> m_cleanup_function;
}; };
@ -149,6 +155,7 @@ namespace mamba
class counting_semaphore class counting_semaphore
{ {
public: public:
inline counting_semaphore(std::ptrdiff_t max = 0); inline counting_semaphore(std::ptrdiff_t max = 0);
inline void lock(); inline void lock();
inline void unlock(); inline void unlock();
@ -156,6 +163,7 @@ namespace mamba
inline void set_max(std::ptrdiff_t value); inline void set_max(std::ptrdiff_t value);
private: private:
std::ptrdiff_t m_value, m_max; std::ptrdiff_t m_value, m_max;
std::mutex m_access_mutex; std::mutex m_access_mutex;
std::condition_variable m_cv; std::condition_variable m_cv;
@ -199,11 +207,17 @@ namespace mamba
{ {
std::ptrdiff_t new_max; std::ptrdiff_t new_max;
if (value == 0) if (value == 0)
{
new_max = std::thread::hardware_concurrency(); new_max = std::thread::hardware_concurrency();
}
else if (value < 0) else if (value < 0)
{
new_max = std::thread::hardware_concurrency() + value; new_max = std::thread::hardware_concurrency() + value;
}
else else
{
new_max = value; new_max = value;
}
m_value += new_max - m_max; m_value += new_max - m_max;
m_max = new_max; m_max = new_max;

View File

@ -14,8 +14,11 @@
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include "mamba/api/install.hpp"
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
#include "env_lockfile.hpp"
#include "fetch.hpp" #include "fetch.hpp"
#include "mamba_fs.hpp" #include "mamba_fs.hpp"
#include "match_spec.hpp" #include "match_spec.hpp"
@ -26,8 +29,6 @@
#include "repo.hpp" #include "repo.hpp"
#include "thread_utils.hpp" #include "thread_utils.hpp"
#include "transaction_context.hpp" #include "transaction_context.hpp"
#include "env_lockfile.hpp"
#include "mamba/api/install.hpp"
extern "C" extern "C"
{ {
@ -45,6 +46,7 @@ namespace mamba
class PackageDownloadExtractTarget class PackageDownloadExtractTarget
{ {
public: public:
PackageDownloadExtractTarget(Solvable* solvable); PackageDownloadExtractTarget(Solvable* solvable);
PackageDownloadExtractTarget(const PackageInfo& pkg_info); PackageDownloadExtractTarget(const PackageInfo& pkg_info);
@ -76,6 +78,7 @@ namespace mamba
std::exception m_decompress_exception; std::exception m_decompress_exception;
private: private:
bool m_finished; bool m_finished;
PackageInfo m_package_info; PackageInfo m_package_info;
@ -100,10 +103,12 @@ namespace mamba
class DownloadExtractSemaphore class DownloadExtractSemaphore
{ {
public: public:
static std::ptrdiff_t get_max(); static std::ptrdiff_t get_max();
static void set_max(int value); static void set_max(int value);
private: private:
static counting_semaphore semaphore; static counting_semaphore semaphore;
friend class PackageDownloadExtractTarget; friend class PackageDownloadExtractTarget;
@ -112,6 +117,7 @@ namespace mamba
class MTransaction class MTransaction
{ {
public: public:
enum class FilterType enum class FilterType
{ {
none, none,
@ -119,16 +125,16 @@ namespace mamba
ignore ignore
}; };
MTransaction(MPool& pool, MTransaction(
const std::vector<MatchSpec>& specs_to_remove, MPool& pool,
const std::vector<MatchSpec>& specs_to_install, const std::vector<MatchSpec>& specs_to_remove,
MultiPackageCache& caches); const std::vector<MatchSpec>& specs_to_install,
MultiPackageCache& caches
);
MTransaction(MSolver& solver, MultiPackageCache& caches); MTransaction(MSolver& solver, MultiPackageCache& caches);
// Only use if the packages have been solved previously already. // Only use if the packages have been solved previously already.
MTransaction(MPool& pool, MTransaction(MPool& pool, const std::vector<PackageInfo>& packages, MultiPackageCache& caches);
const std::vector<PackageInfo>& packages,
MultiPackageCache& caches);
~MTransaction(); ~MTransaction();
@ -155,6 +161,7 @@ namespace mamba
std::pair<std::string, std::string> find_python_version(); std::pair<std::string, std::string> find_python_version();
private: private:
FilterType m_filter_type = FilterType::none; FilterType m_filter_type = FilterType::none;
std::set<Id> m_filter_name_ids; std::set<Id> m_filter_name_ids;
@ -175,14 +182,16 @@ namespace mamba
MPool& pool, MPool& pool,
const std::vector<std::string>& urls, const std::vector<std::string>& urls,
MultiPackageCache& package_caches, MultiPackageCache& package_caches,
std::vector<detail::other_pkg_mgr_spec>& other_specs); std::vector<detail::other_pkg_mgr_spec>& other_specs
);
MTransaction create_explicit_transaction_from_lockfile( MTransaction create_explicit_transaction_from_lockfile(
MPool& pool, MPool& pool,
const fs::u8path& env_lockfile_path, const fs::u8path& env_lockfile_path,
const std::vector<std::string>& categories, const std::vector<std::string>& categories,
MultiPackageCache& package_caches, MultiPackageCache& package_caches,
std::vector<detail::other_pkg_mgr_spec>& other_specs); std::vector<detail::other_pkg_mgr_spec>& other_specs
);
} // namespace mamba } // namespace mamba
#endif // MAMBA_TRANSACTION_HPP #endif // MAMBA_TRANSACTION_HPP

View File

@ -23,17 +23,22 @@ namespace mamba
fs::u8path get_python_short_path(const std::string& python_version); fs::u8path get_python_short_path(const std::string& python_version);
fs::u8path get_python_site_packages_short_path(const std::string& python_version); fs::u8path get_python_site_packages_short_path(const std::string& python_version);
fs::u8path get_bin_directory_short_path(); fs::u8path get_bin_directory_short_path();
fs::u8path get_python_noarch_target_path(const std::string& source_short_path, fs::u8path get_python_noarch_target_path(
const fs::u8path& target_site_packages_short_path); const std::string& source_short_path,
const fs::u8path& target_site_packages_short_path
);
class TransactionContext class TransactionContext
{ {
public: public:
TransactionContext(); TransactionContext();
TransactionContext& operator=(const TransactionContext&); TransactionContext& operator=(const TransactionContext&);
TransactionContext(const fs::u8path& target_prefix, TransactionContext(
const std::pair<std::string, std::string>& py_versions, const fs::u8path& target_prefix,
const std::vector<MatchSpec>& requested_specs); const std::pair<std::string, std::string>& py_versions,
const std::vector<MatchSpec>& requested_specs
);
~TransactionContext(); ~TransactionContext();
bool try_pyc_compilation(const std::vector<fs::u8path>& py_files); bool try_pyc_compilation(const std::vector<fs::u8path>& py_files);
void wait_for_pyc_compilation(); void wait_for_pyc_compilation();
@ -54,6 +59,7 @@ namespace mamba
std::vector<MatchSpec> requested_specs; std::vector<MatchSpec> requested_specs;
private: private:
bool start_pyc_compilation_process(); bool start_pyc_compilation_process();
std::unique_ptr<reproc::process> m_pyc_process = nullptr; std::unique_ptr<reproc::process> m_pyc_process = nullptr;

View File

@ -45,11 +45,13 @@ namespace mamba
void split_anaconda_token(const std::string& url, std::string& cleaned_url, std::string& token); void split_anaconda_token(const std::string& url, std::string& cleaned_url, std::string& token);
void split_scheme_auth_token(const std::string& url, void split_scheme_auth_token(
std::string& remaining_url, const std::string& url,
std::string& scheme, std::string& remaining_url,
std::string& auth, std::string& scheme,
std::string& token); std::string& auth,
std::string& token
);
bool compare_cleaned_url(const std::string& url1, const std::string& url2); bool compare_cleaned_url(const std::string& url1, const std::string& url2);
@ -69,6 +71,7 @@ namespace mamba
class URLHandler class URLHandler
{ {
public: public:
URLHandler(const std::string& url = ""); URLHandler(const std::string& url = "");
~URLHandler(); ~URLHandler();
@ -108,6 +111,7 @@ namespace mamba
URLHandler& set_zoneid(const std::string& zoneid); URLHandler& set_zoneid(const std::string& zoneid);
private: private:
std::string get_part(CURLUPart part); std::string get_part(CURLUPart part);
void set_part(CURLUPart part, const std::string& s); void set_part(CURLUPart part, const std::string& s);

View File

@ -7,23 +7,24 @@
#ifndef MAMBA_CORE_UTIL_HPP #ifndef MAMBA_CORE_UTIL_HPP
#define MAMBA_CORE_UTIL_HPP #define MAMBA_CORE_UTIL_HPP
#include "mamba/core/mamba_fs.hpp" #include <array>
#include <chrono>
#include <limits>
#include <optional>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
#include <time.h>
#include "mamba/core/error_handling.hpp" #include "mamba/core/error_handling.hpp"
#include "mamba/core/mamba_fs.hpp"
#include "mamba/core/util_string.hpp" #include "mamba/core/util_string.hpp"
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
#include "tl/expected.hpp" #include "tl/expected.hpp"
#include <array>
#include <limits>
#include <sstream>
#include <string>
#include <string_view>
#include <time.h>
#include <vector>
#include <chrono>
#include <optional>
#if defined(__PPC64__) || defined(__ppc64__) || defined(_ARCH_PPC64) #if defined(__PPC64__) || defined(__ppc64__) || defined(_ARCH_PPC64)
#include <iomanip> #include <iomanip>
#endif #endif
@ -63,20 +64,22 @@ namespace mamba
std::vector<fs::u8path> filter_dir(const fs::u8path& dir, const std::string& suffix); std::vector<fs::u8path> filter_dir(const fs::u8path& dir, const std::string& suffix);
bool paths_equal(const fs::u8path& lhs, const fs::u8path& rhs); bool paths_equal(const fs::u8path& lhs, const fs::u8path& rhs);
std::string read_contents(const fs::u8path& path, std::string
std::ios::openmode mode = std::ios::in | std::ios::binary); read_contents(const fs::u8path& path, std::ios::openmode mode = std::ios::in | std::ios::binary);
std::vector<std::string> read_lines(const fs::u8path& path); std::vector<std::string> read_lines(const fs::u8path& path);
inline void make_executable(const fs::u8path& p) inline void make_executable(const fs::u8path& p)
{ {
fs::permissions(p, fs::permissions(
fs::perms::owner_all | fs::perms::group_all | fs::perms::others_read p,
| fs::perms::others_exec); fs::perms::owner_all | fs::perms::group_all | fs::perms::others_read | fs::perms::others_exec
);
} }
class TemporaryDirectory class TemporaryDirectory
{ {
public: public:
TemporaryDirectory(); TemporaryDirectory();
~TemporaryDirectory(); ~TemporaryDirectory();
@ -88,15 +91,19 @@ namespace mamba
operator fs::u8path(); operator fs::u8path();
private: private:
fs::u8path m_path; fs::u8path m_path;
}; };
class TemporaryFile class TemporaryFile
{ {
public: public:
TemporaryFile(const std::string& prefix = "mambaf",
const std::string& suffix = "", TemporaryFile(
const std::optional<fs::u8path>& dir = std::nullopt); const std::string& prefix = "mambaf",
const std::string& suffix = "",
const std::optional<fs::u8path>& dir = std::nullopt
);
~TemporaryFile(); ~TemporaryFile();
TemporaryFile(const TemporaryFile&) = delete; TemporaryFile(const TemporaryFile&) = delete;
@ -107,6 +114,7 @@ namespace mamba
operator fs::u8path(); operator fs::u8path();
private: private:
fs::u8path m_path; fs::u8path m_path;
}; };
@ -160,6 +168,7 @@ namespace mamba
class LockFile class LockFile
{ {
public: public:
// Non-throwing constructors, attempting lock on the provided path, file or directory. // Non-throwing constructors, attempting lock on the provided path, file or directory.
// In case of a directory, a lock-file will be created, located at `this->lockfile_path()` // In case of a directory, a lock-file will be created, located at `this->lockfile_path()`
// and `this->is_locked()` (and `if(*this))` will always return true (unless this instance // and `this->is_locked()` (and `if(*this))` will always return true (unless this instance
@ -232,19 +241,22 @@ namespace mamba
std::optional<mamba_error> error() const std::optional<mamba_error> error() const
{ {
if (impl.has_value()) if (impl.has_value())
{
return {}; return {};
}
else else
{
return impl.error(); return impl.error();
}
} }
private: private:
tl::expected<std::shared_ptr<LockFileOwner>, mamba_error> impl; tl::expected<std::shared_ptr<LockFileOwner>, mamba_error> impl;
}; };
void split_package_extension(const std::string& file, void split_package_extension(const std::string& file, std::string& name, std::string& extension);
std::string& name,
std::string& extension);
fs::u8path strip_package_extension(const std::string& file); fs::u8path strip_package_extension(const std::string& file);
template <class T> template <class T>
@ -264,13 +276,17 @@ namespace mamba
void assign_or(const nlohmann::json& j, const char* key, T& target, T default_value) void assign_or(const nlohmann::json& j, const char* key, T& target, T default_value)
{ {
if (j.contains(key)) if (j.contains(key))
{
target = j[key]; target = j[key];
}
else else
{
target = default_value; target = default_value;
}
} }
std::string quote_for_shell(const std::vector<std::string>& arguments, std::string
const std::string& shell = ""); 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 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 fs::u8path& path);
@ -292,21 +308,23 @@ namespace mamba
std::time_t parse_utc_timestamp(const std::string& timestamp); std::time_t parse_utc_timestamp(const std::string& timestamp);
std::ofstream open_ofstream(const fs::u8path& path, std::ofstream
std::ios::openmode mode = std::ios::out | std::ios::binary); open_ofstream(const fs::u8path& path, std::ios::openmode mode = std::ios::out | std::ios::binary);
std::ifstream open_ifstream(const fs::u8path& path, std::ifstream
std::ios::openmode mode = std::ios::in | std::ios::binary); open_ifstream(const fs::u8path& path, std::ios::openmode mode = std::ios::in | std::ios::binary);
bool ensure_comspec_set(); bool ensure_comspec_set();
std::unique_ptr<TemporaryFile> wrap_call(const fs::u8path& root_prefix, std::unique_ptr<TemporaryFile> wrap_call(
const fs::u8path& prefix, const fs::u8path& root_prefix,
bool dev_mode, const fs::u8path& prefix,
bool debug_wrapper_scripts, bool dev_mode,
const std::vector<std::string>& arguments); bool debug_wrapper_scripts,
const std::vector<std::string>& arguments
);
std::tuple<std::vector<std::string>, std::unique_ptr<TemporaryFile>> prepare_wrapped_call( std::tuple<std::vector<std::string>, std::unique_ptr<TemporaryFile>>
const fs::u8path& prefix, const std::vector<std::string>& cmd); prepare_wrapped_call(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. /// Returns `true` if the filename matches names of files which should be interpreted as YAML.
/// NOTE: this does not check if the file exists. /// NOTE: this does not check if the file exists.
@ -320,11 +338,13 @@ namespace mamba
class non_copyable_base class non_copyable_base
{ {
public: public:
non_copyable_base() non_copyable_base()
{ {
} }
private: private:
non_copyable_base(const non_copyable_base&); non_copyable_base(const non_copyable_base&);
non_copyable_base& operator=(const non_copyable_base&); non_copyable_base& operator=(const non_copyable_base&);
}; };

View File

@ -8,11 +8,11 @@
#define MAMBA_CORE_GRAPH_UTIL_HPP #define MAMBA_CORE_GRAPH_UTIL_HPP
#include <algorithm> #include <algorithm>
#include <utility>
#include <vector>
#include <map>
#include <functional> #include <functional>
#include <iterator> #include <iterator>
#include <map>
#include <utility>
#include <vector>
namespace mamba namespace mamba
{ {
@ -20,12 +20,11 @@ namespace mamba
/** /**
* A sorted vector behaving like a set. * A sorted vector behaving like a set.
*/ */
template <typename Key, template <typename Key, typename Compare = std::less<Key>, typename Allocator = std::allocator<Key>>
typename Compare = std::less<Key>,
typename Allocator = std::allocator<Key>>
class vector_set : private std::vector<Key, Allocator> class vector_set : private std::vector<Key, Allocator>
{ {
public: public:
using Base = std::vector<Key, Allocator>; using Base = std::vector<Key, Allocator>;
using typename Base::allocator_type; using typename Base::allocator_type;
using typename Base::const_iterator; using typename Base::const_iterator;
@ -45,27 +44,29 @@ namespace mamba
using Base::size; using Base::size;
vector_set() = default; vector_set() = default;
vector_set(std::initializer_list<value_type> il, vector_set(
key_compare compare = key_compare(), std::initializer_list<value_type> il,
allocator_type const& alloc = allocator_type()); key_compare compare = key_compare(),
const allocator_type& alloc = allocator_type()
);
template <typename InputIterator> template <typename InputIterator>
vector_set(InputIterator first, vector_set(
InputIterator last, InputIterator first,
key_compare compare = key_compare(), InputIterator last,
allocator_type const& alloc = Allocator()); key_compare compare = key_compare(),
vector_set(vector_set const&) = default; const allocator_type& alloc = Allocator()
);
vector_set(const vector_set&) = default;
vector_set(vector_set&&) = default; vector_set(vector_set&&) = default;
explicit vector_set(std::vector<Key, Allocator>&& other, explicit vector_set(std::vector<Key, Allocator>&& other, key_compare compare = key_compare());
key_compare compare = key_compare()); explicit vector_set(const std::vector<Key, Allocator>& other, key_compare compare = key_compare());
explicit vector_set(std::vector<Key, Allocator> const& other,
key_compare compare = key_compare());
vector_set& operator=(vector_set const&) = default; vector_set& operator=(const vector_set&) = default;
vector_set& operator=(vector_set&&) = default; vector_set& operator=(vector_set&&) = default;
bool contains(value_type const&) const; bool contains(const value_type&) const;
value_type const& front() const noexcept; const value_type& front() const noexcept;
value_type const& back() const noexcept; const value_type& back() const noexcept;
const_iterator begin() const noexcept; const_iterator begin() const noexcept;
const_iterator end() const noexcept; const_iterator end() const noexcept;
@ -77,11 +78,12 @@ namespace mamba
* Like std::vector and unlike std::set, inserting an element invalidates iterators. * Like std::vector and unlike std::set, inserting an element invalidates iterators.
*/ */
std::pair<const_iterator, bool> insert(value_type&& value); std::pair<const_iterator, bool> insert(value_type&& value);
std::pair<const_iterator, bool> insert(value_type const& value); std::pair<const_iterator, bool> insert(const value_type& value);
template <typename InputIterator> template <typename InputIterator>
void insert(InputIterator first, InputIterator last); void insert(InputIterator first, InputIterator last);
private: private:
key_compare m_compare; key_compare m_compare;
template <typename U> template <typename U>
@ -89,16 +91,17 @@ namespace mamba
void sort_and_remove_duplicates(); void sort_and_remove_duplicates();
template <typename K, typename C, typename A> template <typename K, typename C, typename A>
friend bool operator==(vector_set<K, C, A> const& lhs, vector_set<K, C, A> const& rhs); friend bool operator==(const vector_set<K, C, A>& lhs, const vector_set<K, C, A>& rhs);
}; };
template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>> template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>>
vector_set(std::initializer_list<Key>, Compare = Compare(), Allocator = Allocator()) vector_set(std::initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
-> vector_set<Key, Compare, Allocator>; -> vector_set<Key, Compare, Allocator>;
template <class InputIt, template <
class Comp = std::less<typename std::iterator_traits<InputIt>::value_type>, class InputIt,
class Alloc = std::allocator<typename std::iterator_traits<InputIt>::value_type>> class Comp = std::less<typename std::iterator_traits<InputIt>::value_type>,
class Alloc = std::allocator<typename std::iterator_traits<InputIt>::value_type>>
vector_set(InputIt, InputIt, Comp = Comp(), Alloc = Alloc()) vector_set(InputIt, InputIt, Comp = Comp(), Alloc = Alloc())
-> vector_set<typename std::iterator_traits<InputIt>::value_type, Comp, Alloc>; -> vector_set<typename std::iterator_traits<InputIt>::value_type, Comp, Alloc>;
@ -107,18 +110,21 @@ namespace mamba
-> vector_set<Key, Compare, Allocator>; -> vector_set<Key, Compare, Allocator>;
template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>> template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>>
vector_set(std::vector<Key, Allocator> const&, Compare compare = Compare()) vector_set(const std::vector<Key, Allocator>&, Compare compare = Compare())
-> vector_set<Key, Compare, Allocator>; -> vector_set<Key, Compare, Allocator>;
template <typename Key, typename Compare, typename Allocator> template <typename Key, typename Compare, typename Allocator>
bool operator==(vector_set<Key, Compare, Allocator> const& lhs, bool operator==(
vector_set<Key, Compare, Allocator> const& rhs); const vector_set<Key, Compare, Allocator>& lhs,
const vector_set<Key, Compare, Allocator>& rhs
);
// Simplified implementation of a directed graph // Simplified implementation of a directed graph
template <typename Node, typename Derived> template <typename Node, typename Derived>
class DiGraphBase class DiGraphBase
{ {
public: public:
using node_t = Node; using node_t = Node;
using node_id = std::size_t; using node_id = std::size_t;
using node_list = std::vector<node_t>; using node_list = std::vector<node_t>;
@ -135,7 +141,7 @@ namespace mamba
std::size_t in_degree(node_id id) const noexcept; std::size_t in_degree(node_id id) const noexcept;
std::size_t out_degree(node_id id) const noexcept; std::size_t out_degree(node_id id) const noexcept;
const node_list& nodes() const; const node_list& nodes() const;
node_t const& node(node_id id) const; const node_t& node(node_id id) const;
node_t& node(node_id id); node_t& node(node_id id);
const node_id_list& successors(node_id id) const; const node_id_list& successors(node_id id) const;
const adjacency_list& successors() const; const adjacency_list& successors() const;
@ -163,10 +169,11 @@ namespace mamba
void depth_first_search(V& visitor, node_id start = node_id(0), bool reverse = false) const; void depth_first_search(V& visitor, node_id start = node_id(0), bool reverse = false) const;
protected: protected:
DiGraphBase() = default; DiGraphBase() = default;
DiGraphBase(DiGraphBase const&) = default; DiGraphBase(const DiGraphBase&) = default;
DiGraphBase(DiGraphBase&&) = default; DiGraphBase(DiGraphBase&&) = default;
DiGraphBase& operator=(DiGraphBase const&) = default; DiGraphBase& operator=(const DiGraphBase&) = default;
DiGraphBase& operator=(DiGraphBase&&) = default; DiGraphBase& operator=(DiGraphBase&&) = default;
~DiGraphBase() = default; ~DiGraphBase() = default;
@ -174,12 +181,13 @@ namespace mamba
{ {
return static_cast<Derived&>(*this); return static_cast<Derived&>(*this);
} }
Derived const& derived_cast() const const Derived& derived_cast() const
{ {
return static_cast<Derived const&>(*this); return static_cast<const Derived&>(*this);
} }
private: private:
enum class visited enum class visited
{ {
no, no,
@ -193,10 +201,12 @@ namespace mamba
node_id add_node_impl(V&& value); node_id add_node_impl(V&& value);
template <class V> template <class V>
void depth_first_search_impl(V& visitor, void depth_first_search_impl(
node_id node, V& visitor,
visited_list& status, node_id node,
adjacency_list const& successors) const; visited_list& status,
const adjacency_list& successors
) const;
node_list m_node_list; node_list m_node_list;
adjacency_list m_predecessors; adjacency_list m_predecessors;
@ -205,14 +215,17 @@ namespace mamba
}; };
template <typename Node, typename Derived> template <typename Node, typename Derived>
auto is_reachable(DiGraphBase<Node, Derived> const& graph, auto is_reachable(
typename DiGraphBase<Node, Derived>::node_id source, const DiGraphBase<Node, Derived>& graph,
typename DiGraphBase<Node, Derived>::node_id target) -> bool; typename DiGraphBase<Node, Derived>::node_id source,
typename DiGraphBase<Node, Derived>::node_id target
) -> bool;
template <class G> template <class G>
class default_visitor class default_visitor
{ {
public: public:
using graph_t = G; using graph_t = G;
using node_id = typename graph_t::node_id; using node_id = typename graph_t::node_id;
@ -244,22 +257,24 @@ namespace mamba
class DiGraph : public DiGraphBase<Node, DiGraph<Node, Edge>> class DiGraph : public DiGraphBase<Node, DiGraph<Node, Edge>>
{ {
public: public:
using Base = DiGraphBase<Node, DiGraph<Node, Edge>>; using Base = DiGraphBase<Node, DiGraph<Node, Edge>>;
using edge_t = Edge; using edge_t = Edge;
using typename Base::node_id; using typename Base::node_id;
using edge_id = std::pair<node_id, node_id>; using edge_id = std::pair<node_id, node_id>;
using edge_map = std::map<edge_id, edge_t>; using edge_map = std::map<edge_id, edge_t>;
void add_edge(node_id from, node_id to, edge_t const& data); void add_edge(node_id from, node_id to, const edge_t& data);
void add_edge(node_id from, node_id to, edge_t&& data); void add_edge(node_id from, node_id to, edge_t&& data);
const edge_map& edges() const; const edge_map& edges() const;
edge_t const& edge(node_id from, node_id to) const; const edge_t& edge(node_id from, node_id to) const;
edge_t const& edge(edge_id edge) const; const edge_t& edge(edge_id edge) const;
edge_t& edge(node_id from, node_id to); edge_t& edge(node_id from, node_id to);
edge_t& edge(edge_id edge); edge_t& edge(edge_id edge);
private: private:
template <typename T> template <typename T>
void add_edge_impl(node_id from, node_id to, T&& data); void add_edge_impl(node_id from, node_id to, T&& data);
@ -276,9 +291,11 @@ namespace mamba
*******************************/ *******************************/
template <typename K, typename C, typename A> template <typename K, typename C, typename A>
vector_set<K, C, A>::vector_set(std::initializer_list<value_type> il, vector_set<K, C, A>::vector_set(
key_compare compare, std::initializer_list<value_type> il,
allocator_type const& alloc) key_compare compare,
const allocator_type& alloc
)
: Base(std::move(il), alloc) : Base(std::move(il), alloc)
, m_compare(std::move(compare)) , m_compare(std::move(compare))
{ {
@ -287,10 +304,12 @@ namespace mamba
template <typename K, typename C, typename A> template <typename K, typename C, typename A>
template <typename InputIterator> template <typename InputIterator>
vector_set<K, C, A>::vector_set(InputIterator first, vector_set<K, C, A>::vector_set(
InputIterator last, InputIterator first,
key_compare compare, InputIterator last,
allocator_type const& alloc) key_compare compare,
const allocator_type& alloc
)
: Base(first, last, alloc) : Base(first, last, alloc)
, m_compare(std::move(compare)) , m_compare(std::move(compare))
{ {
@ -306,7 +325,7 @@ namespace mamba
} }
template <typename K, typename C, typename A> template <typename K, typename C, typename A>
vector_set<K, C, A>::vector_set(std::vector<K, A> const& other, C compare) vector_set<K, C, A>::vector_set(const std::vector<K, A>& other, C compare)
: Base(std::move(other)) : Base(std::move(other))
, m_compare(std::move(compare)) , m_compare(std::move(compare))
{ {
@ -314,19 +333,19 @@ namespace mamba
} }
template <typename K, typename C, typename A> template <typename K, typename C, typename A>
auto vector_set<K, C, A>::contains(value_type const& value) const -> bool auto vector_set<K, C, A>::contains(const value_type& value) const -> bool
{ {
return std::binary_search(begin(), end(), value); return std::binary_search(begin(), end(), value);
} }
template <typename K, typename C, typename A> template <typename K, typename C, typename A>
auto vector_set<K, C, A>::front() const noexcept -> value_type const& auto vector_set<K, C, A>::front() const noexcept -> const value_type&
{ {
return Base::front(); return Base::front();
} }
template <typename K, typename C, typename A> template <typename K, typename C, typename A>
auto vector_set<K, C, A>::back() const noexcept -> value_type const& auto vector_set<K, C, A>::back() const noexcept -> const value_type&
{ {
return Base::back(); return Base::back();
} }
@ -356,7 +375,7 @@ namespace mamba
} }
template <typename K, typename C, typename A> template <typename K, typename C, typename A>
auto vector_set<K, C, A>::insert(value_type const& value) -> std::pair<const_iterator, bool> auto vector_set<K, C, A>::insert(const value_type& value) -> std::pair<const_iterator, bool>
{ {
return insert_impl(value); return insert_impl(value);
} }
@ -395,10 +414,10 @@ namespace mamba
} }
template <typename K, typename C, typename A> template <typename K, typename C, typename A>
bool operator==(vector_set<K, C, A> const& lhs, vector_set<K, C, A> const& rhs) bool operator==(const vector_set<K, C, A>& lhs, const vector_set<K, C, A>& rhs)
{ {
return static_cast<std::vector<K, A> const&>(lhs) return static_cast<const std::vector<K, A>&>(lhs)
== static_cast<std::vector<K, A> const&>(rhs); == static_cast<const std::vector<K, A>&>(rhs);
} }
/******************************** /********************************
@ -442,7 +461,7 @@ namespace mamba
} }
template <typename N, typename G> template <typename N, typename G>
auto DiGraphBase<N, G>::node(node_id id) const -> node_t const& auto DiGraphBase<N, G>::node(node_id id) const -> const node_t&
{ {
return m_node_list[id]; return m_node_list[id];
} }
@ -513,7 +532,7 @@ namespace mamba
template <typename BinaryFunc> template <typename BinaryFunc>
BinaryFunc DiGraphBase<N, G>::for_each_edge(BinaryFunc func) const BinaryFunc DiGraphBase<N, G>::for_each_edge(BinaryFunc func) const
{ {
auto const n_nodes = number_of_nodes(); const auto n_nodes = number_of_nodes();
for (node_id i = 0; i < n_nodes; ++i) for (node_id i = 0; i < n_nodes; ++i)
{ {
for (node_id j : successors(i)) for (node_id j : successors(i))
@ -528,7 +547,7 @@ namespace mamba
template <typename UnaryFunc> template <typename UnaryFunc>
UnaryFunc DiGraphBase<N, G>::for_each_leaf(UnaryFunc func) const UnaryFunc DiGraphBase<N, G>::for_each_leaf(UnaryFunc func) const
{ {
auto const n_nodes = number_of_nodes(); const auto n_nodes = number_of_nodes();
for (node_id i = 0; i < n_nodes; ++i) for (node_id i = 0; i < n_nodes; ++i)
{ {
if (out_degree(i) == 0) if (out_degree(i) == 0)
@ -543,7 +562,7 @@ namespace mamba
template <typename UnaryFunc> template <typename UnaryFunc>
UnaryFunc DiGraphBase<N, G>::for_each_root(UnaryFunc func) const UnaryFunc DiGraphBase<N, G>::for_each_root(UnaryFunc func) const
{ {
auto const n_nodes = number_of_nodes(); const auto n_nodes = number_of_nodes();
for (node_id i = 0; i < n_nodes; ++i) for (node_id i = 0; i < n_nodes; ++i)
{ {
if (in_degree(i) == 0) if (in_degree(i) == 0)
@ -568,7 +587,7 @@ namespace mamba
{ {
} }
void start_node(node_id n, graph_t const& g) void start_node(node_id n, const graph_t& g)
{ {
if (g.out_degree(n) == 0) if (g.out_degree(n) == 0)
{ {
@ -595,7 +614,7 @@ namespace mamba
{ {
} }
void start_node(node_id n, graph_t const& g) void start_node(node_id n, const graph_t& g)
{ {
if (g.in_degree(n) == 0) if (g.in_degree(n) == 0)
{ {
@ -631,10 +650,12 @@ namespace mamba
template <typename N, typename G> template <typename N, typename G>
template <class V> template <class V>
void DiGraphBase<N, G>::depth_first_search_impl(V& visitor, void DiGraphBase<N, G>::depth_first_search_impl(
node_id node, V& visitor,
visited_list& status, node_id node,
adjacency_list const& successors) const visited_list& status,
const adjacency_list& successors
) const
{ {
status[node] = visited::ongoing; status[node] = visited::ongoing;
visitor.start_node(node, derived_cast()); visitor.start_node(node, derived_cast());
@ -665,9 +686,11 @@ namespace mamba
*******************************/ *******************************/
template <typename Node, typename Derived> template <typename Node, typename Derived>
auto is_reachable(DiGraphBase<Node, Derived> const& graph, auto is_reachable(
typename DiGraphBase<Node, Derived>::node_id source, const DiGraphBase<Node, Derived>& graph,
typename DiGraphBase<Node, Derived>::node_id target) -> bool typename DiGraphBase<Node, Derived>::node_id source,
typename DiGraphBase<Node, Derived>::node_id target
) -> bool
{ {
using graph_t = DiGraphBase<Node, Derived>; using graph_t = DiGraphBase<Node, Derived>;
using node_id = typename graph_t::node_id; using node_id = typename graph_t::node_id;
@ -692,7 +715,7 @@ namespace mamba
*********************************/ *********************************/
template <typename N, typename E> template <typename N, typename E>
void DiGraph<N, E>::add_edge(node_id from, node_id to, edge_t const& data) void DiGraph<N, E>::add_edge(node_id from, node_id to, const edge_t& data)
{ {
add_edge_impl(from, to, data); add_edge_impl(from, to, data);
} }
@ -719,13 +742,13 @@ namespace mamba
} }
template <typename N, typename E> template <typename N, typename E>
auto DiGraph<N, E>::edge(edge_id edge) const -> edge_t const& auto DiGraph<N, E>::edge(edge_id edge) const -> const edge_t&
{ {
return m_edges.at(edge); return m_edges.at(edge);
} }
template <typename N, typename E> template <typename N, typename E>
auto DiGraph<N, E>::edge(node_id from, node_id to) const -> edge_t const& auto DiGraph<N, E>::edge(node_id from, node_id to) const -> const edge_t&
{ {
return edge({ from, to }); return edge({ from, to });
} }

View File

@ -7,8 +7,8 @@
#ifndef MAMBA_CORE_UTIL_OS_HPP #ifndef MAMBA_CORE_UTIL_OS_HPP
#define MAMBA_CORE_UTIL_OS_HPP #define MAMBA_CORE_UTIL_OS_HPP
#include <string>
#include <iosfwd> #include <iosfwd>
#include <string>
#include "mamba/core/fsutil.hpp" #include "mamba/core/fsutil.hpp"
@ -42,7 +42,7 @@ namespace mamba
#ifdef _WIN32 #ifdef _WIN32
std::string to_utf8(const wchar_t* w, size_t s); std::string to_utf8(const wchar_t* w, size_t s);
std::string to_utf8(const wchar_t* w); std::string to_utf8(const wchar_t* w);
std::string to_utf8(std::wstring const& s); std::string to_utf8(const std::wstring& s);
#endif #endif
/* Test whether a given `std::ostream` object refers to a terminal. */ /* Test whether a given `std::ostream` object refers to a terminal. */

View File

@ -8,10 +8,10 @@
#define MAMBA_CORE_UTIL_RANDOM_HPP #define MAMBA_CORE_UTIL_RANDOM_HPP
#include <algorithm> #include <algorithm>
#include <cstring>
#include <limits> #include <limits>
#include <random> #include <random>
#include <string> #include <string>
#include <cstring>
namespace mamba namespace mamba
{ {
@ -20,9 +20,8 @@ namespace mamba
{ {
using std::begin; using std::begin;
using std::end; using std::end;
auto constexpr seed_bits = sizeof(typename T::result_type) * T::state_size; constexpr auto seed_bits = sizeof(typename T::result_type) * T::state_size;
auto constexpr seed_len constexpr auto seed_len = seed_bits / std::numeric_limits<std::seed_seq::result_type>::digits;
= seed_bits / std::numeric_limits<std::seed_seq::result_type>::digits;
auto seed = std::array<std::seed_seq::result_type, seed_len>{}; auto seed = std::array<std::seed_seq::result_type, seed_len>{};
auto dev = std::random_device{}; auto dev = std::random_device{};
std::generate_n(begin(seed), seed_len, std::ref(dev)); std::generate_n(begin(seed), seed_len, std::ref(dev));

View File

@ -3,9 +3,11 @@
#define MAMBA_CORE_UTIL_SCOPE_HPP #define MAMBA_CORE_UTIL_SCOPE_HPP
#include <stdexcept> #include <stdexcept>
#include "spdlog/spdlog.h"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "spdlog/spdlog.h"
namespace mamba namespace mamba
{ {

View File

@ -7,15 +7,15 @@
#ifndef MAMBA_CORE_UTIL_STRING_HPP #ifndef MAMBA_CORE_UTIL_STRING_HPP
#define MAMBA_CORE_UTIL_STRING_HPP #define MAMBA_CORE_UTIL_STRING_HPP
#include <vector> #include <algorithm>
#include <cstring>
#include <iomanip>
#include <ostream>
#include <sstream>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <ostream>
#include <cstring>
#include <sstream>
#include <algorithm>
#include <iomanip>
#include <type_traits> #include <type_traits>
#include <vector>
#include "mamba/core/util_compare.hpp" #include "mamba/core/util_compare.hpp"
@ -36,8 +36,8 @@ namespace mamba
// TODO: add concepts here, or at least some contraints // TODO: add concepts here, or at least some contraints
template <typename T, typename AssociativeContainer> template <typename T, typename AssociativeContainer>
auto contains(const AssociativeContainer& values, const T& value_to_find) auto contains(const AssociativeContainer& values, const T& value_to_find)
-> decltype(values.find(value_to_find) -> decltype(values.find(value_to_find) != values.end()) // this should make invalid usage
!= values.end()) // this should make invalid usage SFINAE // SFINAE
{ {
return values.find(value_to_find) != values.end(); return values.find(value_to_find) != values.end();
} }
@ -47,8 +47,8 @@ namespace mamba
bool starts_with_any(const std::string_view& str, const std::vector<std::string_view>& prefix); bool starts_with_any(const std::string_view& str, const std::vector<std::string_view>& prefix);
template <class CharType> template <class CharType>
std::basic_string_view<CharType> strip(const std::basic_string_view<CharType>& input, std::basic_string_view<CharType>
const std::basic_string_view<CharType>& chars) strip(const std::basic_string_view<CharType>& input, const std::basic_string_view<CharType>& chars)
{ {
size_t start = input.find_first_not_of(chars); size_t start = input.find_first_not_of(chars);
if (start == std::basic_string<CharType>::npos) if (start == std::basic_string<CharType>::npos)
@ -71,9 +71,11 @@ namespace mamba
// FIXME: doesnt support const char* mixed with other string types as input. // FIXME: doesnt support const char* mixed with other string types as input.
template <class CharType> template <class CharType>
std::vector<std::basic_string<CharType>> split(const std::basic_string_view<CharType> input, std::vector<std::basic_string<CharType>> split(
const std::basic_string_view<CharType> sep, const std::basic_string_view<CharType> input,
std::size_t max_split = SIZE_MAX) const std::basic_string_view<CharType> sep,
std::size_t max_split = SIZE_MAX
)
{ {
std::vector<std::basic_string<CharType>> result; std::vector<std::basic_string<CharType>> result;
std::size_t i = 0, j = 0, len = input.size(), n = sep.size(); std::size_t i = 0, j = 0, len = input.size(), n = sep.size();
@ -83,7 +85,9 @@ namespace mamba
if (input[i] == sep[0] && input.substr(i, n) == sep) if (input[i] == sep[0] && input.substr(i, n) == sep)
{ {
if (max_split-- <= 0) if (max_split-- <= 0)
{
break; break;
}
result.emplace_back(input.substr(j, i - j)); result.emplace_back(input.substr(j, i - j));
i = j = i + n; i = j = i + n;
} }
@ -100,16 +104,14 @@ namespace mamba
// works, so this is a workaround that fixes it // works, so this is a workaround that fixes it
// FIXME: this overload should not be necessary, but the generic version doesn't // FIXME: this overload should not be necessary, but the generic version doesn't
// work with const char* and mixed with other types for some reason. // work with const char* and mixed with other types for some reason.
inline std::vector<std::string> split(const std::string_view& input, inline std::vector<std::string>
const std::string_view& sep, split(const std::string_view& input, const std::string_view& sep, std::size_t max_split = SIZE_MAX)
std::size_t max_split = SIZE_MAX)
{ {
return split<char>(input, sep, max_split); return split<char>(input, sep, max_split);
} }
std::vector<std::string> rsplit(const std::string_view& input, std::vector<std::string>
const std::string_view& sep, rsplit(const std::string_view& input, const std::string_view& sep, std::size_t max_split = SIZE_MAX);
std::size_t max_split = SIZE_MAX);
namespace details namespace details
{ {
@ -138,7 +140,7 @@ namespace mamba
std::size_t size(const wchar_t* s); std::size_t size(const wchar_t* s);
std::size_t size(const char c); std::size_t size(const char c);
template <class T> template <class T>
std::size_t size(T const& s) std::size_t size(const T& s)
{ {
using std::size; using std::size;
return size(s); return size(s);
@ -154,7 +156,7 @@ namespace mamba
*/ */
// TODO(C++20) Take an input range and return a range // TODO(C++20) Take an input range and return a range
template <typename InputIt, typename UnaryFunction, typename Value> template <typename InputIt, typename UnaryFunction, typename Value>
UnaryFunction join_for_each(InputIt first, InputIt last, UnaryFunction func, Value const& sep) UnaryFunction join_for_each(InputIt first, InputIt last, UnaryFunction func, const Value& sep)
{ {
if (first < last) if (first < last)
{ {
@ -178,7 +180,7 @@ namespace mamba
* @see join_for_each * @see join_for_each
*/ */
template <class Range, class Value, class Joiner = details::PlusEqual> template <class Range, class Value, class Joiner = details::PlusEqual>
auto join(Value const& sep, const Range& container, Joiner joiner = details::PlusEqual{}) -> auto join(const Value& sep, const Range& container, Joiner joiner = details::PlusEqual{}) ->
typename Range::value_type typename Range::value_type
{ {
using Result = typename Range::value_type; using Result = typename Range::value_type;
@ -186,7 +188,7 @@ namespace mamba
if constexpr (details::has_reserve_v<Result>) if constexpr (details::has_reserve_v<Result>)
{ {
std::size_t final_size = 0; std::size_t final_size = 0;
auto inc_size = [&final_size](auto const& val) { final_size += details::size(val); }; auto inc_size = [&final_size](const auto& val) { final_size += details::size(val); };
join_for_each(container.begin(), container.end(), inc_size, sep); join_for_each(container.begin(), container.end(), inc_size, sep);
out.reserve(final_size); out.reserve(final_size);
} }
@ -217,13 +219,15 @@ namespace mamba
*/ */
// TODO(C++20) Take an input range and return a range // TODO(C++20) Take an input range and return a range
template <typename InputIt, typename UnaryFunction, typename Value> template <typename InputIt, typename UnaryFunction, typename Value>
UnaryFunction join_trunc_for_each(InputIt first, UnaryFunction join_trunc_for_each(
InputIt last, InputIt first,
UnaryFunction func, InputIt last,
Value const& sep, UnaryFunction func,
Value const& etc, const Value& sep,
std::size_t threshold = 5, const Value& etc,
std::pair<std::size_t, std::size_t> show = { 2, 1 }) std::size_t threshold = 5,
std::pair<std::size_t, std::size_t> show = { 2, 1 }
)
{ {
if (util::cmp_less_equal(last - first, threshold)) if (util::cmp_less_equal(last - first, threshold))
{ {
@ -243,7 +247,7 @@ namespace mamba
} }
}; };
auto const [show_head, show_tail] = show; const auto [show_head, show_tail] = show;
if (show_head > 0) if (show_head > 0)
{ {
join_for_each_func(first, first + show_head, sep); join_for_each_func(first, first + show_head, sep);
@ -271,19 +275,21 @@ namespace mamba
* @see join * @see join
*/ */
template <typename Range, typename Joiner = details::PlusEqual> template <typename Range, typename Joiner = details::PlusEqual>
auto join_trunc(Range const& range, auto join_trunc(
std::string_view sep = ", ", const Range& range,
std::string_view etc = "...", std::string_view sep = ", ",
std::size_t threshold = 5, std::string_view etc = "...",
std::pair<std::size_t, std::size_t> show = { 2, 1 }, std::size_t threshold = 5,
Joiner joiner = details::PlusEqual{}) -> typename Range::value_type std::pair<std::size_t, std::size_t> show = { 2, 1 },
Joiner joiner = details::PlusEqual{}
) -> typename Range::value_type
{ {
using Result = typename Range::value_type; using Result = typename Range::value_type;
Result out{}; Result out{};
if constexpr (details::has_reserve_v<Result>) if constexpr (details::has_reserve_v<Result>)
{ {
std::size_t final_size = 0; std::size_t final_size = 0;
auto inc_size = [&final_size](auto const& val) { final_size += details::size(val); }; auto inc_size = [&final_size](const auto& val) { final_size += details::size(val); };
join_trunc_for_each(range.begin(), range.end(), inc_size, sep, etc, threshold, show); join_trunc_for_each(range.begin(), range.end(), inc_size, sep, etc, threshold, show);
out.reserve(final_size); out.reserve(final_size);
} }

View File

@ -7,10 +7,10 @@
#ifndef MAMBA_CORE_VALIDATE_HPP #ifndef MAMBA_CORE_VALIDATE_HPP
#define MAMBA_CORE_VALIDATE_HPP #define MAMBA_CORE_VALIDATE_HPP
#include <string>
#include <vector>
#include <set> #include <set>
#include <stdexcept> #include <stdexcept>
#include <string>
#include <vector>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -37,34 +37,35 @@ namespace validate
const std::size_t MAMBA_ED25519_SIGSIZE_BYTES = 64; const std::size_t MAMBA_ED25519_SIGSIZE_BYTES = 64;
int generate_ed25519_keypair(unsigned char* pk, unsigned char* sk); int generate_ed25519_keypair(unsigned char* pk, unsigned char* sk);
std::pair<std::array<unsigned char, MAMBA_ED25519_KEYSIZE_BYTES>, std::pair<
std::array<unsigned char, MAMBA_ED25519_KEYSIZE_BYTES>> std::array<unsigned char, MAMBA_ED25519_KEYSIZE_BYTES>,
std::array<unsigned char, MAMBA_ED25519_KEYSIZE_BYTES>>
generate_ed25519_keypair(); generate_ed25519_keypair();
std::pair<std::string, std::string> generate_ed25519_keypair_hex(); std::pair<std::string, std::string> generate_ed25519_keypair_hex();
int sign(const std::string& data, const unsigned char* sk, unsigned char* signature); int sign(const std::string& data, const unsigned char* sk, unsigned char* signature);
int sign(const std::string& data, const std::string& sk, std::string& signature); int sign(const std::string& data, const std::string& sk, std::string& signature);
std::array<unsigned char, MAMBA_ED25519_SIGSIZE_BYTES> ed25519_sig_hex_to_bytes( std::array<unsigned char, MAMBA_ED25519_SIGSIZE_BYTES>
const std::string& sig_hex) noexcept; ed25519_sig_hex_to_bytes(const std::string& sig_hex) noexcept;
std::array<unsigned char, MAMBA_ED25519_SIGSIZE_BYTES> ed25519_sig_hex_to_bytes( std::array<unsigned char, MAMBA_ED25519_SIGSIZE_BYTES>
const std::string& sig_hex, int& error_code) noexcept; ed25519_sig_hex_to_bytes(const std::string& sig_hex, int& error_code) noexcept;
std::array<unsigned char, MAMBA_ED25519_KEYSIZE_BYTES> ed25519_key_hex_to_bytes( std::array<unsigned char, MAMBA_ED25519_KEYSIZE_BYTES>
const std::string& key_hex) noexcept; ed25519_key_hex_to_bytes(const std::string& key_hex) noexcept;
std::array<unsigned char, MAMBA_ED25519_KEYSIZE_BYTES> ed25519_key_hex_to_bytes( std::array<unsigned char, MAMBA_ED25519_KEYSIZE_BYTES>
const std::string& key_hex, int& error_code) noexcept; ed25519_key_hex_to_bytes(const std::string& key_hex, int& error_code) noexcept;
int verify(const unsigned char* data, int verify(
std::size_t data_len, const unsigned char* data,
const unsigned char* pk, std::size_t data_len,
const unsigned char* signature); const unsigned char* pk,
const unsigned char* signature
);
int verify(const std::string& data, const unsigned char* pk, const unsigned char* signature); int verify(const std::string& data, const unsigned char* pk, const unsigned char* signature);
int verify(const std::string& data, int verify(const std::string& data, const std::string& pk_hex, const std::string& signature_hex);
const std::string& pk_hex,
const std::string& signature_hex);
/** /**
* Verify a GPG/PGP signature against the hash of the binary data and * Verify a GPG/PGP signature against the hash of the binary data and
@ -72,15 +73,15 @@ namespace validate
* See RFC4880, section 5.2.4 https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.4 * See RFC4880, section 5.2.4 https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.4
* This method assumes hash function to be SHA-256 * This method assumes hash function to be SHA-256
*/ */
int verify_gpg_hashed_msg(const unsigned char* data, int verify_gpg_hashed_msg(
const unsigned char* pk, const unsigned char* data,
const unsigned char* signature); const unsigned char* pk,
int verify_gpg_hashed_msg(const std::string& data, const unsigned char* signature
const unsigned char* pk, );
const unsigned char* signature); int
int verify_gpg_hashed_msg(const std::string& data, verify_gpg_hashed_msg(const std::string& data, const unsigned char* pk, const unsigned char* signature);
const std::string& pk, int
const std::string& signature); verify_gpg_hashed_msg(const std::string& data, const std::string& pk, const std::string& signature);
/** /**
* Verify a GPG/PGP signature against the binary data and * Verify a GPG/PGP signature against the binary data and
@ -88,10 +89,12 @@ namespace validate
* See RFC4880, section 5.2.4 https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.4 * See RFC4880, section 5.2.4 https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.4
* This method assumes hash function to be SHA-256 * This method assumes hash function to be SHA-256
*/ */
int verify_gpg(const std::string& data, int verify_gpg(
const std::string& gpg_v4_trailer, const std::string& data,
const std::string& pk, const std::string& gpg_v4_trailer,
const std::string& signature); const std::string& pk,
const std::string& signature
);
/** /**
* Base class for artifact/package verification error. * Base class for artifact/package verification error.
@ -99,11 +102,13 @@ namespace validate
class trust_error : public std::exception class trust_error : public std::exception
{ {
public: public:
trust_error(const std::string& message) noexcept; trust_error(const std::string& message) noexcept;
virtual ~trust_error() = default; virtual ~trust_error() = default;
virtual const char* what() const noexcept override; virtual const char* what() const noexcept override;
private: private:
std::string m_message; std::string m_message;
}; };
@ -116,6 +121,7 @@ namespace validate
class threshold_error : public trust_error class threshold_error : public trust_error
{ {
public: public:
threshold_error() noexcept; threshold_error() noexcept;
virtual ~threshold_error() = default; virtual ~threshold_error() = default;
}; };
@ -127,6 +133,7 @@ namespace validate
class role_metadata_error : public trust_error class role_metadata_error : public trust_error
{ {
public: public:
role_metadata_error() noexcept; role_metadata_error() noexcept;
virtual ~role_metadata_error() = default; virtual ~role_metadata_error() = default;
}; };
@ -139,6 +146,7 @@ namespace validate
class role_file_error : public trust_error class role_file_error : public trust_error
{ {
public: public:
role_file_error() noexcept; role_file_error() noexcept;
virtual ~role_file_error() = default; virtual ~role_file_error() = default;
}; };
@ -151,6 +159,7 @@ namespace validate
class rollback_error : public trust_error class rollback_error : public trust_error
{ {
public: public:
rollback_error() noexcept; rollback_error() noexcept;
virtual ~rollback_error() = default; virtual ~rollback_error() = default;
}; };
@ -163,6 +172,7 @@ namespace validate
class freeze_error : public trust_error class freeze_error : public trust_error
{ {
public: public:
freeze_error() noexcept; freeze_error() noexcept;
virtual ~freeze_error() = default; virtual ~freeze_error() = default;
}; };
@ -175,6 +185,7 @@ namespace validate
class spec_version_error : public trust_error class spec_version_error : public trust_error
{ {
public: public:
spec_version_error() noexcept; spec_version_error() noexcept;
virtual ~spec_version_error() = default; virtual ~spec_version_error() = default;
}; };
@ -187,6 +198,7 @@ namespace validate
class fetching_error : public trust_error class fetching_error : public trust_error
{ {
public: public:
fetching_error() noexcept; fetching_error() noexcept;
virtual ~fetching_error() = default; virtual ~fetching_error() = default;
}; };
@ -199,6 +211,7 @@ namespace validate
class package_error : public trust_error class package_error : public trust_error
{ {
public: public:
package_error() noexcept; package_error() noexcept;
virtual ~package_error() = default; virtual ~package_error() = default;
}; };
@ -210,6 +223,7 @@ namespace validate
class role_error : public trust_error class role_error : public trust_error
{ {
public: public:
role_error() noexcept; role_error() noexcept;
virtual ~role_error() = default; virtual ~role_error() = default;
}; };
@ -221,6 +235,7 @@ namespace validate
class index_error : public trust_error class index_error : public trust_error
{ {
public: public:
index_error() noexcept; index_error() noexcept;
virtual ~index_error() = default; virtual ~index_error() = default;
}; };
@ -324,6 +339,7 @@ namespace validate
class TimeRef class TimeRef
{ {
public: public:
static TimeRef& instance(); static TimeRef& instance();
void set(const std::time_t& time); void set(const std::time_t& time);
@ -331,10 +347,12 @@ namespace validate
std::string timestamp(); std::string timestamp();
protected: protected:
TimeRef(); TimeRef();
~TimeRef(); ~TimeRef();
private: private:
std::time_t m_time_ref; std::time_t m_time_ref;
}; };
@ -345,6 +363,7 @@ namespace validate
class SpecBase class SpecBase
{ {
public: public:
virtual ~SpecBase() = default; virtual ~SpecBase() = default;
std::string version_str() const; std::string version_str() const;
@ -369,12 +388,14 @@ namespace validate
virtual std::set<RoleSignature> signatures(const json& j) const = 0; virtual std::set<RoleSignature> signatures(const json& j) const = 0;
protected: protected:
SpecBase(const std::string& spec_version); SpecBase(const std::string& spec_version);
SpecBase() = delete; SpecBase() = delete;
std::string get_json_value(const json& j) const; std::string get_json_value(const json& j) const;
private: private:
std::string m_spec_version; std::string m_spec_version;
}; };
@ -388,6 +409,7 @@ namespace validate
class RoleBase class RoleBase
{ {
public: public:
RoleBase(const std::string& type, std::shared_ptr<SpecBase> sv); RoleBase(const std::string& type, std::shared_ptr<SpecBase> sv);
virtual ~RoleBase() = 0; virtual ~RoleBase() = 0;
@ -410,6 +432,7 @@ namespace validate
friend void from_json(const json& j, RoleBase* r); friend void from_json(const json& j, RoleBase* r);
protected: protected:
json read_json_file(const fs::u8path& p, bool update = false) const; json read_json_file(const fs::u8path& p, bool update = false) const;
/** /**
@ -424,9 +447,11 @@ namespace validate
* Check that a threshold of valid signatures is met * Check that a threshold of valid signatures is met
* for the signed metadata, using a set of keys. * for the signed metadata, using a set of keys.
*/ */
void check_signatures(const std::string& signed_data, void check_signatures(
const std::set<RoleSignature>& signatures, const std::string& signed_data,
const RoleFullKeys& keyring) const; const std::set<RoleSignature>& signatures,
const RoleFullKeys& keyring
) const;
void set_spec_version(std::shared_ptr<SpecBase> sv); void set_spec_version(std::shared_ptr<SpecBase> sv);
void set_expiration(const std::string& expires); void set_expiration(const std::string& expires);
@ -448,6 +473,7 @@ namespace validate
std::map<std::string, RoleFullKeys> m_defined_roles; std::map<std::string, RoleFullKeys> m_defined_roles;
private: private:
std::string m_internal_type; std::string m_internal_type;
std::string m_type; std::string m_type;
std::shared_ptr<SpecBase> p_spec; std::shared_ptr<SpecBase> p_spec;
@ -465,6 +491,7 @@ namespace validate
class RootRole : public RoleBase class RootRole : public RoleBase
{ {
public: public:
virtual ~RootRole() = default; virtual ~RootRole() = default;
std::unique_ptr<RootRole> update(fs::u8path path); std::unique_ptr<RootRole> update(fs::u8path path);
@ -472,14 +499,15 @@ namespace validate
std::vector<fs::u8path> possible_update_files(); std::vector<fs::u8path> possible_update_files();
virtual std::unique_ptr<RepoIndexChecker> build_index_checker( virtual std::unique_ptr<RepoIndexChecker>
const std::string& url, const fs::u8path& cache_path) const build_index_checker(const std::string& url, const fs::u8path& cache_path) const = 0;
= 0;
protected: protected:
RootRole(std::shared_ptr<SpecBase> spec); RootRole(std::shared_ptr<SpecBase> spec);
private: private:
virtual std::unique_ptr<RootRole> create_update(const json& j) = 0; virtual std::unique_ptr<RootRole> create_update(const json& j) = 0;
}; };
@ -491,12 +519,14 @@ namespace validate
class RepoIndexChecker class RepoIndexChecker
{ {
public: public:
virtual ~RepoIndexChecker() = default; virtual ~RepoIndexChecker() = default;
virtual void verify_index(const json& j) const = 0; virtual void verify_index(const json& j) const = 0;
virtual void verify_index(const fs::u8path& p) const = 0; virtual void verify_index(const fs::u8path& p) const = 0;
virtual void verify_package(const json& signed_data, const json& signatures) const = 0; virtual void verify_package(const json& signed_data, const json& signatures) const = 0;
protected: protected:
RepoIndexChecker() = default; RepoIndexChecker() = default;
}; };
@ -509,15 +539,18 @@ namespace validate
class RepoChecker class RepoChecker
{ {
public: public:
/** /**
* Constructor. * Constructor.
* @param base_url Repository base URL * @param base_url Repository base URL
* @param ref_path Path to the reference directory, hosting trusted root metadata * @param ref_path Path to the reference directory, hosting trusted root metadata
* @param cache_path Path to the cache directory * @param cache_path Path to the cache directory
*/ */
RepoChecker(const std::string& base_url, RepoChecker(
const fs::u8path& ref_path, const std::string& base_url,
const fs::u8path& cache_path = ""); const fs::u8path& ref_path,
const fs::u8path& cache_path = ""
);
// Forwarding to a ``RepoIndexChecker`` implementation // Forwarding to a ``RepoIndexChecker`` implementation
void verify_index(const json& j) const; void verify_index(const json& j) const;
@ -531,6 +564,7 @@ namespace validate
std::size_t root_version(); std::size_t root_version();
private: private:
std::string m_base_url; std::string m_base_url;
std::size_t m_root_version = 0; std::size_t m_root_version = 0;
fs::u8path m_ref_path; fs::u8path m_ref_path;
@ -556,6 +590,7 @@ namespace validate
class SpecImpl final : public SpecBase class SpecImpl final : public SpecBase
{ {
public: public:
SpecImpl(const std::string& sv = "1.0.17"); SpecImpl(const std::string& sv = "1.0.17");
std::string json_key() const override; std::string json_key() const override;
@ -573,18 +608,20 @@ namespace validate
class RootImpl final : public RootRole class RootImpl final : public RootRole
{ {
public: public:
RootImpl(const fs::u8path& p); RootImpl(const fs::u8path& p);
RootImpl(const json& j); RootImpl(const json& j);
RoleFullKeys self_keys() const override; RoleFullKeys self_keys() const override;
std::unique_ptr<RepoIndexChecker> build_index_checker( std::unique_ptr<RepoIndexChecker>
const std::string& url, const fs::u8path& cache_path) const override; build_index_checker(const std::string& url, const fs::u8path& cache_path) const override;
friend void to_json(json& j, const RootImpl& r); friend void to_json(json& j, const RootImpl& r);
friend void from_json(const json& j, RootImpl& r); friend void from_json(const json& j, RootImpl& r);
private: private:
RootImpl() = delete; RootImpl() = delete;
void load_from_json(const json& j); void load_from_json(const json& j);
@ -594,8 +631,8 @@ namespace validate
std::set<std::string> mandatory_defined_roles() const override; std::set<std::string> mandatory_defined_roles() const override;
std::set<std::string> optionally_defined_roles() const override; std::set<std::string> optionally_defined_roles() const override;
void set_defined_roles(std::map<std::string, Key> keys, void
std::map<std::string, RoleKeys> roles); set_defined_roles(std::map<std::string, Key> keys, std::map<std::string, RoleKeys> roles);
}; };
} }
@ -608,6 +645,7 @@ namespace validate
class SpecImpl final : public SpecBase class SpecImpl final : public SpecBase
{ {
public: public:
SpecImpl(const std::string& sv = "0.6.0"); SpecImpl(const std::string& sv = "0.6.0");
std::string json_key() const override; std::string json_key() const override;
@ -622,11 +660,13 @@ namespace validate
class V06RoleBaseExtension class V06RoleBaseExtension
{ {
public: public:
void set_timestamp(const std::string& ts); void set_timestamp(const std::string& ts);
std::string timestamp() const; std::string timestamp() const;
protected: protected:
std::string m_timestamp; std::string m_timestamp;
void check_timestamp_format() const; void check_timestamp_format() const;
@ -644,6 +684,7 @@ namespace validate
, public V06RoleBaseExtension , public V06RoleBaseExtension
{ {
public: public:
RootImpl(const fs::u8path& p); RootImpl(const fs::u8path& p);
RootImpl(const json& j); RootImpl(const json& j);
RootImpl(const std::string& json_str); RootImpl(const std::string& json_str);
@ -652,15 +693,14 @@ namespace validate
* Return a ``RepoIndexChecker`` implementation (derived class) * Return a ``RepoIndexChecker`` implementation (derived class)
* from repository base URL. * from repository base URL.
*/ */
std::unique_ptr<RepoIndexChecker> build_index_checker( std::unique_ptr<RepoIndexChecker>
const std::string& url, const fs::u8path& cache_path) const override; build_index_checker(const std::string& url, const fs::u8path& cache_path) const override;
RoleFullKeys self_keys() const override; RoleFullKeys self_keys() const override;
json upgraded_signable() const; json upgraded_signable() const;
RoleSignature upgraded_signature(const json& j, RoleSignature
const std::string& pk, upgraded_signature(const json& j, const std::string& pk, const unsigned char* sk) const;
const unsigned char* sk) const;
KeyMgrRole create_key_mgr(const fs::u8path& p) const; KeyMgrRole create_key_mgr(const fs::u8path& p) const;
KeyMgrRole create_key_mgr(const json& j) const; KeyMgrRole create_key_mgr(const json& j) const;
@ -669,6 +709,7 @@ namespace validate
friend void from_json(const json& j, RootImpl& r); friend void from_json(const json& j, RootImpl& r);
private: private:
RootImpl() = delete; RootImpl() = delete;
void load_from_json(const json& j); void load_from_json(const json& j);
@ -693,15 +734,14 @@ namespace validate
, public V06RoleBaseExtension , public V06RoleBaseExtension
{ {
public: public:
KeyMgrRole(const fs::u8path& p,
const RoleFullKeys& keys, KeyMgrRole(const fs::u8path& p, const RoleFullKeys& keys, const std::shared_ptr<SpecBase> spec);
const std::shared_ptr<SpecBase> spec); KeyMgrRole(const json& j, const RoleFullKeys& keys, const std::shared_ptr<SpecBase> spec);
KeyMgrRole(const json& j, KeyMgrRole(
const RoleFullKeys& keys, const std::string& json_str,
const std::shared_ptr<SpecBase> spec); const RoleFullKeys& keys,
KeyMgrRole(const std::string& json_str, const std::shared_ptr<SpecBase> spec
const RoleFullKeys& keys, );
const std::shared_ptr<SpecBase> spec);
// std::set<std::string> roles() const override; // std::set<std::string> roles() const override;
RoleFullKeys self_keys() const override; RoleFullKeys self_keys() const override;
@ -713,13 +753,14 @@ namespace validate
* Return a ``RepoIndexChecker`` implementation (derived class) * Return a ``RepoIndexChecker`` implementation (derived class)
* from repository base URL. * from repository base URL.
*/ */
std::unique_ptr<RepoIndexChecker> build_index_checker( std::unique_ptr<RepoIndexChecker>
const std::string& url, const fs::u8path& cache_path) const; build_index_checker(const std::string& url, const fs::u8path& cache_path) const;
friend void to_json(json& j, const KeyMgrRole& r); friend void to_json(json& j, const KeyMgrRole& r);
friend void from_json(const json& j, KeyMgrRole& r); friend void from_json(const json& j, KeyMgrRole& r);
private: private:
KeyMgrRole() = delete; KeyMgrRole() = delete;
void load_from_json(const json& j); void load_from_json(const json& j);
@ -746,16 +787,15 @@ namespace validate
, public RepoIndexChecker , public RepoIndexChecker
{ {
public: public:
PkgMgrRole(const RoleFullKeys& keys, const std::shared_ptr<SpecBase> spec); PkgMgrRole(const RoleFullKeys& keys, const std::shared_ptr<SpecBase> spec);
PkgMgrRole(const fs::u8path& p, PkgMgrRole(const fs::u8path& p, const RoleFullKeys& keys, const std::shared_ptr<SpecBase> spec);
const RoleFullKeys& keys, PkgMgrRole(const json& j, const RoleFullKeys& keys, const std::shared_ptr<SpecBase> spec);
const std::shared_ptr<SpecBase> spec); PkgMgrRole(
PkgMgrRole(const json& j, const std::string& json_str,
const RoleFullKeys& keys, const RoleFullKeys& keys,
const std::shared_ptr<SpecBase> spec); const std::shared_ptr<SpecBase> spec
PkgMgrRole(const std::string& json_str, );
const RoleFullKeys& keys,
const std::shared_ptr<SpecBase> spec);
void verify_index(const fs::u8path& p) const override; void verify_index(const fs::u8path& p) const override;
void verify_index(const json& j) const override; void verify_index(const json& j) const override;
@ -765,6 +805,7 @@ namespace validate
friend void from_json(const json& j, PkgMgrRole& r); friend void from_json(const json& j, PkgMgrRole& r);
private: private:
PkgMgrRole() = delete; PkgMgrRole() = delete;
void load_from_json(const json& j); void load_from_json(const json& j);

View File

@ -7,10 +7,10 @@
#ifndef MAMBA_CORE_VIRTUAL_PACKAGES_HPP #ifndef MAMBA_CORE_VIRTUAL_PACKAGES_HPP
#define MAMBA_CORE_VIRTUAL_PACKAGES_HPP #define MAMBA_CORE_VIRTUAL_PACKAGES_HPP
#include "mamba/core/package_info.hpp"
#include <vector>
#include <string> #include <string>
#include <vector>
#include "mamba/core/package_info.hpp"
namespace mamba namespace mamba
{ {
@ -21,9 +21,11 @@ namespace mamba
std::string cuda_version(); std::string cuda_version();
std::string get_arch(); std::string get_arch();
PackageInfo make_virtual_package(const std::string& name, PackageInfo make_virtual_package(
const std::string& version = "", const std::string& name,
const std::string& build_string = ""); const std::string& version = "",
const std::string& build_string = ""
);
std::vector<PackageInfo> dist_packages(); std::vector<PackageInfo> dist_packages();
} }

View File

@ -26,8 +26,7 @@
(LIBMAMBA_VERSION_MAJOR * 10000 + LIBMAMBA_VERSION_MINOR * 100 + LIBMAMBA_VERSION_PATCH) (LIBMAMBA_VERSION_MAJOR * 10000 + LIBMAMBA_VERSION_MINOR * 100 + LIBMAMBA_VERSION_PATCH)
#define LIBMAMBA_VERSION_STRING \ #define LIBMAMBA_VERSION_STRING \
__LIBMAMBA_STRINGIZE(LIBMAMBA_VERSION_MAJOR) \ __LIBMAMBA_STRINGIZE(LIBMAMBA_VERSION_MAJOR) \
"." __LIBMAMBA_STRINGIZE(LIBMAMBA_VERSION_MINOR) "." __LIBMAMBA_STRINGIZE( \ "." __LIBMAMBA_STRINGIZE(LIBMAMBA_VERSION_MINOR) "." __LIBMAMBA_STRINGIZE(LIBMAMBA_VERSION_PATCH)
LIBMAMBA_VERSION_PATCH)
namespace mamba namespace mamba
{ {

View File

@ -5,6 +5,9 @@
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/api/c_api.h" #include "mamba/api/c_api.h"
#include <string>
#include "mamba/api/config.hpp" #include "mamba/api/config.hpp"
#include "mamba/api/configuration.hpp" #include "mamba/api/configuration.hpp"
#include "mamba/api/create.hpp" #include "mamba/api/create.hpp"
@ -14,8 +17,6 @@
#include "mamba/api/remove.hpp" #include "mamba/api/remove.hpp"
#include "mamba/api/update.hpp" #include "mamba/api/update.hpp"
#include <string>
using namespace mamba; using namespace mamba;

View File

@ -37,9 +37,8 @@ namespace mamba
} }
} }
expected_t<void, mamba_aggregated_error> load_channels(MPool& pool, expected_t<void, mamba_aggregated_error>
MultiPackageCache& package_caches, load_channels(MPool& pool, MultiPackageCache& package_caches, int is_retry)
int is_retry)
{ {
int RETRY_SUBDIR_FETCH = 1 << 0; int RETRY_SUBDIR_FETCH = 1 << 0;
@ -62,8 +61,7 @@ namespace mamba
{ {
for (auto& [platform, url] : channel->platform_urls(true)) for (auto& [platform, url] : channel->platform_urls(true))
{ {
auto sdires auto sdires = MSubdirData::create(*channel, platform, url, package_caches, "repodata.json");
= MSubdirData::create(*channel, platform, url, package_caches, "repodata.json");
if (!sdires.has_value()) if (!sdires.has_value())
{ {
error_list.push_back(std::move(sdires).error()); error_list.push_back(std::move(sdires).error());
@ -99,8 +97,8 @@ namespace mamba
multi_dl.download(MAMBA_NO_CLEAR_PROGRESS_BARS); multi_dl.download(MAMBA_NO_CLEAR_PROGRESS_BARS);
if (is_sig_interrupted()) if (is_sig_interrupted())
{ {
error_list.push_back( error_list.push_back(mamba_error("Interrupted by user", mamba_error_code::user_interrupted)
mamba_error("Interrupted by user", mamba_error_code::user_interrupted)); );
return tl::unexpected(mamba_aggregated_error(std::move(error_list))); return tl::unexpected(mamba_aggregated_error(std::move(error_list)));
} }
@ -131,7 +129,9 @@ namespace mamba
{ {
LOG_INFO << "Creating repo from pkgs_dir for offline"; LOG_INFO << "Creating repo from pkgs_dir for offline";
for (const auto& c : ctx.pkgs_dirs) for (const auto& c : ctx.pkgs_dirs)
{
detail::create_repo_from_pkgs_dir(pool, c); detail::create_repo_from_pkgs_dir(pool, c);
}
} }
std::string prev_channel; std::string prev_channel;
bool loading_failed = false; bool loading_failed = false;
@ -142,8 +142,10 @@ namespace mamba
{ {
if (!ctx.offline && mamba::ends_with(subdir.name(), "/noarch")) if (!ctx.offline && mamba::ends_with(subdir.name(), "/noarch"))
{ {
error_list.push_back(mamba_error("Subdir " + subdir.name() + " not loaded!", error_list.push_back(mamba_error(
mamba_error_code::subdirdata_not_loaded)); "Subdir " + subdir.name() + " not loaded!",
mamba_error_code::subdirdata_not_loaded
));
} }
continue; continue;
} }
@ -161,8 +163,7 @@ namespace mamba
std::stringstream ss; std::stringstream ss;
ss << "Could not load repodata.json for " << subdir.name() << " after retry." ss << "Could not load repodata.json for " << subdir.name() << " after retry."
<< "Please check repodata source. Exiting." << std::endl; << "Please check repodata source. Exiting." << std::endl;
error_list.push_back( error_list.push_back(mamba_error(ss.str(), mamba_error_code::repodata_not_loaded));
mamba_error(ss.str(), mamba_error_code::repodata_not_loaded));
} }
else else
{ {
@ -181,8 +182,10 @@ namespace mamba
LOG_WARNING << "Encountered malformed repodata.json cache. Redownloading."; LOG_WARNING << "Encountered malformed repodata.json cache. Redownloading.";
return load_channels(pool, package_caches, is_retry | RETRY_SUBDIR_FETCH); return load_channels(pool, package_caches, is_retry | RETRY_SUBDIR_FETCH);
} }
error_list.push_back(mamba_error("Could not load repodata. Cache corrupted?", error_list.push_back(mamba_error(
mamba_error_code::repodata_not_loaded)); "Could not load repodata. Cache corrupted?",
mamba_error_code::repodata_not_loaded
));
} }
using return_type = expected_t<void, mamba_aggregated_error>; using return_type = expected_t<void, mamba_aggregated_error>;
return error_list.empty() ? return_type() return error_list.empty() ? return_type()

View File

@ -4,11 +4,11 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/api/clean.hpp"
#include <iostream> #include <iostream>
#include "mamba/api/clean.hpp"
#include "mamba/api/configuration.hpp" #include "mamba/api/configuration.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/mamba_fs.hpp" #include "mamba/core/mamba_fs.hpp"
#include "mamba/core/package_cache.hpp" #include "mamba/core/package_cache.hpp"
@ -50,6 +50,7 @@ namespace mamba
Console::stream() << "Cleaning index cache.."; Console::stream() << "Cleaning index cache..";
for (auto* pkg_cache : caches.writable_caches()) for (auto* pkg_cache : caches.writable_caches())
{
if (fs::exists(pkg_cache->path() / "cache")) if (fs::exists(pkg_cache->path() / "cache"))
{ {
try try
@ -61,6 +62,7 @@ namespace mamba
LOG_WARNING << "Could not clean " << pkg_cache->path() / "cache"; LOG_WARNING << "Could not clean " << pkg_cache->path() / "cache";
} }
} }
}
} }
if (!ctx.dry_run && (clean_locks || clean_all)) if (!ctx.dry_run && (clean_locks || clean_all))
@ -70,6 +72,7 @@ namespace mamba
for (auto* pkg_cache : caches.writable_caches()) for (auto* pkg_cache : caches.writable_caches())
{ {
if (fs::exists(pkg_cache->path())) if (fs::exists(pkg_cache->path()))
{
for (auto& p : fs::directory_iterator(pkg_cache->path())) for (auto& p : fs::directory_iterator(pkg_cache->path()))
{ {
if (p.exists() && ends_with(p.path().string(), ".lock") if (p.exists() && ends_with(p.path().string(), ".lock")
@ -89,8 +92,10 @@ namespace mamba
} }
} }
} }
}
if (fs::exists(pkg_cache->path() / "cache")) if (fs::exists(pkg_cache->path() / "cache"))
{
for (auto& p : fs::recursive_directory_iterator(pkg_cache->path() / "cache")) for (auto& p : fs::recursive_directory_iterator(pkg_cache->path() / "cache"))
{ {
if (p.exists() && ends_with(p.path().string(), ".lock")) if (p.exists() && ends_with(p.path().string(), ".lock"))
@ -107,6 +112,7 @@ namespace mamba
} }
} }
} }
}
} }
} }
@ -165,8 +171,7 @@ namespace mamba
for (auto* pkg_cache : caches.writable_caches()) for (auto* pkg_cache : caches.writable_caches())
{ {
std::string header_line std::string header_line = concat("Package cache folder: ", pkg_cache->path().string());
= concat("Package cache folder: ", pkg_cache->path().string());
std::vector<std::vector<printers::FormattedString>> rows; std::vector<std::vector<printers::FormattedString>> rows;
for (auto& p : fs::directory_iterator(pkg_cache->path())) for (auto& p : fs::directory_iterator(pkg_cache->path()))
{ {
@ -176,14 +181,15 @@ namespace mamba
|| ends_with(p.path().string(), ".conda"))) || ends_with(p.path().string(), ".conda")))
{ {
res.push_back(p.path()); res.push_back(p.path());
rows.push_back( rows.push_back({ p.path().filename().string(), get_file_size(p.file_size()) });
{ p.path().filename().string(), get_file_size(p.file_size()) });
total_size += p.file_size(); total_size += p.file_size();
} }
} }
std::sort(rows.begin(), std::sort(
rows.end(), rows.begin(),
[](const auto& a, const auto& b) { return a[0].s < b[0].s; }); rows.end(),
[](const auto& a, const auto& b) { return a[0].s < b[0].s; }
);
t.add_rows(pkg_cache->path().string(), rows); t.add_rows(pkg_cache->path().string(), rows);
} }
if (total_size) if (total_size)
@ -239,29 +245,28 @@ namespace mamba
for (auto* pkg_cache : caches.writable_caches()) for (auto* pkg_cache : caches.writable_caches())
{ {
std::string header_line std::string header_line = concat("Package cache folder: ", pkg_cache->path().string());
= concat("Package cache folder: ", pkg_cache->path().string());
std::vector<std::vector<printers::FormattedString>> rows; std::vector<std::vector<printers::FormattedString>> rows;
for (auto& p : fs::directory_iterator(pkg_cache->path())) for (auto& p : fs::directory_iterator(pkg_cache->path()))
{ {
if (p.is_directory() && fs::exists(p.path() / "info" / "index.json")) if (p.is_directory() && fs::exists(p.path() / "info" / "index.json"))
{ {
if (installed_pkgs.find(p.path().filename().string()) if (installed_pkgs.find(p.path().filename().string()) != installed_pkgs.end())
!= installed_pkgs.end())
{ {
// do not remove installed packages // do not remove installed packages
continue; continue;
} }
res.push_back(p.path()); res.push_back(p.path());
std::size_t folder_size = get_folder_size(p); std::size_t folder_size = get_folder_size(p);
rows.push_back( rows.push_back({ p.path().filename().string(), get_file_size(folder_size) });
{ p.path().filename().string(), get_file_size(folder_size) });
total_size += folder_size; total_size += folder_size;
} }
} }
std::sort(rows.begin(), std::sort(
rows.end(), rows.begin(),
[](const auto& a, const auto& b) { return a[0].s < b[0].s; }); rows.end(),
[](const auto& a, const auto& b) { return a[0].s < b[0].s; }
);
t.add_rows(pkg_cache->path().string(), rows); t.add_rows(pkg_cache->path().string(), rows);
} }
if (total_size) if (total_size)

View File

@ -18,12 +18,14 @@ namespace mamba
config.at("use_target_prefix_fallback").set_value(true); config.at("use_target_prefix_fallback").set_value(true);
config.at("show_banner").set_value(false); config.at("show_banner").set_value(false);
config.at("target_prefix_checks") config.at("target_prefix_checks")
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX .set_value(
| MAMBA_ALLOW_NOT_ENV_PREFIX | MAMBA_NOT_EXPECT_EXISTING_PREFIX); MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX
| MAMBA_ALLOW_NOT_ENV_PREFIX | MAMBA_NOT_EXPECT_EXISTING_PREFIX
);
config.load(); config.load();
auto show_group auto show_group = config.at("show_config_groups").value<bool>() ? MAMBA_SHOW_CONFIG_GROUPS
= config.at("show_config_groups").value<bool>() ? MAMBA_SHOW_CONFIG_GROUPS : 0; : 0;
auto show_long_desc = config.at("show_config_long_descriptions").value<bool>() auto show_long_desc = config.at("show_config_long_descriptions").value<bool>()
? MAMBA_SHOW_CONFIG_LONG_DESCS ? MAMBA_SHOW_CONFIG_LONG_DESCS
: 0; : 0;
@ -42,19 +44,21 @@ namespace mamba
config.at("use_target_prefix_fallback").set_value(true); config.at("use_target_prefix_fallback").set_value(true);
config.at("show_banner").set_value(false); config.at("show_banner").set_value(false);
config.at("target_prefix_checks") config.at("target_prefix_checks")
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX .set_value(
| MAMBA_ALLOW_NOT_ENV_PREFIX | MAMBA_NOT_EXPECT_EXISTING_PREFIX); MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX
| MAMBA_ALLOW_NOT_ENV_PREFIX | MAMBA_NOT_EXPECT_EXISTING_PREFIX
);
config.load(); config.load();
auto show_sources auto show_sources = config.at("show_config_sources").value<bool>() ? MAMBA_SHOW_CONFIG_SRCS
= config.at("show_config_sources").value<bool>() ? MAMBA_SHOW_CONFIG_SRCS : 0; : 0;
auto show_all = config.at("show_all_configs").value<bool>() ? MAMBA_SHOW_ALL_CONFIGS : 0; auto show_all = config.at("show_all_configs").value<bool>() ? MAMBA_SHOW_ALL_CONFIGS : 0;
auto show_all_rcs auto show_all_rcs = config.at("show_all_rc_configs").value<bool>() ? MAMBA_SHOW_ALL_RC_CONFIGS
= config.at("show_all_rc_configs").value<bool>() ? MAMBA_SHOW_ALL_RC_CONFIGS : 0; : 0;
auto show_group auto show_group = config.at("show_config_groups").value<bool>() ? MAMBA_SHOW_CONFIG_GROUPS
= config.at("show_config_groups").value<bool>() ? MAMBA_SHOW_CONFIG_GROUPS : 0; : 0;
auto show_desc auto show_desc = config.at("show_config_descriptions").value<bool>() ? MAMBA_SHOW_CONFIG_DESCS
= config.at("show_config_descriptions").value<bool>() ? MAMBA_SHOW_CONFIG_DESCS : 0; : 0;
auto show_long_desc = config.at("show_config_long_descriptions").value<bool>() auto show_long_desc = config.at("show_config_long_descriptions").value<bool>()
? MAMBA_SHOW_CONFIG_LONG_DESCS ? MAMBA_SHOW_CONFIG_LONG_DESCS
: 0; : 0;
@ -74,8 +78,10 @@ namespace mamba
config.at("use_target_prefix_fallback").set_value(true); config.at("use_target_prefix_fallback").set_value(true);
config.at("show_banner").set_value(false); config.at("show_banner").set_value(false);
config.at("target_prefix_checks") config.at("target_prefix_checks")
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX .set_value(
| MAMBA_ALLOW_NOT_ENV_PREFIX | MAMBA_NOT_EXPECT_EXISTING_PREFIX); MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX
| MAMBA_ALLOW_NOT_ENV_PREFIX | MAMBA_NOT_EXPECT_EXISTING_PREFIX
);
config.load(); config.load();
auto& no_rc = config.at("no_rc").value<bool>(); auto& no_rc = config.at("no_rc").value<bool>();

View File

@ -4,27 +4,26 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/api/configuration.hpp"
#include <algorithm> #include <algorithm>
#include <regex>
#include <iostream> #include <iostream>
#include <regex>
#include <stdexcept> #include <stdexcept>
#include <nlohmann/json.hpp>
#include <reproc++/run.hpp> #include <reproc++/run.hpp>
#include <nlohmann/json.hpp>
#include "spdlog/spdlog.h"
#include "mamba/api/configuration.hpp"
#include "mamba/api/info.hpp" #include "mamba/api/info.hpp"
#include "mamba/api/install.hpp" #include "mamba/api/install.hpp"
#include "mamba/core/environment.hpp" #include "mamba/core/environment.hpp"
#include "mamba/core/fsutil.hpp" #include "mamba/core/fsutil.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/transaction.hpp" #include "mamba/core/transaction.hpp"
#include "mamba/core/url.hpp" #include "mamba/core/url.hpp"
#include "spdlog/spdlog.h"
namespace mamba namespace mamba
{ {
/************************ /************************
@ -36,11 +35,17 @@ namespace mamba
bool ConfigurableImplBase::env_var_configured() const bool ConfigurableImplBase::env_var_configured() const
{ {
if (Context::instance().no_env) if (Context::instance().no_env)
{
return false; return false;
}
for (const auto& env_var : m_env_var_names) for (const auto& env_var : m_env_var_names)
{
if (env::get(env_var)) if (env::get(env_var))
{
return true; return true;
}
}
return false; return false;
} }
@ -146,9 +151,13 @@ namespace mamba
p_impl->m_rc_configurable_policy = level; p_impl->m_rc_configurable_policy = level;
if (level == RCConfigLevel::kTargetPrefix) if (level == RCConfigLevel::kTargetPrefix)
{
p_impl->m_needed_configs.insert("target_prefix"); p_impl->m_needed_configs.insert("target_prefix");
}
else else
{
p_impl->m_needed_configs.insert("root_prefix"); p_impl->m_needed_configs.insert("root_prefix");
}
return std::move(*this); return std::move(*this);
} }
@ -186,12 +195,18 @@ namespace mamba
Configurable&& Configurable::set_env_var_names(const std::vector<std::string>& names) Configurable&& Configurable::set_env_var_names(const std::vector<std::string>& names)
{ {
if (names.empty()) if (names.empty())
{
p_impl->m_env_var_names = { "MAMBA_" + to_upper(p_impl->m_name) }; p_impl->m_env_var_names = { "MAMBA_" + to_upper(p_impl->m_name) };
}
else else
{
p_impl->m_env_var_names = names; p_impl->m_env_var_names = names;
}
if (name() != "no_env") if (name() != "no_env")
{
p_impl->m_needed_configs.insert("no_env"); p_impl->m_needed_configs.insert("no_env");
}
return std::move(*this); return std::move(*this);
} }
@ -236,8 +251,12 @@ namespace mamba
Configurable&& Configurable::clear_env_values() Configurable&& Configurable::clear_env_values()
{ {
if (env_var_configured()) if (env_var_configured())
{
for (const auto& ev : p_impl->m_env_var_names) for (const auto& ev : p_impl->m_env_var_names)
{
env::unset(ev); env::unset(ev);
}
}
return std::move(*this); return std::move(*this);
} }
@ -269,15 +288,16 @@ namespace mamba
return std::move(*this); return std::move(*this);
} }
Configurable&& Configurable::set_rc_yaml_value(const YAML::Node& value, Configurable&& Configurable::set_rc_yaml_value(const YAML::Node& value, const std::string& source)
const std::string& source)
{ {
p_impl->set_rc_yaml_value(value, source); p_impl->set_rc_yaml_value(value, source);
return std::move(*this); return std::move(*this);
} }
Configurable&& Configurable::set_rc_yaml_values(const std::map<std::string, YAML::Node>& values, Configurable&& Configurable::set_rc_yaml_values(
const std::vector<std::string>& sources) const std::map<std::string, YAML::Node>& values,
const std::vector<std::string>& sources
)
{ {
p_impl->set_rc_yaml_values(values, sources); p_impl->set_rc_yaml_values(values, sources);
return std::move(*this); return std::move(*this);
@ -413,8 +433,8 @@ namespace mamba
if (name.find_first_of("/\\") != std::string::npos) if (name.find_first_of("/\\") != std::string::npos)
{ {
throw std::runtime_error( throw std::runtime_error(
"An unexpected file-system separator was found in environment name: '" + name "An unexpected file-system separator was found in environment name: '" + name + "'"
+ "'"); );
} }
} }
@ -458,11 +478,15 @@ namespace mamba
if (!config.at("target_prefix").cli_configured() if (!config.at("target_prefix").cli_configured()
&& config.at("env_name").cli_configured()) && config.at("env_name").cli_configured())
{
config.at("target_prefix").set_cli_value<fs::u8path>(prefix); config.at("target_prefix").set_cli_value<fs::u8path>(prefix);
}
if (!config.at("target_prefix").api_configured() if (!config.at("target_prefix").api_configured()
&& config.at("env_name").api_configured()) && config.at("env_name").api_configured())
{
config.at("target_prefix").set_value(prefix); config.at("target_prefix").set_value(prefix);
}
} }
} }
@ -492,7 +516,9 @@ namespace mamba
{ {
bool use_fallback = config.at("use_target_prefix_fallback").value<bool>(); bool use_fallback = config.at("use_target_prefix_fallback").value<bool>();
if (use_fallback) if (use_fallback)
{
prefix = std::getenv("CONDA_PREFIX") ? std::getenv("CONDA_PREFIX") : ""; prefix = std::getenv("CONDA_PREFIX") ? std::getenv("CONDA_PREFIX") : "";
}
} }
#ifdef _WIN32 #ifdef _WIN32
@ -501,10 +527,11 @@ namespace mamba
std::string sep = "/"; std::string sep = "/";
#endif #endif
if (!prefix.empty()) if (!prefix.empty())
{
prefix = rstrip(fs::weakly_canonical(env::expand_user(prefix)).string(), sep); prefix = rstrip(fs::weakly_canonical(env::expand_user(prefix)).string(), sep);
}
if ((prefix == root_prefix) if ((prefix == root_prefix) && Configuration::instance().at("create_base").value<bool>())
&& Configuration::instance().at("create_base").value<bool>())
{ {
path::touch(root_prefix / "conda-meta" / "history", true); path::touch(root_prefix / "conda-meta" / "history", true);
} }
@ -538,19 +565,23 @@ namespace mamba
if (fs::is_directory(prefix)) if (fs::is_directory(prefix))
{ {
if (!fs::is_empty(prefix) if (!fs::is_empty(prefix)
&& (!(fs::exists(prefix / "pkgs") || fs::exists(prefix / "conda-meta") && (!(
|| fs::exists(prefix / "envs")))) fs::exists(prefix / "pkgs") || fs::exists(prefix / "conda-meta")
|| fs::exists(prefix / "envs")
)))
{ {
throw std::runtime_error(fmt::format( throw std::runtime_error(fmt::format(
"Could not use default 'root_prefix': {}: Directory exists, is not empty and not a conda prefix.", "Could not use default 'root_prefix': {}: Directory exists, is not empty and not a conda prefix.",
prefix.string())); prefix.string()
));
} }
} }
else else
{ {
throw std::runtime_error(fmt::format( throw std::runtime_error(fmt::format(
"Could not use default 'root_prefix': {}: File is not a directory.", "Could not use default 'root_prefix': {}: File is not a directory.",
prefix.string())); prefix.string()
));
} }
} }
@ -601,7 +632,9 @@ namespace mamba
auto& ctx = Context::instance(); auto& ctx = Context::instance();
if (ctx.json) if (ctx.json)
{
return mamba::log_level::off; return mamba::log_level::off;
}
else if (Configuration::instance().at("verbose").configured()) else if (Configuration::instance().at("verbose").configured())
{ {
switch (ctx.verbosity) switch (ctx.verbosity)
@ -617,7 +650,9 @@ namespace mamba
} }
} }
else else
{
return mamba::log_level::warn; return mamba::log_level::warn;
}
} }
void verbose_hook(int& lvl) void verbose_hook(int& lvl)
@ -638,7 +673,9 @@ namespace mamba
bool expect_existing = options & MAMBA_EXPECT_EXISTING_PREFIX; bool expect_existing = options & MAMBA_EXPECT_EXISTING_PREFIX;
if (no_checks) if (no_checks)
{
return; return;
}
if (prefix.empty()) if (prefix.empty())
{ {
@ -670,8 +707,7 @@ namespace mamba
else if (expect_existing) else if (expect_existing)
{ {
LOG_ERROR << "No prefix found at: " << prefix.string(); LOG_ERROR << "No prefix found at: " << prefix.string();
LOG_ERROR LOG_ERROR << "Environment must first be created with \"micromamba create -n {env_name} ...\"";
<< "Environment must first be created with \"micromamba create -n {env_name} ...\"";
throw std::runtime_error("Aborting."); throw std::runtime_error("Aborting.");
} }
} }
@ -711,7 +747,9 @@ namespace mamba
void debug_hook(bool& value) void debug_hook(bool& value)
{ {
if (value) if (value)
{
LOG_WARNING << "Debug mode enabled"; LOG_WARNING << "Debug mode enabled";
}
} }
void print_config_only_hook(bool& value) void print_config_only_hook(bool& value)
@ -790,8 +828,12 @@ namespace mamba
void download_threads_hook(std::size_t& value) void download_threads_hook(std::size_t& value)
{ {
if (!value) if (!value)
{
throw std::runtime_error(fmt::format( throw std::runtime_error(fmt::format(
"Number of download threads as to be positive (currently set to {})", value)); "Number of download threads as to be positive (currently set to {})",
value
));
}
} }
void extract_threads_hook() void extract_threads_hook()
@ -805,7 +847,11 @@ namespace mamba
std::vector<std::string> args = { "conda", "config", "--show", "root_prefix", "--json" }; std::vector<std::string> args = { "conda", "config", "--show", "root_prefix", "--json" };
std::string out, err; std::string out, err;
auto [status, ec] = reproc::run( auto [status, ec] = reproc::run(
args, reproc::options{}, reproc::sink::string(out), reproc::sink::string(err)); args,
reproc::options{},
reproc::sink::string(out),
reproc::sink::string(err)
);
if (ec) if (ec)
{ {
@ -849,10 +895,8 @@ namespace mamba
void print_node(YAML::Emitter& out, YAML::Node value, YAML::Node source, bool show_source); void print_node(YAML::Emitter& out, YAML::Node value, YAML::Node source, bool show_source);
void print_scalar_node(YAML::Emitter& out, void
YAML::Node value, print_scalar_node(YAML::Emitter& out, YAML::Node value, YAML::Node source, bool show_source)
YAML::Node source,
bool show_source)
{ {
out << value; out << value;
@ -875,10 +919,7 @@ namespace mamba
} }
} }
void print_seq_node(YAML::Emitter& out, void print_seq_node(YAML::Emitter& out, YAML::Node value, YAML::Node source, bool show_source)
YAML::Node value,
YAML::Node source,
bool show_source)
{ {
if (value.size() > 0) if (value.size() > 0)
{ {
@ -893,14 +934,13 @@ namespace mamba
{ {
out << YAML::_Null(); out << YAML::_Null();
if (show_source) if (show_source)
{
out << YAML::Comment("'default'"); out << YAML::Comment("'default'");
}
} }
} }
void print_map_node(YAML::Emitter& out, void print_map_node(YAML::Emitter& out, YAML::Node value, YAML::Node source, bool show_source)
YAML::Node value,
YAML::Node source,
bool show_source)
{ {
out << YAML::BeginMap; out << YAML::BeginMap;
for (auto n : value) for (auto n : value)
@ -945,9 +985,9 @@ namespace mamba
int append_blk = blk_size - prepend_blk; int append_blk = blk_size - prepend_blk;
out << YAML::Comment(std::string(54, '#')) << YAML::Newline; out << YAML::Comment(std::string(54, '#')) << YAML::Newline;
out << YAML::Comment("#" + std::string(prepend_blk, ' ') + group_title out << YAML::Comment(
+ std::string(append_blk, ' ') + "#") "#" + std::string(prepend_blk, ' ') + group_title + std::string(append_blk, ' ') + "#"
<< YAML::Newline; ) << YAML::Newline;
out << YAML::Comment(std::string(54, '#')); out << YAML::Comment(std::string(54, '#'));
} }
@ -1117,13 +1157,13 @@ namespace mamba
.description("Custom channels") .description("Custom channels")
.long_description("A dictionary with name: url to use for custom channels.")); .long_description("A dictionary with name: url to use for custom channels."));
insert( insert(Configurable("custom_multichannels", &ctx.custom_multichannels)
Configurable("custom_multichannels", &ctx.custom_multichannels) .group("Channels")
.group("Channels") .set_rc_configurable()
.set_rc_configurable() .description("Custom multichannels")
.description("Custom multichannels") .long_description(
.long_description( "A dictionary with name: list of names/urls to use for custom multichannels."
"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", &ctx.override_channels_enabled)
.group("Channels") .group("Channels")
@ -1260,19 +1300,18 @@ namespace mamba
.group("Solver") .group("Solver")
.description("Freeze already installed dependencies")); .description("Freeze already installed dependencies"));
insert(Configurable("force_reinstall", false) insert(
Configurable("force_reinstall", false).group("Solver").description("Force reinstall of package")
);
insert(Configurable("no_deps", false)
.group("Solver") .group("Solver")
.description("Force reinstall of package")); .description("Do not install dependencies. This WILL lead to broken environments "
"and inconsistent behavior. Use at your own risk"));
insert( insert(
Configurable("no_deps", false) Configurable("only_deps", false).group("Solver").description("Only install dependencies")
.group("Solver") );
.description("Do not install dependencies. This WILL lead to broken environments "
"and inconsistent behavior. Use at your own risk"));
insert(Configurable("only_deps", false)
.group("Solver")
.description("Only install dependencies"));
insert(Configurable("categories", std::vector<std::string>({ "main" })) insert(Configurable("categories", std::vector<std::string>({ "main" }))
.group("Solver") .group("Solver")
@ -1287,8 +1326,8 @@ namespace mamba
.group("Solver") .group("Solver")
.set_rc_configurable() .set_rc_configurable()
.set_env_var_names() .set_env_var_names()
.description( .description("Allow uninstall when installing or updating packages. Default is true."
"Allow uninstall when installing or updating packages. Default is true.")); ));
insert(Configurable("allow_downgrade", &ctx.allow_downgrade) insert(Configurable("allow_downgrade", &ctx.allow_downgrade)
.group("Solver") .group("Solver")
@ -1352,13 +1391,13 @@ namespace mamba
!WARNING: Using this option can result in corruption of long-lived !WARNING: Using this option can result in corruption of long-lived
environments due to broken links (deleted cache).)"))); environments due to broken links (deleted cache).)")));
insert( insert(Configurable("shortcuts", &ctx.shortcuts)
Configurable("shortcuts", &ctx.shortcuts) .group("Extract, Link & Install")
.group("Extract, Link & Install") .set_rc_configurable()
.set_rc_configurable() .set_env_var_names()
.set_env_var_names() .description(
.description( "Install start-menu shortcuts on Windows (not implemented on Linux / macOS)"
"Install start-menu shortcuts on Windows (not implemented on Linux / macOS)")); ));
insert(Configurable("safety_checks", &ctx.safety_checks) insert(Configurable("safety_checks", &ctx.safety_checks)
.group("Extract, Link & Install") .group("Extract, Link & Install")
@ -1400,8 +1439,7 @@ namespace mamba
.group("Extract, Link & Install") .group("Extract, Link & Install")
.set_rc_configurable() .set_rc_configurable()
.set_env_var_names() .set_env_var_names()
.description( .description("Enable or disable the usage of filesystem lockfiles for shared resources")
"Enable or disable the usage of filesystem lockfiles for shared resources")
.long_description(unindent(R"( .long_description(unindent(R"(
By default, mamba uses lockfiles on the filesystem to synchronize access to By default, mamba uses lockfiles on the filesystem to synchronize access to
shared resources for multiple mamba processes (such as the package cache). shared resources for multiple mamba processes (such as the package cache).
@ -1438,8 +1476,8 @@ namespace mamba
insert(Configurable("download_only", &ctx.download_only) insert(Configurable("download_only", &ctx.download_only)
.group("Output, Prompt and Flow Control") .group("Output, Prompt and Flow Control")
.set_env_var_names() .set_env_var_names()
.description( .description("Only download and extract packages, do not link them into environment."
"Only download and extract packages, do not link them into environment.")); ));
insert(Configurable("log_level", &ctx.logging_level) insert(Configurable("log_level", &ctx.logging_level)
.group("Output, Prompt and Flow Control") .group("Output, Prompt and Flow Control")
@ -1482,21 +1520,21 @@ namespace mamba
.set_env_var_names() .set_env_var_names()
.description("Report all output as json")); .description("Report all output as json"));
insert( insert(Configurable("changeps1", &ctx.change_ps1)
Configurable("changeps1", &ctx.change_ps1) .group("Output, Prompt and Flow Control")
.group("Output, Prompt and Flow Control") .set_rc_configurable()
.set_rc_configurable() .set_env_var_names()
.set_env_var_names() .description(
.description( "When using activate, change the command prompt ($PS1) to include the activated environment."
"When using activate, change the command prompt ($PS1) to include the activated environment.")); ));
insert( insert(Configurable("shell_completion", &ctx.shell_completion)
Configurable("shell_completion", &ctx.shell_completion) .group("Output, Prompt and Flow Control")
.group("Output, Prompt and Flow Control") .set_rc_configurable()
.set_rc_configurable() .set_env_var_names()
.set_env_var_names() .description(
.description( "Enable or disable shell autocompletion (currently works for bash and zsh)."
"Enable or disable shell autocompletion (currently works for bash and zsh).")); ));
insert(Configurable("env_prompt", &ctx.env_prompt) insert(Configurable("env_prompt", &ctx.env_prompt)
.group("Output, Prompt and Flow Control") .group("Output, Prompt and Flow Control")
@ -1510,19 +1548,17 @@ namespace mamba
active environment is a named environment ('-n' flag), or otherwise holds the value active environment is a named environment ('-n' flag), or otherwise holds the value
of '{prefix}'.)"))); of '{prefix}'.)")));
insert( insert(Configurable("print_config_only", false)
Configurable("print_config_only", false) .group("Output, Prompt and Flow Control")
.group("Output, Prompt and Flow Control") .needs({ "debug" })
.needs({ "debug" }) .set_post_merge_hook(detail::print_config_only_hook)
.set_post_merge_hook(detail::print_config_only_hook) .description("Print the context after loading the config. Allow ultra-dry runs"));
.description("Print the context after loading the config. Allow ultra-dry runs"));
insert( insert(Configurable("print_context_only", false)
Configurable("print_context_only", false) .group("Output, Prompt and Flow Control")
.group("Output, Prompt and Flow Control") .needs({ "debug" })
.needs({ "debug" }) .set_post_merge_hook(detail::print_context_only_hook)
.set_post_merge_hook(detail::print_context_only_hook) .description("Print the context after loading the config. Allow ultra-dry runs"));
.description("Print the context after loading the config. Allow ultra-dry runs"));
insert(Configurable("show_banner", true) insert(Configurable("show_banner", true)
.group("Output, Prompt and Flow Control") .group("Output, Prompt and Flow Control")
@ -1675,13 +1711,21 @@ namespace mamba
std::vector<fs::u8path> sources; std::vector<fs::u8path> sources;
if (level >= RCConfigLevel::kSystemDir) if (level >= RCConfigLevel::kSystemDir)
{
sources.insert(sources.end(), system.begin(), system.end()); sources.insert(sources.end(), system.begin(), system.end());
}
if ((level >= RCConfigLevel::kRootPrefix) && !ctx.root_prefix.empty()) if ((level >= RCConfigLevel::kRootPrefix) && !ctx.root_prefix.empty())
{
sources.insert(sources.end(), root.begin(), root.end()); sources.insert(sources.end(), root.begin(), root.end());
}
if (level >= RCConfigLevel::kHomeDir) if (level >= RCConfigLevel::kHomeDir)
{
sources.insert(sources.end(), home.begin(), home.end()); sources.insert(sources.end(), home.begin(), home.end());
}
if ((level >= RCConfigLevel::kTargetPrefix) && !ctx.target_prefix.empty()) if ((level >= RCConfigLevel::kTargetPrefix) && !ctx.target_prefix.empty())
{
sources.insert(sources.end(), prefix.begin(), prefix.end()); sources.insert(sources.end(), prefix.begin(), prefix.end());
}
// Sort by precedence // Sort by precedence
std::reverse(sources.begin(), sources.end()); std::reverse(sources.begin(), sources.end());
@ -1718,7 +1762,9 @@ namespace mamba
CONFIG_DEBUGGING; CONFIG_DEBUGGING;
if (at("show_banner").value<bool>()) if (at("show_banner").value<bool>())
{
Console::instance().print(banner()); Console::instance().print(banner());
}
auto& ctx = Context::instance(); auto& ctx = Context::instance();
ctx.set_log_level(ctx.logging_level); ctx.set_log_level(ctx.logging_level);
@ -1728,9 +1774,13 @@ namespace mamba
Context::instance().dump_backtrace_no_guards(); Context::instance().dump_backtrace_no_guards();
if (ctx.log_backtrace > 0) if (ctx.log_backtrace > 0)
{
spdlog::enable_backtrace(ctx.log_backtrace); spdlog::enable_backtrace(ctx.log_backtrace);
}
else else
{
spdlog::disable_backtrace(); spdlog::disable_backtrace();
}
} }
bool Configuration::is_loading() bool Configuration::is_loading()
@ -1744,12 +1794,16 @@ namespace mamba
std::vector<std::string> locks; std::vector<std::string> locks;
for (auto& c : m_config_order) for (auto& c : m_config_order)
{
add_to_loading_sequence(m_loading_sequence, c, locks); add_to_loading_sequence(m_loading_sequence, c, locks);
}
} }
void Configuration::add_to_loading_sequence(std::vector<std::string>& seq, void Configuration::add_to_loading_sequence(
const std::string& name, std::vector<std::string>& seq,
std::vector<std::string>& locks) const std::string& name,
std::vector<std::string>& locks
)
{ {
auto found = std::find(seq.begin(), seq.end(), name); auto found = std::find(seq.begin(), seq.end(), name);
@ -1763,8 +1817,7 @@ namespace mamba
if (at(n).locked()) if (at(n).locked())
{ {
LOG_ERROR << "Circular import: " << join("->", locks) << "->" << n; LOG_ERROR << "Circular import: " << join("->", locks) << "->" << n;
throw std::runtime_error( throw std::runtime_error("Circular import detected in configuration. Aborting.");
"Circular import detected in configuration. Aborting.");
} }
add_to_loading_sequence(seq, n, locks); add_to_loading_sequence(seq, n, locks);
} }
@ -1780,20 +1833,26 @@ namespace mamba
locks.pop_back(); locks.pop_back();
for (auto& n : at(name).implied()) for (auto& n : at(name).implied())
{
add_to_loading_sequence(seq, n, locks); add_to_loading_sequence(seq, n, locks);
}
} }
} }
void Configuration::reset_compute_counters() void Configuration::reset_compute_counters()
{ {
for (auto& c : m_config) for (auto& c : m_config)
{
c.second.reset_compute_counter(); c.second.reset_compute_counter();
}
} }
void Configuration::clear_rc_values() void Configuration::clear_rc_values()
{ {
for (auto& c : m_config) for (auto& c : m_config)
{
c.second.clear_rc_values(); c.second.clear_rc_values();
}
} }
void Configuration::clear_rc_sources() void Configuration::clear_rc_sources()
@ -1806,22 +1865,32 @@ namespace mamba
void Configuration::clear_cli_values() void Configuration::clear_cli_values()
{ {
for (auto& c : m_config) for (auto& c : m_config)
{
c.second.clear_cli_value(); c.second.clear_cli_value();
}
} }
void Configuration::clear_values() void Configuration::clear_values()
{ {
for (auto& c : m_config) for (auto& c : m_config)
{
c.second.clear_values(); c.second.clear_values();
}
} }
void Configuration::operation_teardown() void Configuration::operation_teardown()
{ {
for (auto& c : m_config) for (auto& c : m_config)
{
if (c.second.has_single_op_lifetime()) if (c.second.has_single_op_lifetime())
{
c.second.clear_values(); c.second.clear_values();
}
else else
{
c.second.clear_cli_value(); c.second.clear_cli_value();
}
}
} }
std::vector<fs::u8path> Configuration::sources() std::vector<fs::u8path> Configuration::sources()
@ -1871,13 +1940,15 @@ namespace mamba
return config; return config;
} }
void Configuration::set_rc_values(std::vector<fs::u8path> possible_rc_paths, void
const RCConfigLevel& level) Configuration::set_rc_values(std::vector<fs::u8path> possible_rc_paths, const RCConfigLevel& level)
{ {
LOG_TRACE << "Get RC files configuration from locations up to " LOG_TRACE << "Get RC files configuration from locations up to "
<< YAML::Node(level).as<std::string>(); << YAML::Node(level).as<std::string>();
if (possible_rc_paths.empty()) if (possible_rc_paths.empty())
{
possible_rc_paths = compute_default_rc_sources(level); possible_rc_paths = compute_default_rc_sources(level);
}
m_sources = get_existing_rc_sources(possible_rc_paths); m_sources = get_existing_rc_sources(possible_rc_paths);
m_valid_sources.clear(); m_valid_sources.clear();
@ -1888,7 +1959,9 @@ namespace mamba
{ {
auto node = load_rc_file(s); auto node = load_rc_file(s);
if (node.IsNull()) if (node.IsNull())
{
continue; continue;
}
m_rc_yaml_nodes_cache.insert({ s, node }); m_rc_yaml_nodes_cache.insert({ s, node });
} }
@ -1902,15 +1975,18 @@ namespace mamba
auto& key = it.first; auto& key = it.first;
auto& c = it.second; auto& c = it.second;
if (!c.rc_configurable() || (c.rc_configurable_level() > level) if (!c.rc_configurable() || (c.rc_configurable_level() > level) || c.rc_configured())
|| c.rc_configured()) {
continue; continue;
}
for (const auto& source : m_valid_sources) for (const auto& source : m_valid_sources)
{ {
auto yaml = m_rc_yaml_nodes_cache[source]; auto yaml = m_rc_yaml_nodes_cache[source];
if (!yaml[key] || yaml[key].IsNull()) if (!yaml[key] || yaml[key].IsNull())
{
continue; continue;
}
c.set_rc_yaml_value(yaml[key], env::shrink_user(source).string()); c.set_rc_yaml_value(yaml[key], env::shrink_user(source).string());
} }
@ -1918,8 +1994,8 @@ namespace mamba
} }
} }
std::vector<fs::u8path> Configuration::get_existing_rc_sources( std::vector<fs::u8path>
const std::vector<fs::u8path>& possible_rc_paths) Configuration::get_existing_rc_sources(const std::vector<fs::u8path>& possible_rc_paths)
{ {
std::vector<fs::u8path> sources; std::vector<fs::u8path> sources;
@ -1948,7 +2024,9 @@ namespace mamba
else else
{ {
if (!l.empty()) if (!l.empty())
{
LOG_TRACE << "Configuration not found at '" << l.string() << "'"; LOG_TRACE << "Configuration not found at '" << l.string() << "'";
}
} }
} }
@ -1966,9 +2044,11 @@ namespace mamba
void dump_configurable(nl::json& node, const Configurable& c, const std::string& name); void dump_configurable(nl::json& node, const Configurable& c, const std::string& name);
} }
std::string dump_json(int opts, std::string dump_json(
const std::vector<std::string>& names, int opts,
const std::vector<Configuration::grouped_config_type>& grouped_config) const std::vector<std::string>& names,
const std::vector<Configuration::grouped_config_type>& grouped_config
)
{ {
// bool show_values = opts & MAMBA_SHOW_CONFIG_VALUES; // bool show_values = opts & MAMBA_SHOW_CONFIG_VALUES;
bool show_sources = opts & MAMBA_SHOW_CONFIG_SRCS; bool show_sources = opts & MAMBA_SHOW_CONFIG_SRCS;
@ -2042,9 +2122,11 @@ namespace mamba
return root.dump(4); return root.dump(4);
} }
std::string dump_yaml(int opts, std::string dump_yaml(
const std::vector<std::string>& names, int opts,
const std::vector<Configuration::grouped_config_type>& grouped_config) const std::vector<std::string>& names,
const std::vector<Configuration::grouped_config_type>& grouped_config
)
{ {
bool show_values = opts & MAMBA_SHOW_CONFIG_VALUES; bool show_values = opts & MAMBA_SHOW_CONFIG_VALUES;
bool show_sources = opts & MAMBA_SHOW_CONFIG_SRCS; bool show_sources = opts & MAMBA_SHOW_CONFIG_SRCS;
@ -2080,12 +2162,16 @@ namespace mamba
if (show_groups && first_group_config) if (show_groups && first_group_config)
{ {
if (!first_config) if (!first_config)
{
out << YAML::Newline << YAML::Newline; out << YAML::Newline << YAML::Newline;
}
detail::print_group_title(out, group_name); detail::print_group_title(out, group_name);
} }
if (!first_config || (first_config && show_groups)) if (!first_config || (first_config && show_groups))
{
out << YAML::Newline << YAML::Newline; out << YAML::Newline << YAML::Newline;
}
out << YAML::Comment(c->name()) << YAML::Newline; out << YAML::Comment(c->name()) << YAML::Newline;
if (show_long_descs) if (show_long_descs)
@ -2101,7 +2187,9 @@ namespace mamba
if (show_values) if (show_values)
{ {
if (first_config) if (first_config)
{
out << YAML::BeginMap; out << YAML::BeginMap;
}
out << YAML::Key << c->name(); out << YAML::Key << c->name();
out << YAML::Value; out << YAML::Value;
detail::print_configurable(out, *c, show_sources); detail::print_configurable(out, *c, show_sources);
@ -2113,7 +2201,9 @@ namespace mamba
} }
} }
if (show_values && !first_config) if (show_values && !first_config)
{
out << YAML::EndMap; out << YAML::EndMap;
}
return out.c_str(); return out.c_str();
} }

View File

@ -4,10 +4,10 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/api/configuration.hpp"
#include "mamba/api/create.hpp" #include "mamba/api/create.hpp"
#include "mamba/api/install.hpp"
#include "mamba/api/configuration.hpp"
#include "mamba/api/install.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
@ -21,8 +21,10 @@ namespace mamba
config.at("use_target_prefix_fallback").set_value(false); config.at("use_target_prefix_fallback").set_value(false);
config.at("target_prefix_checks") config.at("target_prefix_checks")
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_NOT_ENV_PREFIX .set_value(
| MAMBA_NOT_ALLOW_MISSING_PREFIX | MAMBA_NOT_EXPECT_EXISTING_PREFIX); MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_NOT_ENV_PREFIX
| MAMBA_NOT_ALLOW_MISSING_PREFIX | MAMBA_NOT_EXPECT_EXISTING_PREFIX
);
config.load(); config.load();
auto& create_specs = config.at("specs").value<std::vector<std::string>>(); auto& create_specs = config.at("specs").value<std::vector<std::string>>();
@ -39,12 +41,17 @@ namespace mamba
} }
else if (fs::exists(ctx.target_prefix / "conda-meta")) else if (fs::exists(ctx.target_prefix / "conda-meta"))
{ {
if (Console::prompt("Found conda-prefix at '" + ctx.target_prefix.string() if (Console::prompt(
+ "'. Overwrite?", "Found conda-prefix at '" + ctx.target_prefix.string() + "'. Overwrite?",
'n')) 'n'
))
{
fs::remove_all(ctx.target_prefix); fs::remove_all(ctx.target_prefix);
}
else else
{
throw std::runtime_error("Aborting."); throw std::runtime_error("Aborting.");
}
} }
else else
{ {
@ -53,10 +60,14 @@ namespace mamba
} }
} }
if (create_specs.empty()) if (create_specs.empty())
{
detail::create_empty_target(ctx.target_prefix); detail::create_empty_target(ctx.target_prefix);
}
if (config.at("platform").configured() && !config.at("platform").rc_configured()) if (config.at("platform").configured() && !config.at("platform").rc_configured())
{
detail::store_platform_config(ctx.target_prefix, ctx.platform); detail::store_platform_config(ctx.target_prefix, ctx.platform);
}
} }
if (Context::instance().env_lockfile) if (Context::instance().env_lockfile)
@ -65,14 +76,19 @@ namespace mamba
install_lockfile_specs( install_lockfile_specs(
lockfile_path, lockfile_path,
Configuration::instance().at("categories").value<std::vector<std::string>>(), Configuration::instance().at("categories").value<std::vector<std::string>>(),
true); true
);
} }
else if (!create_specs.empty()) else if (!create_specs.empty())
{ {
if (use_explicit) if (use_explicit)
{
install_explicit_specs(create_specs, true); install_explicit_specs(create_specs, true);
}
else else
{
install_specs(create_specs, true); install_specs(create_specs, true);
}
} }
config.operation_teardown(); config.operation_teardown();
@ -83,7 +99,9 @@ namespace mamba
void store_platform_config(const fs::u8path& prefix, const std::string& platform) void store_platform_config(const fs::u8path& prefix, const std::string& platform)
{ {
if (!fs::exists(prefix)) if (!fs::exists(prefix))
{
fs::create_directories(prefix); fs::create_directories(prefix);
}
auto out = open_ofstream(prefix / ".mambarc"); auto out = open_ofstream(prefix / ".mambarc");
out << "platform: " << platform; out << "platform: " << platform;

View File

@ -4,9 +4,9 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/api/configuration.hpp"
#include "mamba/api/info.hpp" #include "mamba/api/info.hpp"
#include "mamba/api/configuration.hpp"
#include "mamba/core/channel.hpp" #include "mamba/core/channel.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/environment.hpp" #include "mamba/core/environment.hpp"
@ -28,8 +28,9 @@ namespace mamba
config.at("use_target_prefix_fallback").set_value(true); config.at("use_target_prefix_fallback").set_value(true);
config.at("target_prefix_checks") config.at("target_prefix_checks")
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX .set_value(
| MAMBA_ALLOW_NOT_ENV_PREFIX); MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX | MAMBA_ALLOW_NOT_ENV_PREFIX
);
config.load(); config.load();
detail::print_info(); detail::print_info();
@ -48,7 +49,9 @@ namespace mamba
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)
{ {
if (Context::instance().json) if (Context::instance().json)
{
return; return;
}
int key_max_length = 0; int key_max_length = 0;
for (auto& item : items) for (auto& item : items)
@ -82,7 +85,9 @@ namespace mamba
{ {
std::map<std::string, nlohmann::json> items_map; std::map<std::string, nlohmann::json> items_map;
for (auto& [key, val] : items) for (auto& [key, val] : items)
{
items_map.insert({ key, val }); items_map.insert({ key, val });
}
Console::instance().json_write(items_map); Console::instance().json_write(items_map);
} }
@ -125,8 +130,8 @@ namespace mamba
items.push_back({ "env location", location }); items.push_back({ "env location", location });
// items.insert( { "shell level", { 1 } }); // items.insert( { "shell level", { 1 } });
items.push_back( items.push_back({ "user config files",
{ "user config files", { (env::home_directory() / ".mambarc").string() } }); { (env::home_directory() / ".mambarc").string() } });
Configuration& config = Configuration::instance(); Configuration& config = Configuration::instance();
std::vector<std::string> sources; std::vector<std::string> sources;
@ -139,7 +144,9 @@ namespace mamba
items.push_back({ "libmamba version", version() }); items.push_back({ "libmamba version", version() });
if (ctx.is_micromamba && !ctx.caller_version.empty()) if (ctx.is_micromamba && !ctx.caller_version.empty())
{
items.push_back({ "micromamba version", ctx.caller_version }); items.push_back({ "micromamba version", ctx.caller_version });
}
items.push_back({ "curl version", curl_version() }); items.push_back({ "curl version", curl_version() });
items.push_back({ "libarchive version", archive_version_details() }); items.push_back({ "libarchive version", archive_version_details() });

View File

@ -4,18 +4,21 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/api/install.hpp"
#include <stdexcept> #include <stdexcept>
#include <fmt/color.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <fmt/ostream.h> #include <fmt/ostream.h>
#include <fmt/color.h>
#include <reproc/reproc.h>
#include <reproc++/run.hpp> #include <reproc++/run.hpp>
#include <reproc/reproc.h>
#include "mamba/api/configuration.hpp"
#include "mamba/api/install.hpp"
#include "mamba/api/channel_loader.hpp" #include "mamba/api/channel_loader.hpp"
#include "mamba/api/configuration.hpp"
#include "mamba/core/activation.hpp"
#include "mamba/core/env_lockfile.hpp"
#include "mamba/core/environments_manager.hpp"
#include "mamba/core/mamba_fs.hpp" #include "mamba/core/mamba_fs.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/package_cache.hpp" #include "mamba/core/package_cache.hpp"
@ -23,9 +26,6 @@
#include "mamba/core/transaction.hpp" #include "mamba/core/transaction.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/core/virtual_packages.hpp" #include "mamba/core/virtual_packages.hpp"
#include "mamba/core/env_lockfile.hpp"
#include "mamba/core/activation.hpp"
#include "mamba/core/environments_manager.hpp"
namespace mamba namespace mamba
{ {
@ -34,31 +34,32 @@ namespace mamba
using command_args = std::vector<std::string>; using command_args = std::vector<std::string>;
tl::expected<command_args, std::runtime_error> get_other_pkg_mgr_install_instructions( tl::expected<command_args, std::runtime_error> get_other_pkg_mgr_install_instructions(
const std::string& name, const std::string& target_prefix, const fs::u8path& spec_file) const std::string& name,
const std::string& target_prefix,
const fs::u8path& spec_file
)
{ {
const auto get_python_path const auto get_python_path = [&]
= [&] { return env::which("python", get_path_dirs(target_prefix)).string(); }; { return env::which("python", get_path_dirs(target_prefix)).string(); };
const std::unordered_map<std::string, command_args> other_pkg_mgr_install_instructions{ const std::unordered_map<std::string, command_args> other_pkg_mgr_install_instructions{
{ "pip", { "pip",
{ get_python_path(), "-m", "pip", "install", "-r", spec_file, "--no-input" } }, { get_python_path(), "-m", "pip", "install", "-r", spec_file, "--no-input" } },
{ "pip --no-deps", { "pip --no-deps",
{ get_python_path(), { get_python_path(), "-m", "pip", "install", "--no-deps", "-r", spec_file, "--no-input" } }
"-m",
"pip",
"install",
"--no-deps",
"-r",
spec_file,
"--no-input" } }
}; };
auto found_it = other_pkg_mgr_install_instructions.find(name); auto found_it = other_pkg_mgr_install_instructions.find(name);
if (found_it != other_pkg_mgr_install_instructions.end()) if (found_it != other_pkg_mgr_install_instructions.end())
{
return found_it->second; return found_it->second;
}
else else
{
return tl::unexpected(std::runtime_error( return tl::unexpected(std::runtime_error(
fmt::format("no install instruction found for package manager '{}'", name))); fmt::format("no install instruction found for package manager '{}'", name)
));
}
} }
} }
@ -87,11 +88,17 @@ namespace mamba
|| (!terminated_not_an_err && reproc_terminated(status))) || (!terminated_not_an_err && reproc_terminated(status)))
{ {
if (ec) if (ec)
{
LOG_ERROR << "Subprocess call failed: " << ec.message(); LOG_ERROR << "Subprocess call failed: " << ec.message();
}
else if (reproc_killed(status)) else if (reproc_killed(status))
{
LOG_ERROR << "Subprocess call failed (killed)"; LOG_ERROR << "Subprocess call failed (killed)";
}
else else
{
LOG_ERROR << "Subprocess call failed (terminated)"; LOG_ERROR << "Subprocess call failed (terminated)";
}
throw std::runtime_error("Subprocess call failed. Aborting."); throw std::runtime_error("Subprocess call failed. Aborting.");
} }
} }
@ -108,30 +115,40 @@ namespace mamba
{ {
std::ofstream specs_f = open_ofstream(specs.path()); std::ofstream specs_f = open_ofstream(specs.path());
for (auto& d : deps) for (auto& d : deps)
{
specs_f << d.c_str() << '\n'; specs_f << d.c_str() << '\n';
}
} }
command_args install_instructions = [&] command_args install_instructions = [&]
{ {
const auto maybe_instructions = get_other_pkg_mgr_install_instructions( const auto maybe_instructions = get_other_pkg_mgr_install_instructions(
pkg_mgr, ctx.target_prefix.string(), specs.path()); pkg_mgr,
ctx.target_prefix.string(),
specs.path()
);
if (maybe_instructions) if (maybe_instructions)
{
return maybe_instructions.value(); return maybe_instructions.value();
}
else else
{
throw maybe_instructions.error(); throw maybe_instructions.error();
}
}(); }();
auto [wrapped_command, tmpfile] auto [wrapped_command, tmpfile] = prepare_wrapped_call(ctx.target_prefix, install_instructions);
= prepare_wrapped_call(ctx.target_prefix, install_instructions);
reproc::options options; reproc::options options;
options.redirect.parent = true; options.redirect.parent = true;
options.working_directory = cwd.c_str(); options.working_directory = cwd.c_str();
Console::stream() << fmt::format(Context::instance().palette.external, Console::stream() << fmt::format(
"\nInstalling {} packages: {}", Context::instance().palette.external,
pkg_mgr, "\nInstalling {} packages: {}",
fmt::join(deps, ", ")); pkg_mgr,
fmt::join(deps, ", ")
);
fmt::print(LOG_INFO, "Calling: {}", fmt::join(install_instructions, " ")); fmt::print(LOG_INFO, "Calling: {}", fmt::join(install_instructions, " "));
auto [status, ec] = reproc::run(wrapped_command, options); auto [status, ec] = reproc::run(wrapped_command, options);
@ -178,7 +195,8 @@ namespace mamba
if (!(starts_with(selector, "sel(") && selector[selector.size() - 1] == ')')) if (!(starts_with(selector, "sel(") && selector[selector.size() - 1] == ')'))
{ {
throw std::runtime_error( throw std::runtime_error(
"Couldn't parse selector. Needs to start with sel( and end with )"); "Couldn't parse selector. Needs to start with sel( and end with )"
);
} }
std::string expr = selector.substr(4, selector.size() - 5); std::string expr = selector.substr(4, selector.size() - 5);
@ -214,7 +232,9 @@ namespace mamba
YAML::Node deps; YAML::Node deps;
if (f["dependencies"] && f["dependencies"].IsSequence() && f["dependencies"].size() > 0) if (f["dependencies"] && f["dependencies"].IsSequence() && f["dependencies"].size() > 0)
{
deps = f["dependencies"]; deps = f["dependencies"];
}
else else
{ {
LOG_ERROR << "No 'dependencies' specified in YAML spec file '" << file.string() LOG_ERROR << "No 'dependencies' specified in YAML spec file '" << file.string()
@ -249,14 +269,15 @@ namespace mamba
else else
{ {
throw std::runtime_error( throw std::runtime_error(
"Complicated selection merge not implemented yet."); "Complicated selection merge not implemented yet."
);
} }
} }
} }
else if (key == "pip") else if (key == "pip")
{ {
const auto yaml_parent_path const auto yaml_parent_path = fs::absolute(yaml_file).parent_path().string(
= fs::absolute(yaml_file).parent_path().string(); );
result.others_pkg_mgrs_specs.push_back({ result.others_pkg_mgrs_specs.push_back({
"pip", "pip",
map_el.second.as<std::vector<std::string>>(), map_el.second.as<std::vector<std::string>>(),
@ -275,13 +296,14 @@ namespace mamba
} }
catch (const YAML::Exception& e) catch (const YAML::Exception& e)
{ {
LOG_ERROR << "Bad conversion of 'dependencies' to a vector of string: " LOG_ERROR << "Bad conversion of 'dependencies' to a vector of string: " << final_deps;
<< final_deps;
throw e; throw e;
} }
if (has_pip_deps && !std::count(dependencies.begin(), dependencies.end(), "pip")) if (has_pip_deps && !std::count(dependencies.begin(), dependencies.end(), "pip"))
{
dependencies.push_back("pip"); dependencies.push_back("pip");
}
result.dependencies = dependencies; result.dependencies = dependencies;
@ -313,15 +335,17 @@ namespace mamba
return result; return result;
} }
std::tuple<std::vector<PackageInfo>, std::vector<MatchSpec>> parse_urls_to_package_info( std::tuple<std::vector<PackageInfo>, std::vector<MatchSpec>>
const std::vector<std::string>& urls) parse_urls_to_package_info(const std::vector<std::string>& urls)
{ {
std::vector<PackageInfo> pi_result; std::vector<PackageInfo> pi_result;
std::vector<MatchSpec> ms_result; std::vector<MatchSpec> ms_result;
for (auto& u : urls) for (auto& u : urls)
{ {
if (strip(u).size() == 0) if (strip(u).size() == 0)
{
continue; continue;
}
std::size_t hash = u.find_first_of('#'); std::size_t hash = u.find_first_of('#');
MatchSpec ms(u.substr(0, hash)); MatchSpec ms(u.substr(0, hash));
PackageInfo p(ms.name); PackageInfo p(ms.name);
@ -355,8 +379,10 @@ namespace mamba
config.at("create_base").set_value(true); config.at("create_base").set_value(true);
config.at("use_target_prefix_fallback").set_value(true); config.at("use_target_prefix_fallback").set_value(true);
config.at("target_prefix_checks") config.at("target_prefix_checks")
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_NOT_ALLOW_MISSING_PREFIX .set_value(
| MAMBA_NOT_ALLOW_NOT_ENV_PREFIX | MAMBA_EXPECT_EXISTING_PREFIX); MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_NOT_ALLOW_MISSING_PREFIX
| MAMBA_NOT_ALLOW_NOT_ENV_PREFIX | MAMBA_EXPECT_EXISTING_PREFIX
);
config.load(); config.load();
auto& install_specs = config.at("specs").value<std::vector<std::string>>(); auto& install_specs = config.at("specs").value<std::vector<std::string>>();
@ -369,7 +395,8 @@ namespace mamba
install_lockfile_specs( install_lockfile_specs(
lockfile_path, lockfile_path,
Configuration::instance().at("categories").value<std::vector<std::string>>(), Configuration::instance().at("categories").value<std::vector<std::string>>(),
false); false
);
} }
else if (!install_specs.empty()) else if (!install_specs.empty())
{ {
@ -393,10 +420,8 @@ namespace mamba
int RETRY_SUBDIR_FETCH = 1 << 0; int RETRY_SUBDIR_FETCH = 1 << 0;
int RETRY_SOLVE_ERROR = 1 << 1; int RETRY_SOLVE_ERROR = 1 << 1;
void install_specs(const std::vector<std::string>& specs, void
bool create_env, install_specs(const std::vector<std::string>& specs, bool create_env, int solver_flag, int is_retry)
int solver_flag,
int is_retry)
{ {
auto& ctx = Context::instance(); auto& ctx = Context::instance();
auto& config = Configuration::instance(); auto& config = Configuration::instance();
@ -416,7 +441,8 @@ namespace mamba
if (!fs::exists(ctx.target_prefix) && create_env == false) if (!fs::exists(ctx.target_prefix) && create_env == false)
{ {
throw std::runtime_error( throw std::runtime_error(
fmt::format("Prefix does not exist at: {}", ctx.target_prefix.string())); fmt::format("Prefix does not exist at: {}", ctx.target_prefix.string())
);
} }
MultiPackageCache package_caches(ctx.pkgs_dirs); MultiPackageCache package_caches(ctx.pkgs_dirs);
@ -458,17 +484,20 @@ namespace mamba
std::vector<std::string> prefix_pkgs; std::vector<std::string> prefix_pkgs;
for (auto& it : prefix_data.records()) for (auto& it : prefix_data.records())
{
prefix_pkgs.push_back(it.first); prefix_pkgs.push_back(it.first);
}
prefix_data.add_packages(get_virtual_packages()); prefix_data.add_packages(get_virtual_packages());
MRepo::create(pool, prefix_data); MRepo::create(pool, prefix_data);
MSolver solver(std::move(pool), MSolver solver(
{ { SOLVER_FLAG_ALLOW_UNINSTALL, ctx.allow_uninstall }, std::move(pool),
{ SOLVER_FLAG_ALLOW_DOWNGRADE, ctx.allow_downgrade }, { { SOLVER_FLAG_ALLOW_UNINSTALL, ctx.allow_uninstall },
{ SOLVER_FLAG_STRICT_REPO_PRIORITY, { SOLVER_FLAG_ALLOW_DOWNGRADE, ctx.allow_downgrade },
ctx.channel_priority == ChannelPriority::kStrict } }); { SOLVER_FLAG_STRICT_REPO_PRIORITY, ctx.channel_priority == ChannelPriority::kStrict } }
);
solver.set_postsolve_flags({ { MAMBA_NO_DEPS, no_deps }, solver.set_postsolve_flags({ { MAMBA_NO_DEPS, no_deps },
{ MAMBA_ONLY_DEPS, only_deps }, { MAMBA_ONLY_DEPS, only_deps },
@ -500,7 +529,9 @@ namespace mamba
{ {
std::vector<std::string> pinned_str; std::vector<std::string> pinned_str;
for (auto& ms : solver.pinned_specs()) for (auto& ms : solver.pinned_specs())
{
pinned_str.push_back(" - " + ms.conda_build_form() + "\n"); pinned_str.push_back(" - " + ms.conda_build_form() + "\n");
}
Console::instance().print("\nPinned packages:\n" + join("", pinned_str)); Console::instance().print("\nPinned packages:\n" + join("", pinned_str));
} }
@ -514,15 +545,19 @@ namespace mamba
return install_specs(specs, create_env, solver_flag, is_retry | RETRY_SOLVE_ERROR); return install_specs(specs, create_env, solver_flag, is_retry | RETRY_SOLVE_ERROR);
} }
if (freeze_installed) if (freeze_installed)
{
Console::instance().print("Possible hints:\n - 'freeze_installed' is turned on\n"); Console::instance().print("Possible hints:\n - 'freeze_installed' is turned on\n");
}
if (ctx.json) if (ctx.json)
{ {
Console::instance().json_write( Console::instance().json_write({ { "success", false },
{ { "success", false }, { "solver_problems", solver.all_problems() } }); { "solver_problems", solver.all_problems() } });
} }
throw mamba_error("Could not solve for environment specs", throw mamba_error(
mamba_error_code::satisfiablitity_error); "Could not solve for environment specs",
mamba_error_code::satisfiablitity_error
);
} }
MTransaction trans(solver, package_caches); MTransaction trans(solver, package_caches);
@ -537,12 +572,14 @@ namespace mamba
if (trans.prompt()) if (trans.prompt())
{ {
if (create_env && !Context::instance().dry_run) if (create_env && !Context::instance().dry_run)
{
detail::create_target_directory(ctx.target_prefix); detail::create_target_directory(ctx.target_prefix);
}
trans.execute(prefix_data); trans.execute(prefix_data);
for (auto other_spec : config.at("others_pkg_mgrs_specs") for (auto other_spec :
.value<std::vector<detail::other_pkg_mgr_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(other_spec);
} }
@ -567,8 +604,8 @@ namespace mamba
MultiPackageCache pkg_caches(ctx.pkgs_dirs); MultiPackageCache pkg_caches(ctx.pkgs_dirs);
prefix_data.add_packages(get_virtual_packages()); prefix_data.add_packages(get_virtual_packages());
MRepo::create( MRepo::create(pool, prefix_data); // Potentially re-alloc (moves in memory) Solvables
pool, prefix_data); // Potentially re-alloc (moves in memory) Solvables in the pool // in the pool
std::vector<detail::other_pkg_mgr_spec> others; std::vector<detail::other_pkg_mgr_spec> others;
// Note that the Transaction will gather the Solvables, // Note that the Transaction will gather the Solvables,
@ -576,12 +613,16 @@ namespace mamba
auto transaction = create_transaction(pool, pkg_caches, others); auto transaction = create_transaction(pool, pkg_caches, others);
if (ctx.json) if (ctx.json)
{
transaction.log_json(); transaction.log_json();
}
if (transaction.prompt()) if (transaction.prompt())
{ {
if (create_env && !Context::instance().dry_run) if (create_env && !Context::instance().dry_run)
{
detail::create_target_directory(ctx.target_prefix); detail::create_target_directory(ctx.target_prefix);
}
transaction.execute(prefix_data); transaction.execute(prefix_data);
@ -598,12 +639,15 @@ namespace mamba
detail::install_explicit_with_transaction( detail::install_explicit_with_transaction(
[&](auto& pool, auto& pkg_caches, auto& others) [&](auto& pool, auto& pkg_caches, auto& others)
{ return create_explicit_transaction_from_urls(pool, specs, pkg_caches, others); }, { return create_explicit_transaction_from_urls(pool, specs, pkg_caches, others); },
create_env); create_env
);
} }
void install_lockfile_specs(const std::string& lockfile, void install_lockfile_specs(
const std::vector<std::string>& categories, const std::string& lockfile,
bool create_env) const std::vector<std::string>& categories,
bool create_env
)
{ {
std::unique_ptr<TemporaryFile> tmp_lock_file; std::unique_ptr<TemporaryFile> tmp_lock_file;
fs::u8path file; fs::u8path file;
@ -617,7 +661,8 @@ namespace mamba
if (!success || dt.http_status != 200) if (!success || dt.http_status != 200)
{ {
throw std::runtime_error( throw std::runtime_error(
fmt::format("Could not download environment lockfile from {}", lockfile)); fmt::format("Could not download environment lockfile from {}", lockfile)
);
} }
file = tmp_lock_file->path(); file = tmp_lock_file->path();
@ -629,10 +674,10 @@ namespace mamba
detail::install_explicit_with_transaction( detail::install_explicit_with_transaction(
[&](auto& pool, auto& pkg_caches, auto& others) { [&](auto& pool, auto& pkg_caches, auto& others) {
return create_explicit_transaction_from_lockfile( return create_explicit_transaction_from_lockfile(pool, file, categories, pkg_caches, others);
pool, file, categories, pkg_caches, others);
}, },
create_env); create_env
);
} }
namespace detail namespace detail
@ -641,10 +686,10 @@ namespace mamba
{ {
detail::create_target_directory(prefix); detail::create_target_directory(prefix);
Console::instance().print( Console::instance().print(join(
join("", "",
std::vector<std::string>( std::vector<std::string>({ "Empty environment created at prefix: ", prefix.string() })
{ "Empty environment created at prefix: ", prefix.string() }))); ));
Console::instance().json_write({ { "success", true } }); Console::instance().json_write({ { "success", true } });
} }
@ -666,7 +711,9 @@ namespace mamba
auto& channels = config.at("channels"); auto& channels = config.at("channels");
if (file_specs.size() == 0) if (file_specs.size() == 0)
{
return; return;
}
for (const auto& file : file_specs) for (const auto& file : file_specs)
{ {
@ -766,7 +813,9 @@ namespace mamba
{ {
std::string_view spec = strip((*f)); std::string_view spec = strip((*f));
if (!spec.empty() && spec[0] != '#') if (!spec.empty() && spec[0] != '#')
{
explicit_specs.push_back(*f); explicit_specs.push_back(*f);
}
} }
specs.clear_values(); specs.clear_values();

View File

@ -4,12 +4,12 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include <regex>
#include <iostream>
#include "mamba/api/list.hpp" #include "mamba/api/list.hpp"
#include "mamba/api/configuration.hpp"
#include <iostream>
#include <regex>
#include "mamba/api/configuration.hpp"
#include "mamba/core/channel.hpp" #include "mamba/core/channel.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/prefix_data.hpp" #include "mamba/core/prefix_data.hpp"
@ -23,8 +23,10 @@ namespace mamba
config.at("show_banner").set_value(false); config.at("show_banner").set_value(false);
config.at("use_target_prefix_fallback").set_value(true); config.at("use_target_prefix_fallback").set_value(true);
config.at("target_prefix_checks") config.at("target_prefix_checks")
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX .set_value(
| MAMBA_NOT_ALLOW_NOT_ENV_PREFIX | MAMBA_EXPECT_EXISTING_PREFIX); MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX
| MAMBA_NOT_ALLOW_NOT_ENV_PREFIX | MAMBA_EXPECT_EXISTING_PREFIX
);
config.load(); config.load();
detail::list_packages(regex); detail::list_packages(regex);

View File

@ -28,8 +28,10 @@ namespace mamba
config.at("use_target_prefix_fallback").set_value(true); config.at("use_target_prefix_fallback").set_value(true);
config.at("target_prefix_checks") config.at("target_prefix_checks")
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_NOT_ALLOW_MISSING_PREFIX .set_value(
| MAMBA_NOT_ALLOW_NOT_ENV_PREFIX | MAMBA_EXPECT_EXISTING_PREFIX); MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_NOT_ALLOW_MISSING_PREFIX
| MAMBA_NOT_ALLOW_NOT_ENV_PREFIX | MAMBA_EXPECT_EXISTING_PREFIX
);
config.load(); config.load();
auto remove_specs = config.at("specs").value<std::vector<std::string>>(); auto remove_specs = config.at("specs").value<std::vector<std::string>>();
@ -90,10 +92,14 @@ namespace mamba
auto execute_transaction = [&](MTransaction& transaction) auto execute_transaction = [&](MTransaction& transaction)
{ {
if (ctx.json) if (ctx.json)
{
transaction.log_json(); transaction.log_json();
}
if (transaction.prompt()) if (transaction.prompt())
{
transaction.execute(prefix_data); transaction.execute(prefix_data);
}
}; };
if (force) if (force)
@ -104,24 +110,30 @@ namespace mamba
} }
else else
{ {
MSolver solver(std::move(pool), MSolver solver(
{ { SOLVER_FLAG_ALLOW_DOWNGRADE, 1 }, std::move(pool),
{ SOLVER_FLAG_ALLOW_UNINSTALL, 1 }, { { SOLVER_FLAG_ALLOW_DOWNGRADE, 1 },
{ SOLVER_FLAG_STRICT_REPO_PRIORITY, { SOLVER_FLAG_ALLOW_UNINSTALL, 1 },
ctx.channel_priority == ChannelPriority::kStrict } }); { SOLVER_FLAG_STRICT_REPO_PRIORITY,
ctx.channel_priority == ChannelPriority::kStrict } }
);
History history(ctx.target_prefix); History history(ctx.target_prefix);
auto hist_map = history.get_requested_specs_map(); auto hist_map = history.get_requested_specs_map();
std::vector<std::string> keep_specs; std::vector<std::string> keep_specs;
for (auto& it : hist_map) for (auto& it : hist_map)
{
keep_specs.push_back(it.second.conda_build_form()); keep_specs.push_back(it.second.conda_build_form());
}
solver.add_jobs(keep_specs, SOLVER_USERINSTALLED); solver.add_jobs(keep_specs, SOLVER_USERINSTALLED);
int solver_flag = SOLVER_ERASE; int solver_flag = SOLVER_ERASE;
if (prune) if (prune)
{
solver_flag |= SOLVER_CLEANDEPS; solver_flag |= SOLVER_CLEANDEPS;
}
solver.add_jobs(specs, solver_flag); solver.add_jobs(specs, solver_flag);
solver.must_solve(); solver.must_solve();

View File

@ -4,19 +4,16 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/api/repoquery.hpp"
#include <iostream> #include <iostream>
#include "mamba/api/configuration.hpp"
#include "mamba/api/channel_loader.hpp" #include "mamba/api/channel_loader.hpp"
#include "mamba/api/configuration.hpp"
#include "mamba/api/repoquery.hpp"
namespace mamba namespace mamba
{ {
void repoquery(QueryType type, void repoquery(QueryType type, QueryResultFormat format, bool use_local, const std::string& query)
QueryResultFormat format,
bool use_local,
const std::string& query)
{ {
auto& ctx = Context::instance(); auto& ctx = Context::instance();
auto& config = Configuration::instance(); auto& config = Configuration::instance();
@ -76,9 +73,10 @@ namespace mamba
} }
else if (type == QueryType::kDEPENDS) else if (type == QueryType::kDEPENDS)
{ {
auto res = q.depends(query, auto res = q.depends(
format == QueryResultFormat::kTREE query,
|| format == QueryResultFormat::kRECURSIVETABLE); format == QueryResultFormat::kTREE || format == QueryResultFormat::kRECURSIVETABLE
);
switch (format) switch (format)
{ {
case QueryResultFormat::kTREE: case QueryResultFormat::kTREE:
@ -95,9 +93,10 @@ namespace mamba
} }
else if (type == QueryType::kWHONEEDS) else if (type == QueryType::kWHONEEDS)
{ {
auto res = q.whoneeds(query, auto res = q.whoneeds(
format == QueryResultFormat::kTREE query,
|| format == QueryResultFormat::kRECURSIVETABLE); format == QueryResultFormat::kTREE || format == QueryResultFormat::kRECURSIVETABLE
);
switch (format) switch (format)
{ {
case QueryResultFormat::kTREE: case QueryResultFormat::kTREE:
@ -111,7 +110,8 @@ namespace mamba
case QueryResultFormat::kRECURSIVETABLE: case QueryResultFormat::kRECURSIVETABLE:
res.sort("name").table( res.sort("name").table(
std::cout, std::cout,
{ "Name", "Version", "Build", concat("Depends:", query), "Channel" }); { "Name", "Version", "Build", concat("Depends:", query), "Channel" }
);
} }
} }

View File

@ -4,11 +4,11 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/api/shell.hpp"
#include <iostream> #include <iostream>
#include "mamba/api/configuration.hpp" #include "mamba/api/configuration.hpp"
#include "mamba/api/shell.hpp"
#include "mamba/core/activation.hpp" #include "mamba/core/activation.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/environment.hpp" #include "mamba/core/environment.hpp"
@ -43,10 +43,8 @@ namespace mamba
} }
} }
void shell(const std::string& action, void
std::string& shell_type, shell(const std::string& action, std::string& shell_type, const std::string& prefix, bool stack)
const std::string& prefix,
bool stack)
{ {
auto& ctx = Context::instance(); auto& ctx = Context::instance();
auto& config = Configuration::instance(); auto& config = Configuration::instance();
@ -95,18 +93,26 @@ namespace mamba
if (action == "init") if (action == "init")
{ {
if (prefix.empty() || prefix == "base") if (prefix.empty() || prefix == "base")
{
shell_prefix = ctx.root_prefix.string(); shell_prefix = ctx.root_prefix.string();
}
else else
{
shell_prefix = fs::weakly_canonical(env::expand_user(prefix)).string(); shell_prefix = fs::weakly_canonical(env::expand_user(prefix)).string();
}
init_shell(shell_type, shell_prefix); init_shell(shell_type, shell_prefix);
} }
else if (action == "deinit") else if (action == "deinit")
{ {
if (prefix.empty() || prefix == "base") if (prefix.empty() || prefix == "base")
{
shell_prefix = ctx.root_prefix.string(); shell_prefix = ctx.root_prefix.string();
}
else else
{
shell_prefix = fs::weakly_canonical(env::expand_user(prefix)).string(); shell_prefix = fs::weakly_canonical(env::expand_user(prefix)).string();
}
deinit_shell(shell_type, shell_prefix); deinit_shell(shell_type, shell_prefix);
} }
@ -127,7 +133,8 @@ namespace mamba
{ { "success", true }, { { "success", true },
{ "operation", "shell_hook" }, { "operation", "shell_hook" },
{ "context", { { "shell_type", shell_type } } }, { "context", { { "shell_type", shell_type } } },
{ "actions", { { "print", { activator->hook(shell_type) } } } } }); { "actions", { { "print", { activator->hook(shell_type) } } } } }
);
} }
else else
{ {
@ -137,15 +144,22 @@ namespace mamba
else if (action == "activate") else if (action == "activate")
{ {
if (prefix.empty() || prefix == "base") if (prefix.empty() || prefix == "base")
{
shell_prefix = ctx.root_prefix.string(); shell_prefix = ctx.root_prefix.string();
}
else if (prefix.find_first_of("/\\") == std::string::npos) else if (prefix.find_first_of("/\\") == std::string::npos)
{
shell_prefix = (ctx.root_prefix / "envs" / prefix).string(); shell_prefix = (ctx.root_prefix / "envs" / prefix).string();
}
else else
{
shell_prefix = fs::weakly_canonical(env::expand_user(prefix)).string(); shell_prefix = fs::weakly_canonical(env::expand_user(prefix)).string();
}
if (!fs::exists(shell_prefix)) if (!fs::exists(shell_prefix))
throw std::runtime_error("Cannot activate, prefix does not exist at: " {
+ shell_prefix); throw std::runtime_error("Cannot activate, prefix does not exist at: " + shell_prefix);
}
std::cout << activator->activate(shell_prefix, stack); std::cout << activator->activate(shell_prefix, stack);
} }
@ -168,8 +182,7 @@ namespace mamba
#endif #endif
else else
{ {
throw std::runtime_error( throw std::runtime_error("Need an action {init, hook, activate, deactivate, reactivate}");
"Need an action {init, hook, activate, deactivate, reactivate}");
} }
config.operation_teardown(); config.operation_teardown();

View File

@ -4,13 +4,13 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/api/configuration.hpp"
#include "mamba/api/update.hpp" #include "mamba/api/update.hpp"
#include "mamba/api/channel_loader.hpp"
#include "mamba/api/channel_loader.hpp"
#include "mamba/api/configuration.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/pinning.hpp" #include "mamba/core/pinning.hpp"
#include "mamba/core/transaction.hpp" #include "mamba/core/transaction.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/virtual_packages.hpp" #include "mamba/core/virtual_packages.hpp"
@ -23,8 +23,10 @@ namespace mamba
config.at("use_target_prefix_fallback").set_value(true); config.at("use_target_prefix_fallback").set_value(true);
config.at("target_prefix_checks") config.at("target_prefix_checks")
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_NOT_ALLOW_MISSING_PREFIX .set_value(
| MAMBA_NOT_ALLOW_NOT_ENV_PREFIX | MAMBA_EXPECT_EXISTING_PREFIX); MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_NOT_ALLOW_MISSING_PREFIX
| MAMBA_NOT_ALLOW_NOT_ENV_PREFIX | MAMBA_EXPECT_EXISTING_PREFIX
);
config.load(); config.load();
auto update_specs = config.at("specs").value<std::vector<std::string>>(); auto update_specs = config.at("specs").value<std::vector<std::string>>();
@ -59,17 +61,20 @@ namespace mamba
std::vector<std::string> prefix_pkgs; std::vector<std::string> prefix_pkgs;
for (auto& it : prefix_data.records()) for (auto& it : prefix_data.records())
{
prefix_pkgs.push_back(it.first); prefix_pkgs.push_back(it.first);
}
prefix_data.add_packages(get_virtual_packages()); prefix_data.add_packages(get_virtual_packages());
MRepo::create(pool, prefix_data); MRepo::create(pool, prefix_data);
MSolver solver(std::move(pool), MSolver solver(
{ { SOLVER_FLAG_ALLOW_DOWNGRADE, ctx.allow_downgrade }, std::move(pool),
{ SOLVER_FLAG_ALLOW_UNINSTALL, ctx.allow_uninstall }, { { SOLVER_FLAG_ALLOW_DOWNGRADE, ctx.allow_downgrade },
{ SOLVER_FLAG_STRICT_REPO_PRIORITY, { SOLVER_FLAG_ALLOW_UNINSTALL, ctx.allow_uninstall },
ctx.channel_priority == ChannelPriority::kStrict } }); { SOLVER_FLAG_STRICT_REPO_PRIORITY, ctx.channel_priority == ChannelPriority::kStrict } }
);
if (update_all) if (update_all)
{ {
@ -113,7 +118,9 @@ namespace mamba
{ {
std::vector<std::string> pinned_str; std::vector<std::string> pinned_str;
for (auto& ms : solver.pinned_specs()) for (auto& ms : solver.pinned_specs())
{
pinned_str.push_back(" - " + ms.conda_build_form() + "\n"); pinned_str.push_back(" - " + ms.conda_build_form() + "\n");
}
Console::instance().print("\nPinned packages:\n" + join("", pinned_str)); Console::instance().print("\nPinned packages:\n" + join("", pinned_str));
} }
@ -124,11 +131,15 @@ namespace mamba
auto execute_transaction = [&](MTransaction& transaction) auto execute_transaction = [&](MTransaction& transaction)
{ {
if (ctx.json) if (ctx.json)
{
transaction.log_json(); transaction.log_json();
}
bool yes = transaction.prompt(); bool yes = transaction.prompt();
if (yes) if (yes)
{
transaction.execute(prefix_data); transaction.execute(prefix_data);
}
}; };
execute_transaction(transaction); execute_transaction(transaction);

View File

@ -5,6 +5,7 @@
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/activation.hpp" #include "mamba/core/activation.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/environment.hpp" #include "mamba/core/environment.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
@ -63,8 +64,8 @@ namespace mamba
} }
} }
std::vector<std::pair<std::string, std::string>> Activator::get_environment_vars( std::vector<std::pair<std::string, std::string>>
const fs::u8path& prefix) Activator::get_environment_vars(const fs::u8path& prefix)
{ {
fs::u8path env_vars_file = prefix / PREFIX_STATE_FILE; fs::u8path env_vars_file = prefix / PREFIX_STATE_FILE;
fs::u8path pkg_env_var_dir = prefix / PACKAGE_ENV_VARS_DIR; fs::u8path pkg_env_var_dir = prefix / PACKAGE_ENV_VARS_DIR;
@ -125,9 +126,11 @@ namespace mamba
return res; return res;
} }
std::string Activator::get_prompt_modifier(const fs::u8path& prefix, std::string Activator::get_prompt_modifier(
const std::string& conda_default_env, const fs::u8path& prefix,
int old_conda_shlvl) const std::string& conda_default_env,
int old_conda_shlvl
)
{ {
if (Context::instance().change_ps1) if (Context::instance().change_ps1)
{ {
@ -136,10 +139,12 @@ namespace mamba
std::string env_i; std::string env_i;
for (int i = 1; i < old_conda_shlvl + 1; ++i) for (int i = 1; i < old_conda_shlvl + 1; ++i)
{ {
const std::string env_prefix const std::string env_prefix = (i == old_conda_shlvl)
= (i == old_conda_shlvl) ? "CONDA_PREFIX" : "CONDA_PREFIX_" + std::to_string(i); ? "CONDA_PREFIX"
const std::string default_prefix : "CONDA_PREFIX_" + std::to_string(i);
= (m_env.find(env_prefix) != m_env.end()) ? m_env[env_prefix] : ""; const std::string default_prefix = (m_env.find(env_prefix) != m_env.end())
? m_env[env_prefix]
: "";
env_i = get_default_env(default_prefix); env_i = get_default_env(default_prefix);
bool stacked_i = m_env.find("CONDA_STACKED_" + std::to_string(i)) != m_env.end(); bool stacked_i = m_env.find("CONDA_STACKED_" + std::to_string(i)) != m_env.end();
@ -156,11 +161,15 @@ namespace mamba
if (m_action == ActivationType::DEACTIVATE) if (m_action == ActivationType::DEACTIVATE)
{ {
if (prompt_stack.size()) if (prompt_stack.size())
{
prompt_stack.pop_back(); prompt_stack.pop_back();
}
if (env_stack.size()) if (env_stack.size())
{
env_stack.pop_back(); env_stack.pop_back();
bool stacked }
= m_env.find("CONDA_STACKED_" + std::to_string(old_conda_shlvl)) != m_env.end(); bool stacked = m_env.find("CONDA_STACKED_" + std::to_string(old_conda_shlvl))
!= m_env.end();
if (!stacked && env_stack.size()) if (!stacked && env_stack.size())
{ {
prompt_stack.push_back(env_stack.back()); prompt_stack.push_back(env_stack.back());
@ -268,10 +277,11 @@ namespace mamba
// never trigger. // never trigger.
if (old_conda_shlvl == 0) if (old_conda_shlvl == 0)
{ {
bool no_condabin = std::none_of(path_list.begin(), bool no_condabin = std::none_of(
path_list.end(), path_list.begin(),
[](const fs::u8path& s) path_list.end(),
{ return ends_with(s.string(), "condabin"); }); [](const fs::u8path& s) { return ends_with(s.string(), "condabin"); }
);
if (no_condabin) if (no_condabin)
{ {
auto condabin_dir = Context::instance().root_prefix / "condabin"; auto condabin_dir = Context::instance().root_prefix / "condabin";
@ -289,8 +299,8 @@ namespace mamba
return result; return result;
} }
std::string Activator::replace_prefix_in_path(const fs::u8path& old_prefix, std::string
const fs::u8path& new_prefix) Activator::replace_prefix_in_path(const fs::u8path& old_prefix, const fs::u8path& new_prefix)
{ {
// TODO not done yet. // TODO not done yet.
std::vector<fs::u8path> current_path = get_clean_dirs(); std::vector<fs::u8path> current_path = get_clean_dirs();
@ -333,8 +343,10 @@ namespace mamba
} }
else else
{ {
current_path.erase(std::unique(current_path.begin(), current_path.end()), current_path.erase(
current_path.end()); std::unique(current_path.begin(), current_path.end()),
current_path.end()
);
std::string result = join(env::pathsep(), current_path).string(); std::string result = join(env::pathsep(), current_path).string();
return result; return result;
} }
@ -347,7 +359,8 @@ namespace mamba
void Activator::get_export_unset_vars( void Activator::get_export_unset_vars(
EnvironmentTransform& envt, EnvironmentTransform& envt,
const std::vector<std::pair<std::string, std::string>>& to_export) const std::vector<std::pair<std::string, std::string>>& to_export
)
{ {
// conda_exe_vars_export = OrderedDict() // conda_exe_vars_export = OrderedDict()
// for k, v in context.conda_exe_vars_dict.items(): // for k, v in context.conda_exe_vars_dict.items():
@ -395,8 +408,11 @@ namespace mamba
auto new_path = replace_prefix_in_path(conda_prefix, conda_prefix); auto new_path = replace_prefix_in_path(conda_prefix, conda_prefix);
std::string conda_prompt_modifier std::string conda_prompt_modifier = get_prompt_modifier(
= get_prompt_modifier(conda_prefix, conda_default_env, conda_shlvl); conda_prefix,
conda_default_env,
conda_shlvl
);
if (Context::instance().change_ps1) if (Context::instance().change_ps1)
{ {
auto res = update_prompt(conda_prompt_modifier); auto res = update_prompt(conda_prompt_modifier);
@ -406,10 +422,11 @@ namespace mamba
} }
} }
std::vector<std::pair<std::string, std::string>> env_vars_to_export std::vector<std::pair<std::string, std::string>> env_vars_to_export = {
= { { "path", new_path }, { "path", new_path },
{ "conda_shlvl", std::to_string(conda_shlvl) }, { "conda_shlvl", std::to_string(conda_shlvl) },
{ "conda_prompt_modifier", conda_prompt_modifier } }; { "conda_prompt_modifier", conda_prompt_modifier }
};
get_export_unset_vars(envt, env_vars_to_export); get_export_unset_vars(envt, env_vars_to_export);
// TODO figure out if this is all really necessary? // TODO figure out if this is all really necessary?
@ -456,11 +473,12 @@ namespace mamba
// and anything at all in my env still references it (apart from the shell // and anything at all in my env still references it (apart from the shell
// script, we need something I suppose!) // script, we need something I suppose!)
envt.export_path = new_path; envt.export_path = new_path;
std::vector<std::pair<std::string, std::string>> env_vars_to_export std::vector<std::pair<std::string, std::string>> env_vars_to_export = {
= { { "conda_prefix", "" }, { "conda_prefix", "" },
{ "conda_shlvl", std::to_string(new_conda_shlvl) }, { "conda_shlvl", std::to_string(new_conda_shlvl) },
{ "conda_default_env", "" }, { "conda_default_env", "" },
{ "conda_prompt_modifier", "" } }; { "conda_prompt_modifier", "" }
};
get_export_unset_vars(envt, env_vars_to_export); get_export_unset_vars(envt, env_vars_to_export);
} }
else else
@ -468,8 +486,7 @@ namespace mamba
assert(old_conda_shlvl > 1); assert(old_conda_shlvl > 1);
std::string new_prefix = m_env.at("CONDA_PREFIX_" + std::to_string(new_conda_shlvl)); std::string new_prefix = m_env.at("CONDA_PREFIX_" + std::to_string(new_conda_shlvl));
std::string conda_default_env = get_default_env(new_prefix); std::string conda_default_env = get_default_env(new_prefix);
conda_prompt_modifier conda_prompt_modifier = get_prompt_modifier(new_prefix, conda_default_env, old_conda_shlvl);
= get_prompt_modifier(new_prefix, conda_default_env, old_conda_shlvl);
auto new_conda_environment_env_vars = get_environment_vars(new_prefix); auto new_conda_environment_env_vars = get_environment_vars(new_prefix);
bool old_prefix_stacked bool old_prefix_stacked
@ -487,11 +504,12 @@ namespace mamba
new_path = replace_prefix_in_path(old_conda_prefix, new_prefix); new_path = replace_prefix_in_path(old_conda_prefix, new_prefix);
} }
std::vector<std::pair<std::string, std::string>> env_vars_to_export std::vector<std::pair<std::string, std::string>> env_vars_to_export = {
= { { "conda_prefix", new_prefix }, { "conda_prefix", new_prefix },
{ "conda_shlvl", std::to_string(new_conda_shlvl) }, { "conda_shlvl", std::to_string(new_conda_shlvl) },
{ "conda_default_env", conda_default_env }, { "conda_default_env", conda_default_env },
{ "conda_prompt_modifier", conda_prompt_modifier } }; { "conda_prompt_modifier", conda_prompt_modifier }
};
get_export_unset_vars(envt, env_vars_to_export); get_export_unset_vars(envt, env_vars_to_export);
@ -516,8 +534,7 @@ namespace mamba
for (auto& env_var : old_conda_environment_env_vars) for (auto& env_var : old_conda_environment_env_vars)
{ {
envt.unset_vars.push_back(env_var.first); envt.unset_vars.push_back(env_var.first);
std::string save_var std::string save_var = fmt::format("__CONDA_SHLVL_{}_{}", new_conda_shlvl, env_var.first);
= fmt::format("__CONDA_SHLVL_{}_{}", new_conda_shlvl, env_var.first);
if (m_env.find(save_var) != m_env.end()) if (m_env.find(save_var) != m_env.end())
{ {
envt.export_vars.push_back({ env_var.first, m_env[save_var] }); envt.export_vars.push_back({ env_var.first, m_env[save_var] });
@ -576,27 +593,35 @@ namespace mamba
envt.activate_scripts = get_activate_scripts(prefix); envt.activate_scripts = get_activate_scripts(prefix);
std::string conda_default_env = get_default_env(prefix); std::string conda_default_env = get_default_env(prefix);
std::string conda_prompt_modifier std::string conda_prompt_modifier = get_prompt_modifier(
= get_prompt_modifier(prefix, conda_default_env, old_conda_shlvl); prefix,
conda_default_env,
old_conda_shlvl
);
auto conda_environment_env_vars = get_environment_vars(prefix); auto conda_environment_env_vars = get_environment_vars(prefix);
// TODO check with conda if that's really what's supposed to happen ... // TODO check with conda if that's really what's supposed to happen ...
std::remove_if(conda_environment_env_vars.begin(), std::remove_if(
conda_environment_env_vars.end(), conda_environment_env_vars.begin(),
[](auto& el) { return el.second == CONDA_ENV_VARS_UNSET_VAR; }); conda_environment_env_vars.end(),
[](auto& el) { return el.second == CONDA_ENV_VARS_UNSET_VAR; }
);
std::vector<std::string> clobbering_env_vars; std::vector<std::string> clobbering_env_vars;
for (auto& env_var : conda_environment_env_vars) for (auto& env_var : conda_environment_env_vars)
{ {
if (m_env.find(env_var.first) != m_env.end()) if (m_env.find(env_var.first) != m_env.end())
{
clobbering_env_vars.push_back(env_var.first); clobbering_env_vars.push_back(env_var.first);
}
} }
for (const auto& v : clobbering_env_vars) for (const auto& v : clobbering_env_vars)
{ {
conda_environment_env_vars.push_back( conda_environment_env_vars.push_back(
{ fmt::format("__CONDA_SHLVL_{}_{}", old_conda_shlvl, v), m_env[v] }); { fmt::format("__CONDA_SHLVL_{}_{}", old_conda_shlvl, v), m_env[v] }
);
} }
if (clobbering_env_vars.size()) if (clobbering_env_vars.size())
@ -627,10 +652,9 @@ namespace mamba
else if (m_stack) else if (m_stack)
{ {
get_export_unset_vars(envt, env_vars_to_export); get_export_unset_vars(envt, env_vars_to_export);
envt.export_vars.push_back( envt.export_vars.push_back({ fmt::format("CONDA_PREFIX_{}", old_conda_shlvl),
{ fmt::format("CONDA_PREFIX_{}", old_conda_shlvl), old_conda_prefix }); old_conda_prefix });
envt.export_vars.push_back( envt.export_vars.push_back({ fmt::format("CONDA_STACKED_{}", new_conda_shlvl), "true" });
{ fmt::format("CONDA_STACKED_{}", new_conda_shlvl), "true" });
} }
else else
{ {
@ -647,15 +671,17 @@ namespace mamba
+ env_var.first; // % (new_conda_shlvl, env_var) + env_var.first; // % (new_conda_shlvl, env_var)
if (m_env.find(save_var) != m_env.end()) if (m_env.find(save_var) != m_env.end())
{ {
envt.export_vars.insert(envt.export_vars.begin(), envt.export_vars.insert(
{ env_var.first, m_env[save_var] }); envt.export_vars.begin(),
{ env_var.first, m_env[save_var] }
);
} }
} }
env_vars_to_export[0] = { "PATH", new_path }; env_vars_to_export[0] = { "PATH", new_path };
get_export_unset_vars(envt, env_vars_to_export); get_export_unset_vars(envt, env_vars_to_export);
envt.export_vars.push_back( envt.export_vars.push_back({ fmt::format("CONDA_PREFIX_{}", old_conda_shlvl),
{ fmt::format("CONDA_PREFIX_{}", old_conda_shlvl), old_conda_prefix }); old_conda_prefix });
} }
if (Context::instance().change_ps1) if (Context::instance().change_ps1)
@ -788,8 +814,8 @@ namespace mamba
return out.str(); return out.str();
} }
std::pair<std::string, std::string> PosixActivator::update_prompt( std::pair<std::string, std::string>
const std::string& conda_prompt_modifier) PosixActivator::update_prompt(const std::string& conda_prompt_modifier)
{ {
std::string ps1 = (m_env.find("PS1") != m_env.end()) ? m_env["PS1"] : ""; std::string ps1 = (m_env.find("PS1") != m_env.end()) ? m_env["PS1"] : "";
if (ps1.find("POWERLINE_COMMAND") != ps1.npos) if (ps1.find("POWERLINE_COMMAND") != ps1.npos)
@ -907,8 +933,8 @@ namespace mamba
return out.str(); return out.str();
} }
std::pair<std::string, std::string> CshActivator::update_prompt( std::pair<std::string, std::string>
const std::string& conda_prompt_modifier) CshActivator::update_prompt(const std::string& conda_prompt_modifier)
{ {
std::string prompt = (m_env.find("prompt") != m_env.end()) ? m_env["prompt"] : ""; std::string prompt = (m_env.find("prompt") != m_env.end()) ? m_env["prompt"] : "";
auto current_prompt_modifier = env::get("CONDA_PROMPT_MODIFIER"); auto current_prompt_modifier = env::get("CONDA_PROMPT_MODIFIER");
@ -975,8 +1001,8 @@ namespace mamba
return ""; return "";
} }
std::pair<std::string, std::string> CmdExeActivator::update_prompt( std::pair<std::string, std::string>
const std::string& /* conda_prompt_modifier */) CmdExeActivator::update_prompt(const std::string& /* conda_prompt_modifier */)
{ {
return { "", "" }; return { "", "" };
} }
@ -1035,8 +1061,10 @@ namespace mamba
std::string PowerShellActivator::hook_preamble() std::string PowerShellActivator::hook_preamble()
{ {
return fmt::format("$MambaModuleArgs = @{{ChangePs1 = ${}}}", return fmt::format(
Context::instance().change_ps1 ? "True" : "False"); "$MambaModuleArgs = @{{ChangePs1 = ${}}}",
Context::instance().change_ps1 ? "True" : "False"
);
} }
std::string PowerShellActivator::hook_postamble() std::string PowerShellActivator::hook_postamble()
@ -1049,8 +1077,8 @@ namespace mamba
return Context::instance().root_prefix / "condabin" / "mamba_hook.ps1"; return Context::instance().root_prefix / "condabin" / "mamba_hook.ps1";
} }
std::pair<std::string, std::string> PowerShellActivator::update_prompt( std::pair<std::string, std::string>
const std::string& /*conda_prompt_modifier*/) PowerShellActivator::update_prompt(const std::string& /*conda_prompt_modifier*/)
{ {
return { "", "" }; return { "", "" };
} }
@ -1117,8 +1145,8 @@ namespace mamba
return Context::instance().root_prefix / "etc" / "profile.d" / "mamba.xsh"; return Context::instance().root_prefix / "etc" / "profile.d" / "mamba.xsh";
} }
std::pair<std::string, std::string> XonshActivator::update_prompt( std::pair<std::string, std::string>
const std::string& /*conda_prompt_modifier*/) XonshActivator::update_prompt(const std::string& /*conda_prompt_modifier*/)
{ {
return { "", "" }; return { "", "" };
} }
@ -1185,8 +1213,8 @@ namespace mamba
return Context::instance().root_prefix / "etc" / "fish" / "conf.d" / "mamba.fish"; return Context::instance().root_prefix / "etc" / "fish" / "conf.d" / "mamba.fish";
} }
std::pair<std::string, std::string> FishActivator::update_prompt( std::pair<std::string, std::string>
const std::string& /*conda_prompt_modifier*/) FishActivator::update_prompt(const std::string& /*conda_prompt_modifier*/)
{ {
return { "", "" }; return { "", "" };
} }

View File

@ -22,7 +22,6 @@
#include "mamba/core/url.hpp" #include "mamba/core/url.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/core/validate.hpp" #include "mamba/core/validate.hpp"
#include "mamba/core/environment.hpp"
namespace mamba namespace mamba
@ -30,22 +29,27 @@ namespace mamba
// Constants used by Channel and ChannelContext // Constants used by Channel and ChannelContext
namespace namespace
{ {
const std::map<std::string, std::string> DEFAULT_CUSTOM_CHANNELS const std::map<std::string, std::string> DEFAULT_CUSTOM_CHANNELS = {
= { { "pkgs/pro", "https://repo.anaconda.com" } }; { "pkgs/pro", "https://repo.anaconda.com" }
};
const char UNKNOWN_CHANNEL[] = "<unknown>"; const char UNKNOWN_CHANNEL[] = "<unknown>";
const std::set<std::string> INVALID_CHANNELS const std::set<std::string> INVALID_CHANNELS = { "<unknown>",
= { "<unknown>", "None:///<unknown>", "None", "", ":///<unknown>" }; "None:///<unknown>",
"None",
"",
":///<unknown>" };
const char LOCAL_CHANNELS_NAME[] = "local"; const char LOCAL_CHANNELS_NAME[] = "local";
const char DEFAULT_CHANNELS_NAME[] = "defaults"; const char DEFAULT_CHANNELS_NAME[] = "defaults";
// ATTENTION names with substrings need to go longer -> smalle // ATTENTION names with substrings need to go longer -> smalle
// otherwise linux-ppc64 matches for linux-ppc64le etc! // otherwise linux-ppc64 matches for linux-ppc64le etc!
const std::vector<std::string> KNOWN_PLATFORMS const std::vector<std::string> KNOWN_PLATFORMS = {
= { "noarch", "linux-32", "linux-64", "linux-aarch64", "linux-armv6l", "noarch", "linux-32", "linux-64", "linux-aarch64", "linux-armv6l",
"linux-armv7l", "linux-ppc64le", "linux-ppc64", "osx-64", "osx-arm64", "linux-armv7l", "linux-ppc64le", "linux-ppc64", "osx-64", "osx-arm64",
"win-32", "win-64", "zos-z" }; "win-32", "win-64", "zos-z"
};
} // namespace } // namespace
/************************** /**************************
@ -86,13 +90,15 @@ namespace mamba
} }
} }
Channel::Channel(const std::string& scheme, Channel::Channel(
const std::string& location, const std::string& scheme,
const std::string& name, const std::string& location,
const std::optional<std::string>& auth, const std::string& name,
const std::optional<std::string>& token, const std::optional<std::string>& auth,
const std::optional<std::string>& package_filename, const std::optional<std::string>& token,
const std::optional<std::string>& canonical_name) const std::optional<std::string>& package_filename,
const std::optional<std::string>& canonical_name
)
: m_scheme(scheme) : m_scheme(scheme)
, m_location(location) , m_location(location)
, m_name(name) , m_name(name)
@ -147,7 +153,8 @@ namespace mamba
rsplit(base_url(), "/", 1).front(), rsplit(base_url(), "/", 1).front(),
Context::instance().root_prefix / "etc" / "trusted-repos" Context::instance().root_prefix / "etc" / "trusted-repos"
/ cache_name_from_url(base_url()), / cache_name_from_url(base_url()),
caches.first_writable_path() / "cache" / cache_name_from_url(base_url())); caches.first_writable_path() / "cache" / cache_name_from_url(base_url())
);
fs::create_directories(p_repo_checker->cache_path()); fs::create_directories(p_repo_checker->cache_path());
p_repo_checker->generate_index_checker(); p_repo_checker->generate_index_checker();
@ -204,8 +211,9 @@ namespace mamba
} }
std::string platform = m_platforms[0]; std::string platform = m_platforms[0];
return { { build_url( return {
*this, join_url(base, name(), platform, *package_filename()), with_credential) } }; { build_url(*this, join_url(base, name(), platform, *package_filename()), with_credential) }
};
} }
else else
{ {
@ -218,8 +226,7 @@ namespace mamba
} }
} }
std::vector<std::pair<std::string, std::string>> Channel::platform_urls( std::vector<std::pair<std::string, std::string>> Channel::platform_urls(bool with_credential) const
bool with_credential) const
{ {
std::string base = location(); std::string base = location();
if (with_credential && token()) if (with_credential && token())
@ -230,8 +237,10 @@ namespace mamba
std::vector<std::pair<std::string, std::string>> ret; std::vector<std::pair<std::string, std::string>> ret;
for (const auto& platform : platforms()) for (const auto& platform : platforms())
{ {
ret.emplace_back(platform, ret.emplace_back(
build_url(*this, join_url(base, name(), platform), with_credential)); platform,
build_url(*this, join_url(base, name(), platform), with_credential)
);
} }
return ret; return ret;
} }
@ -309,24 +318,30 @@ namespace mamba
if (whitelist.size()) if (whitelist.size())
{ {
std::vector<std::string> accepted_urls(whitelist.size()); std::vector<std::string> accepted_urls(whitelist.size());
std::transform(whitelist.begin(), std::transform(
whitelist.end(), whitelist.begin(),
accepted_urls.begin(), whitelist.end(),
[](const std::string& url) { return make_channel(url).base_url(); }); accepted_urls.begin(),
std::for_each(urls.begin(), [](const std::string& url) { return make_channel(url).base_url(); }
urls.end(), );
[&accepted_urls](const std::string& s) std::for_each(
{ urls.begin(),
auto it = std::find(accepted_urls.begin(), urls.end(),
accepted_urls.end(), [&accepted_urls](const std::string& s)
make_channel(s).base_url()); {
if (it == accepted_urls.end()) auto it = std::find(
{ accepted_urls.begin(),
std::ostringstream str; accepted_urls.end(),
str << "Channel " << s << " not allowed"; make_channel(s).base_url()
throw std::runtime_error(str.str().c_str()); );
} if (it == accepted_urls.end())
}); {
std::ostringstream str;
str << "Channel " << s << " not allowed";
throw std::runtime_error(str.str().c_str());
}
}
);
} }
} }
@ -334,10 +349,12 @@ namespace mamba
* ChannelBuilder implementation * * ChannelBuilder implementation *
*********************************/ *********************************/
Channel ChannelBuilder::make_simple_channel(const Channel& channel_alias, Channel ChannelBuilder::make_simple_channel(
const std::string& channel_url, const Channel& channel_alias,
const std::string& channel_name, const std::string& channel_url,
const std::string& multi_name) const std::string& channel_name,
const std::string& multi_name
)
{ {
std::string name(channel_name); std::string name(channel_name);
std::string location, scheme, auth, token; std::string location, scheme, auth, token;
@ -362,18 +379,22 @@ namespace mamba
std::string full_url = concat_scheme_url(scheme, location); std::string full_url = concat_scheme_url(scheme, location);
URLHandler parser(full_url); URLHandler parser(full_url);
location = rstrip( location = rstrip(
URLHandler().set_host(parser.host()).set_port(parser.port()).url(), "/"); URLHandler().set_host(parser.host()).set_port(parser.port()).url(),
"/"
);
name = lstrip(parser.path(), "/"); name = lstrip(parser.path(), "/");
} }
} }
name = name != "" ? strip(name, "/") : strip(channel_url, "/"); name = name != "" ? strip(name, "/") : strip(channel_url, "/");
return Channel(scheme, return Channel(
location, scheme,
name, location,
nonempty_str(std::move(auth)), name,
nonempty_str(std::move(token)), nonempty_str(std::move(auth)),
{}, nonempty_str(std::move(token)),
nonempty_str(std::string(multi_name))); {},
nonempty_str(std::string(multi_name))
);
} }
const Channel& ChannelBuilder::make_cached_channel(const std::string& value) const Channel& ChannelBuilder::make_cached_channel(const std::string& value)
@ -386,10 +407,12 @@ namespace mamba
auto chan = ChannelBuilder::from_value(value); auto chan = ChannelBuilder::from_value(value);
if (!chan.token()) if (!chan.token())
{ {
auto const& with_channel const auto& with_channel = join_url(
= join_url(chan.location(), chan.name() == UNKNOWN_CHANNEL ? "" : chan.name()); chan.location(),
auto const& without_channel = chan.location(); chan.name() == UNKNOWN_CHANNEL ? "" : chan.name()
for (auto const& auth : { with_channel, without_channel }) );
const auto& without_channel = chan.location();
for (const auto& auth : { with_channel, without_channel })
{ {
auto it = ctx.authentication_info().find(auth); auto it = ctx.authentication_info().find(auth);
if (it != ctx.authentication_info().end() if (it != ctx.authentication_info().end()
@ -398,8 +421,7 @@ namespace mamba
chan.m_token = it->second.value; chan.m_token = it->second.value;
break; break;
} }
else if (it != ctx.authentication_info().end() else if (it != ctx.authentication_info().end() && it->second.type == AuthenticationType::kBasicHTTPAuthentication)
&& it->second.type == AuthenticationType::kBasicHTTPAuthentication)
{ {
chan.m_auth = it->second.value; chan.m_auth = it->second.value;
break; break;
@ -418,14 +440,16 @@ namespace mamba
namespace namespace
{ {
void split_conda_url(const std::string& url, void split_conda_url(
std::string& scheme, const std::string& url,
std::string& host, std::string& scheme,
std::string& port, std::string& host,
std::string& path, std::string& port,
std::string& auth, std::string& path,
std::string& token, std::string& auth,
std::string& package_name) std::string& token,
std::string& package_name
)
{ {
std::string cleaned_url, extension; std::string cleaned_url, extension;
split_anaconda_token(url, cleaned_url, token); split_anaconda_token(url, cleaned_url, token);
@ -452,11 +476,13 @@ namespace mamba
struct channel_configuration struct channel_configuration
{ {
channel_configuration(const std::string& location, channel_configuration(
const std::string& name, const std::string& location,
const std::string& scheme, const std::string& name,
const std::string& auth, const std::string& scheme,
const std::string& token) const std::string& auth,
const std::string& token
)
: m_location(location) : m_location(location)
, m_name(name) , m_name(name)
, m_scheme(scheme) , m_scheme(scheme)
@ -472,23 +498,27 @@ namespace mamba
std::string m_token; std::string m_token;
}; };
channel_configuration read_channel_configuration(const std::string& scheme, channel_configuration read_channel_configuration(
const std::string& host, const std::string& scheme,
const std::string& port, const std::string& host,
const std::string& path) const std::string& port,
const std::string& path
)
{ {
std::string spath = std::string(rstrip(path, "/")); std::string spath = std::string(rstrip(path, "/"));
std::string url std::string url = URLHandler()
= URLHandler().set_scheme(scheme).set_host(host).set_port(port).set_path(spath).url( .set_scheme(scheme)
true); .set_host(host)
.set_port(port)
.set_path(spath)
.url(true);
// Case 1: No path given, channel name is "" // Case 1: No path given, channel name is ""
if (spath == "") if (spath == "")
{ {
URLHandler handler; URLHandler handler;
handler.set_host(host).set_port(port); handler.set_host(host).set_port(port);
return channel_configuration( return channel_configuration(std::string(rstrip(handler.url(), "/")), "", scheme, "", "");
std::string(rstrip(handler.url(), "/")), "", scheme, "", "");
} }
// Case 2: migrated_custom_channels not implemented yet // Case 2: migrated_custom_channels not implemented yet
@ -504,11 +534,13 @@ namespace mamba
{ {
auto subname = std::string(strip(url.replace(0u, test_url.size(), ""), "/")); auto subname = std::string(strip(url.replace(0u, test_url.size(), ""), "/"));
return channel_configuration(channel.location(), return channel_configuration(
join_url(channel.name(), subname), channel.location(),
scheme, join_url(channel.name(), subname),
channel.auth().value_or(""), scheme,
channel.token().value_or("")); channel.auth().value_or(""),
channel.token().value_or("")
);
} }
} }
@ -518,7 +550,12 @@ namespace mamba
{ {
auto name = std::string(strip(url.replace(0u, ca.location().size(), ""), "/")); auto name = std::string(strip(url.replace(0u, ca.location().size(), ""), "/"));
return channel_configuration( return channel_configuration(
ca.location(), name, scheme, ca.auth().value_or(""), ca.token().value_or("")); ca.location(),
name,
scheme,
ca.auth().value_or(""),
ca.token().value_or("")
);
} }
// Case 6: not-otherwise-specified file://-type urls // Case 6: not-otherwise-specified file://-type urls
@ -548,7 +585,8 @@ namespace mamba
config.m_name, config.m_name,
auth.size() ? std::make_optional(auth) : nonempty_str(std::move(config.m_auth)), auth.size() ? std::make_optional(auth) : nonempty_str(std::move(config.m_auth)),
token.size() ? std::make_optional(token) : nonempty_str(std::move(config.m_token)), token.size() ? std::make_optional(token) : nonempty_str(std::move(config.m_token)),
nonempty_str(std::move(package_name))); nonempty_str(std::move(package_name))
);
} }
Channel ChannelBuilder::from_name(const std::string& name) Channel ChannelBuilder::from_name(const std::string& name)
@ -585,13 +623,15 @@ namespace mamba
combined_name += name.substr(name.find('/') + 1, std::string::npos); combined_name += name.substr(name.find('/') + 1, std::string::npos);
} }
return Channel(it->second.scheme(), return Channel(
it->second.location(), it->second.scheme(),
combined_name, it->second.location(),
it->second.auth(), combined_name,
it->second.token(), it->second.auth(),
it->second.package_filename(), it->second.token(),
name); it->second.package_filename(),
name
);
} }
else else
{ {
@ -619,21 +659,29 @@ namespace mamba
#endif #endif
} }
void split_platform(const std::vector<std::string>& known_platforms, void split_platform(
const std::string& url, const std::vector<std::string>& known_platforms,
std::string& cleaned_url, const std::string& url,
std::string& platform) std::string& cleaned_url,
std::string& platform
)
{ {
platform = ""; platform = "";
auto check_platform_position = [&url](std::size_t pos, const std::string& platform) -> bool auto check_platform_position = [&url](std::size_t pos, const std::string& platform) -> bool
{ {
if (pos == std::string::npos) if (pos == std::string::npos)
{
return false; return false;
}
if (pos > 0 && url[pos - 1] != '/') if (pos > 0 && url[pos - 1] != '/')
{
return false; return false;
}
if ((pos + platform.size()) < url.size() && url[pos + platform.size()] != '/') if ((pos + platform.size()) < url.size() && url[pos + platform.size()] != '/')
{
return false; return false;
}
return true; return true;
}; };
@ -684,7 +732,9 @@ namespace mamba
platforms.emplace_back(value.substr(ind, end - ind)); platforms.emplace_back(value.substr(ind, end - ind));
ind = end; ind = end;
while (value[ind] == ',' || value[ind] == ' ') while (value[ind] == ',' || value[ind] == ' ')
{
ind++; ind++;
}
} }
value.resize(end_value); value.resize(end_value);
@ -732,10 +782,12 @@ namespace mamba
return chan; return chan;
} }
Channel ChannelBuilder::from_alias(const std::string& scheme, Channel ChannelBuilder::from_alias(
const std::string& location, const std::string& scheme,
const std::optional<std::string>& auth, const std::string& location,
const std::optional<std::string>& token) const std::optional<std::string>& auth,
const std::optional<std::string>& token
)
{ {
return Channel(scheme, location, "<alias>", auth, token); return Channel(scheme, location, "<alias>", auth, token);
} }
@ -792,7 +844,11 @@ namespace mamba
std::string location, scheme, auth, token; std::string location, scheme, auth, token;
split_scheme_auth_token(alias, location, scheme, auth, token); split_scheme_auth_token(alias, location, scheme, auth, token);
return ChannelBuilder::from_alias( return ChannelBuilder::from_alias(
scheme, location, nonempty_str(std::move(auth)), nonempty_str(std::move(token))); scheme,
location,
nonempty_str(std::move(auth)),
nonempty_str(std::move(token))
);
} }
void ChannelContext::init_custom_channels() void ChannelContext::init_custom_channels()
@ -808,7 +864,11 @@ namespace mamba
for (auto& url : default_channels) for (auto& url : default_channels)
{ {
auto channel = ChannelBuilder::make_simple_channel( auto channel = ChannelBuilder::make_simple_channel(
m_channel_alias, url, "", DEFAULT_CHANNELS_NAME); m_channel_alias,
url,
"",
DEFAULT_CHANNELS_NAME
);
std::string name = channel.name(); std::string name = channel.name();
auto res = m_custom_channels.emplace(std::move(name), std::move(channel)); auto res = m_custom_channels.emplace(std::move(name), std::move(channel));
*default_name_iter++ = res.first->first; *default_name_iter++ = res.first->first;
@ -816,10 +876,11 @@ namespace mamba
m_custom_multichannels.emplace(DEFAULT_CHANNELS_NAME, std::move(default_names)); m_custom_multichannels.emplace(DEFAULT_CHANNELS_NAME, std::move(default_names));
// Local channels // Local channels
std::vector<std::string> local_channels std::vector<std::string> local_channels = {
= { Context::instance().target_prefix.string() + "/conda-bld", Context::instance().target_prefix.string() + "/conda-bld",
Context::instance().root_prefix.string() + "/conda-bld", Context::instance().root_prefix.string() + "/conda-bld",
"~/conda-bld" }; "~/conda-bld"
};
std::vector<std::string> local_names; std::vector<std::string> local_names;
local_names.reserve(local_channels.size()); local_names.reserve(local_channels.size());
@ -829,7 +890,11 @@ namespace mamba
{ {
std::string url = path_to_url(p); std::string url = path_to_url(p);
auto channel = ChannelBuilder::make_simple_channel( auto channel = ChannelBuilder::make_simple_channel(
m_channel_alias, url, "", LOCAL_CHANNELS_NAME); m_channel_alias,
url,
"",
LOCAL_CHANNELS_NAME
);
std::string name = channel.name(); std::string name = channel.name();
auto res = m_custom_channels.emplace(std::move(name), std::move(channel)); auto res = m_custom_channels.emplace(std::move(name), std::move(channel));
local_names.push_back(res.first->first); local_names.push_back(res.first->first);
@ -842,7 +907,9 @@ namespace mamba
{ {
std::string url = p; std::string url = p;
if (!starts_with(url, "http")) if (!starts_with(url, "http"))
{
url = path_to_url(url); url = path_to_url(url);
}
auto channel = ChannelBuilder::make_simple_channel(m_channel_alias, url, n, ""); auto channel = ChannelBuilder::make_simple_channel(m_channel_alias, url, n, "");
m_custom_channels.emplace(n, std::move(channel)); m_custom_channels.emplace(n, std::move(channel));
@ -856,7 +923,11 @@ namespace mamba
for (auto& url : urllist) for (auto& url : urllist)
{ {
auto channel = ChannelBuilder::make_simple_channel( auto channel = ChannelBuilder::make_simple_channel(
m_channel_alias, url, "", multichannelname); m_channel_alias,
url,
"",
multichannelname
);
std::string name = channel.name(); std::string name = channel.name();
m_custom_channels.emplace(std::move(name), std::move(channel)); m_custom_channels.emplace(std::move(name), std::move(channel));
*name_iter++ = url; *name_iter++ = url;
@ -873,7 +944,8 @@ namespace mamba
{ {
m_custom_channels.emplace( m_custom_channels.emplace(
ch.first, ch.first,
ChannelBuilder::make_simple_channel(m_channel_alias, ch.second, ch.first)); ChannelBuilder::make_simple_channel(m_channel_alias, ch.second, ch.first)
);
} }
} }
} // namespace mamba } // namespace mamba

View File

@ -4,25 +4,28 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/context.hpp"
#include <iostream> #include <iostream>
#include <spdlog/spdlog.h>
#include <spdlog/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
#include <spdlog/sinks/stdout_color_sinks.h> #include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>
#include "mamba/core/context.hpp"
#include "mamba/core/environment.hpp" #include "mamba/core/environment.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/thread_utils.hpp" #include "mamba/core/thread_utils.hpp"
#include "mamba/core/url.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/core/util_os.hpp" #include "mamba/core/util_os.hpp"
#include "mamba/core/url.hpp"
#include "mamba/core/execution.hpp"
namespace mamba namespace mamba
{ {
class Logger : public spdlog::logger class Logger : public spdlog::logger
{ {
public: public:
Logger(const std::string& name, const std::string& pattern, const std::string& eol); Logger(const std::string& name, const std::string& pattern, const std::string& eol);
void dump_backtrace_no_guards(); void dump_backtrace_no_guards();
@ -32,7 +35,10 @@ namespace mamba
: spdlog::logger(name, std::make_shared<spdlog::sinks::stderr_color_sink_mt>()) : spdlog::logger(name, std::make_shared<spdlog::sinks::stderr_color_sink_mt>())
{ {
auto f = std::make_unique<spdlog::pattern_formatter>( auto f = std::make_unique<spdlog::pattern_formatter>(
pattern, spdlog::pattern_time_type::local, eol); pattern,
spdlog::pattern_time_type::local,
eol
);
set_formatter(std::move(f)); set_formatter(std::move(f));
} }
@ -45,8 +51,11 @@ namespace mamba
[this](const log_msg& msg) [this](const log_msg& msg)
{ {
if (this->should_log(msg.level)) if (this->should_log(msg.level))
{
this->sink_it_(msg); this->sink_it_(msg);
}); }
}
);
} }
} }
@ -76,7 +85,7 @@ namespace mamba
keep_temp_directories = env::get("MAMBA_KEEP_TEMP_DIRS") ? true : false; keep_temp_directories = env::get("MAMBA_KEEP_TEMP_DIRS") ? true : false;
{ {
bool const cout_is_atty = is_atty(std::cout); const bool cout_is_atty = is_atty(std::cout);
no_progress_bars = (on_ci || !cout_is_atty); no_progress_bars = (on_ci || !cout_is_atty);
palette = cout_is_atty ? Palette::terminal() : Palette::no_color(); palette = cout_is_atty ? Palette::terminal() : Palette::no_color();
} }
@ -90,10 +99,16 @@ namespace mamba
set_default_signal_handler(); set_default_signal_handler();
std::shared_ptr<spdlog::logger> l = std::make_shared<Logger>("libmamba", log_pattern, "\n"); std::shared_ptr<spdlog::logger> l = std::make_shared<Logger>("libmamba", log_pattern, "\n");
std::shared_ptr<spdlog::logger> libcurl_logger std::shared_ptr<spdlog::logger> libcurl_logger = std::make_shared<Logger>(
= std::make_shared<Logger>("libcurl", log_pattern, ""); "libcurl",
std::shared_ptr<spdlog::logger> libsolv_logger log_pattern,
= std::make_shared<Logger>("libsolv", log_pattern, ""); ""
);
std::shared_ptr<spdlog::logger> libsolv_logger = std::make_shared<Logger>(
"libsolv",
log_pattern,
""
);
spdlog::register_logger(libcurl_logger); spdlog::register_logger(libcurl_logger);
spdlog::register_logger(libsolv_logger); spdlog::register_logger(libsolv_logger);
@ -152,7 +167,9 @@ namespace mamba
std::map<std::string, AuthenticationInfo>& Context::authentication_info() std::map<std::string, AuthenticationInfo>& Context::authentication_info()
{ {
if (!m_authentication_infos_loaded) if (!m_authentication_infos_loaded)
{
load_authentication_info(); load_authentication_info();
}
return m_authentication_info; return m_authentication_info;
} }
@ -196,8 +213,7 @@ namespace mamba
} }
std::map<std::string, AuthenticationInfo> res; std::map<std::string, AuthenticationInfo> res;
fs::u8path auth_loc(mamba::env::home_directory() / ".mamba" / "auth" fs::u8path auth_loc(mamba::env::home_directory() / ".mamba" / "auth" / "authentication.json");
/ "authentication.json");
try try
{ {
if (fs::exists(auth_loc)) if (fs::exists(auth_loc))
@ -220,7 +236,7 @@ namespace mamba
else if (type == "BasicHTTPAuthentication") else if (type == "BasicHTTPAuthentication")
{ {
info.type = AuthenticationType::kBasicHTTPAuthentication; info.type = AuthenticationType::kBasicHTTPAuthentication;
auto const& user = el.value("user", ""); const auto& user = el.value("user", "");
auto pass = decode_base64(el["password"].get<std::string>()); auto pass = decode_base64(el["password"].get<std::string>());
if (pass) if (pass)
{ {

View File

@ -6,12 +6,11 @@
#include "mamba/core/env_lockfile.hpp" #include "mamba/core/env_lockfile.hpp"
#include <yaml-cpp/yaml.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <yaml-cpp/yaml.h>
#include "mamba/core/output.hpp"
#include "mamba/core/match_spec.hpp" #include "mamba/core/match_spec.hpp"
#include "mamba/core/output.hpp"
namespace mamba namespace mamba
{ {
@ -27,7 +26,9 @@ namespace mamba
[&] [&]
{ {
if (const auto& optional_node = package_node["optional"]) if (const auto& optional_node = package_node["optional"])
{
return optional_node.as<bool>(); return optional_node.as<bool>();
}
return false; return false;
}(), }(),
/* .category = */ /* .category = */
@ -39,13 +40,20 @@ namespace mamba
package.info.version = package_node["version"].as<std::string>(); package.info.version = package_node["version"].as<std::string>();
const auto& hash_node = package_node["hash"]; const auto& hash_node = package_node["hash"];
if (const auto& md5_node = hash_node["md5"]) if (const auto& md5_node = hash_node["md5"])
{
package.info.md5 = md5_node.as<std::string>(); package.info.md5 = md5_node.as<std::string>();
}
if (const auto& sha256_node = hash_node["sha256"]) if (const auto& sha256_node = hash_node["sha256"])
{
package.info.sha256 = sha256_node.as<std::string>(); package.info.sha256 = sha256_node.as<std::string>();
}
if (package.info.sha256.empty() && package.info.md5.empty()) if (package.info.sha256.empty() && package.info.md5.empty())
{
return tl::unexpected(EnvLockFileError::make_error( return tl::unexpected(EnvLockFileError::make_error(
file_parsing_error_code::invalid_data, file_parsing_error_code::invalid_data,
"either package 'package.info.hash.md5' or 'package.info.hash.sha256' must be specified, found none")); "either package 'package.info.hash.md5' or 'package.info.hash.sha256' must be specified, found none"
));
}
package.info.url = package_node["url"].as<std::string>(); package.info.url = package_node["url"].as<std::string>();
const MatchSpec spec{ package.info.url }; const MatchSpec spec{ package.info.url };
@ -59,7 +67,8 @@ namespace mamba
const auto dependency_name = dependency.first.as<std::string>(); const auto dependency_name = dependency.first.as<std::string>();
const auto dependency_constraint = dependency.second.as<std::string>(); const auto dependency_constraint = dependency.second.as<std::string>();
package.info.depends.push_back( package.info.depends.push_back(
fmt::format("{} {}", dependency_name, dependency_constraint)); fmt::format("{} {}", dependency_name, dependency_constraint)
);
} }
if (const auto& constraints_nodes = package_node["constrains"]) if (const auto& constraints_nodes = package_node["constrains"])
@ -69,15 +78,16 @@ namespace mamba
const auto constraint_dep_name = dependency.first.as<std::string>(); const auto constraint_dep_name = dependency.first.as<std::string>();
const auto constraint_expr = dependency.second.as<std::string>(); const auto constraint_expr = dependency.second.as<std::string>();
package.info.constrains.push_back( package.info.constrains.push_back(
fmt::format("{} {}", constraint_dep_name, constraint_expr)); fmt::format("{} {}", constraint_dep_name, constraint_expr)
);
} }
} }
return package; return package;
} }
tl::expected<EnvironmentLockFile::Meta, mamba_error> read_metadata( tl::expected<EnvironmentLockFile::Meta, mamba_error>
const YAML::Node& metadata_node) read_metadata(const YAML::Node& metadata_node)
{ {
EnvironmentLockFile::Meta metadata; EnvironmentLockFile::Meta metadata;
@ -86,25 +96,30 @@ namespace mamba
metadata.platforms.push_back(platform_node.as<std::string>()); metadata.platforms.push_back(platform_node.as<std::string>());
} }
if (metadata.platforms.empty()) if (metadata.platforms.empty())
{
return tl::unexpected(EnvLockFileError::make_error( return tl::unexpected(EnvLockFileError::make_error(
file_parsing_error_code::invalid_data, file_parsing_error_code::invalid_data,
"at least one 'metadata.platform.*' must be specified, found none")); "at least one 'metadata.platform.*' must be specified, found none"
));
}
for (const auto& source_node : metadata_node["sources"]) for (const auto& source_node : metadata_node["sources"])
{ {
metadata.sources.push_back(source_node.as<std::string>()); metadata.sources.push_back(source_node.as<std::string>());
} }
if (metadata.sources.empty()) if (metadata.sources.empty())
{
return tl::unexpected(EnvLockFileError::make_error( return tl::unexpected(EnvLockFileError::make_error(
file_parsing_error_code::invalid_data, file_parsing_error_code::invalid_data,
"at least one 'metadata.source.*' must be specified, found none")); "at least one 'metadata.source.*' must be specified, found none"
));
}
for (const auto& channel_node : metadata_node["channels"]) for (const auto& channel_node : metadata_node["channels"])
{ {
EnvironmentLockFile::Channel channel; EnvironmentLockFile::Channel channel;
channel.url = channel_node["url"].as<std::string>(); channel.url = channel_node["url"].as<std::string>();
channel.used_env_vars channel.used_env_vars = channel_node["used_env_vars"].as<std::vector<std::string>>();
= channel_node["used_env_vars"].as<std::vector<std::string>>();
metadata.channels.push_back(std::move(channel)); metadata.channels.push_back(std::move(channel));
} }
@ -112,23 +127,30 @@ namespace mamba
{ {
const auto& platform_node = node_pair.first; const auto& platform_node = node_pair.first;
const auto& hash_node = node_pair.first; const auto& hash_node = node_pair.first;
metadata.content_hash.emplace(platform_node.as<std::string>(), metadata.content_hash.emplace(
hash_node.as<std::string>()); platform_node.as<std::string>(),
hash_node.as<std::string>()
);
} }
if (metadata.content_hash.empty()) if (metadata.content_hash.empty())
{
return tl::unexpected(EnvLockFileError::make_error( return tl::unexpected(EnvLockFileError::make_error(
file_parsing_error_code::invalid_data, file_parsing_error_code::invalid_data,
"at least one 'metadata.content_hash.*' value must be specified, found none")); "at least one 'metadata.content_hash.*' value must be specified, found none"
));
}
return metadata; return metadata;
} }
tl::expected<EnvironmentLockFile, mamba_error> read_environment_lockfile( tl::expected<EnvironmentLockFile, mamba_error>
const YAML::Node& lockfile_yaml) read_environment_lockfile(const YAML::Node& lockfile_yaml)
{ {
const auto& maybe_metadata = read_metadata(lockfile_yaml["metadata"]); const auto& maybe_metadata = read_metadata(lockfile_yaml["metadata"]);
if (!maybe_metadata) if (!maybe_metadata)
{
return tl::unexpected(maybe_metadata.error()); return tl::unexpected(maybe_metadata.error());
}
auto metadata = maybe_metadata.value(); auto metadata = maybe_metadata.value();
@ -149,11 +171,11 @@ namespace mamba
} }
} }
tl::expected<EnvironmentLockFile, mamba_error> read_environment_lockfile( tl::expected<EnvironmentLockFile, mamba_error>
const fs::u8path& lockfile_location) read_environment_lockfile(const fs::u8path& lockfile_location)
{ {
const auto file_path = fs::absolute( const auto file_path = fs::absolute(lockfile_location); // Having the complete path helps
lockfile_location); // Having the complete path helps with logging and error reports. // with logging and error reports.
try try
{ {
// TODO: add fields validation here (using some schema validation tool) // TODO: add fields validation here (using some schema validation tool)
@ -171,7 +193,9 @@ namespace mamba
fmt::format( fmt::format(
"Failed to read environment lockfile at '{}' : unknown version '{}'", "Failed to read environment lockfile at '{}' : unknown version '{}'",
file_path.string(), file_path.string(),
lockfile_version))); lockfile_version
)
));
} }
} }
} }
@ -182,21 +206,28 @@ namespace mamba
fmt::format( fmt::format(
"YAML parsing error while reading environment lockfile located at '{}' : {}", "YAML parsing error while reading environment lockfile located at '{}' : {}",
file_path.string(), file_path.string(),
err.what()), err.what()
std::type_index{ typeid(err) })); ),
std::type_index{ typeid(err) }
));
} }
catch (...) catch (...)
{ {
return tl::unexpected(EnvLockFileError::make_error( return tl::unexpected(EnvLockFileError::make_error(
file_parsing_error_code::parsing_failure, file_parsing_error_code::parsing_failure,
fmt::format("unknown error while reading environment lockfile located at '{}'", fmt::format(
file_path.string()))); "unknown error while reading environment lockfile located at '{}'",
file_path.string()
)
));
} }
} }
std::vector<PackageInfo> EnvironmentLockFile::get_packages_for(std::string_view category, std::vector<PackageInfo> EnvironmentLockFile::get_packages_for(
std::string_view platform, std::string_view category,
std::string_view manager) const std::string_view platform,
std::string_view manager
) const
{ {
std::vector<PackageInfo> results; std::vector<PackageInfo> results;
@ -209,7 +240,9 @@ namespace mamba
for (const auto& package : packages) for (const auto& package : packages)
{ {
if (package_predicate(package)) if (package_predicate(package))
{
results.push_back(package.info); results.push_back(package.info);
}
} }
return results; return results;

View File

@ -1,4 +1,5 @@
#include "mamba/core/environment.hpp" #include "mamba/core/environment.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#ifdef _WIN32 #ifdef _WIN32
@ -41,9 +42,13 @@ namespace mamba
#else #else
const char* value = std::getenv(key.c_str()); const char* value = std::getenv(key.c_str());
if (value) if (value)
{
return value; return value;
}
else else
{
return {}; return {};
}
#endif #endif
} }
@ -146,8 +151,8 @@ namespace mamba
{ {
std::string_view s(c); std::string_view s(c);
auto pos = s.find("="); auto pos = s.find("=");
m[std::string(s.substr(0, pos))] m[std::string(s.substr(0, pos))] = (pos != s.npos) ? std::string(s.substr(pos + 1))
= (pos != s.npos) ? std::string(s.substr(pos + 1)) : ""; : "";
c = *(environ + i); c = *(environ + i);
} }
#else #else
@ -202,13 +207,16 @@ namespace mamba
std::string maybe_home = env::get("USERPROFILE").value_or(""); std::string maybe_home = env::get("USERPROFILE").value_or("");
if (maybe_home.empty()) if (maybe_home.empty())
{ {
maybe_home maybe_home = concat(
= concat(env::get("HOMEDRIVE").value_or(""), env::get("HOMEPATH").value_or("")); env::get("HOMEDRIVE").value_or(""),
env::get("HOMEPATH").value_or("")
);
} }
if (maybe_home.empty()) if (maybe_home.empty())
{ {
throw std::runtime_error( throw std::runtime_error(
"Cannot determine HOME (checked USERPROFILE, HOMEDRIVE and HOMEPATH env vars)"); "Cannot determine HOME (checked USERPROFILE, HOMEDRIVE and HOMEPATH env vars)"
);
} }
#else #else
std::string maybe_home = env::get("HOME").value_or(""); std::string maybe_home = env::get("HOME").value_or("");

View File

@ -3,12 +3,13 @@
// Distributed under the terms of the BSD 3-Clause License. // Distributed under the terms of the BSD 3-Clause License.
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/environments_manager.hpp"
#include <set> #include <set>
#include <string> #include <string>
#include <vector> #include <vector>
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/environments_manager.hpp"
#include "mamba/core/environment.hpp" #include "mamba/core/environment.hpp"
#include "mamba/core/fsutil.hpp" #include "mamba/core/fsutil.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
@ -50,7 +51,9 @@ namespace mamba
for (auto& l : lines) for (auto& l : lines)
{ {
if (l == final_location_string) if (l == final_location_string)
{
return; return;
}
} }
std::ofstream out = open_ofstream(env_txt_file, std::ios::app); std::ofstream out = open_ofstream(env_txt_file, std::ios::app);
@ -65,7 +68,10 @@ namespace mamba
else else
{ {
throw std::system_error( throw std::system_error(
errno, std::system_category(), "failed to open " + env_txt_file.string()); errno,
std::system_category(),
"failed to open " + env_txt_file.string()
);
} }
} }
} }
@ -149,20 +155,24 @@ namespace mamba
return all_env_paths; return all_env_paths;
} }
std::set<std::string> EnvironmentsManager::clean_environments_txt( std::set<std::string>
const fs::u8path& env_txt_file, const fs::u8path& location) EnvironmentsManager::clean_environments_txt(const fs::u8path& env_txt_file, const fs::u8path& location)
{ {
if (!fs::exists(env_txt_file)) if (!fs::exists(env_txt_file))
{
return {}; return {};
}
std::error_code fsabs_error; std::error_code fsabs_error;
fs::u8path abs_loc = fs::absolute( fs::u8path abs_loc = fs::absolute(location, fsabs_error); // If it fails we just get the
location, fsabs_error); // If it fails we just get the defaultly constructed path. // defaultly constructed path.
if (fsabs_error && !location.empty()) // Ignore cases where we got an empty location. if (fsabs_error && !location.empty()) // Ignore cases where we got an empty location.
{ {
LOG_WARNING << fmt::format("Failed to get absolute path for location '{}' : {}", LOG_WARNING << fmt::format(
location.string(), "Failed to get absolute path for location '{}' : {}",
fsabs_error.message()); location.string(),
fsabs_error.message()
);
} }
std::vector<std::string> lines = read_lines(env_txt_file); std::vector<std::string> lines = read_lines(env_txt_file);

View File

@ -9,7 +9,9 @@ namespace mamba
void maybe_dump_backtrace(mamba_error_code ec) void maybe_dump_backtrace(mamba_error_code ec)
{ {
if (ec == mamba_error_code::internal_failure) if (ec == mamba_error_code::internal_failure)
{
spdlog::dump_backtrace(); spdlog::dump_backtrace();
}
} }
} }

View File

@ -14,8 +14,10 @@ namespace mamba
{ {
const auto result = safe_invoke(handler); const auto result = safe_invoke(handler);
if (!result) if (!result)
{
LOG_ERROR << "main executor close handler failed (ignored): " LOG_ERROR << "main executor close handler failed (ignored): "
<< result.error().what(); << result.error().what();
}
} }
} }
} }

View File

@ -4,17 +4,18 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/fetch.hpp"
#include <string_view> #include <string_view>
#include "spdlog/spdlog.h"
#include "mamba/version.hpp"
#include "mamba/core/fetch.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/thread_utils.hpp" #include "mamba/core/thread_utils.hpp"
#include "mamba/core/util.hpp"
#include "mamba/core/url.hpp" #include "mamba/core/url.hpp"
#include "mamba/core/util.hpp"
#include "mamba/version.hpp"
#include "spdlog/spdlog.h"
#include "progress_bar_impl.hpp" #include "progress_bar_impl.hpp"
@ -65,7 +66,11 @@ namespace mamba
} }
size_t wcb_res = m_write_callback( size_t wcb_res = m_write_callback(
buffer, 1, BUFFER_SIZE - stream->avail_out, m_write_callback_data); buffer,
1,
BUFFER_SIZE - stream->avail_out,
m_write_callback_data
);
if (wcb_res != BUFFER_SIZE - stream->avail_out) if (wcb_res != BUFFER_SIZE - stream->avail_out)
{ {
return size + 1; return size + 1;
@ -163,9 +168,7 @@ namespace mamba
* DownloadTarget implementation * * DownloadTarget implementation *
*********************************/ *********************************/
DownloadTarget::DownloadTarget(const std::string& name, DownloadTarget::DownloadTarget(const std::string& name, const std::string& url, const std::string& filename)
const std::string& url,
const std::string& filename)
: m_name(name) : m_name(name)
, m_filename(filename) , m_filename(filename)
, m_url(unc_url(url)) , m_url(unc_url(url))
@ -279,8 +282,9 @@ namespace mamba
curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, Context::instance().connect_timeout_secs); curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, Context::instance().connect_timeout_secs);
std::string ssl_no_revoke_env std::string ssl_no_revoke_env = std::getenv("MAMBA_SSL_NO_REVOKE")
= std::getenv("MAMBA_SSL_NO_REVOKE") ? std::getenv("MAMBA_SSL_NO_REVOKE") : "0"; ? std::getenv("MAMBA_SSL_NO_REVOKE")
: "0";
if (Context::instance().ssl_no_revoke || ssl_no_revoke_env != "0") if (Context::instance().ssl_no_revoke || ssl_no_revoke_env != "0")
{ {
curl_easy_setopt(handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); curl_easy_setopt(handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
@ -334,8 +338,8 @@ namespace mamba
} }
} }
int curl_debug_callback( int
CURL* /* handle */, curl_infotype type, char* data, size_t size, void* userptr) curl_debug_callback(CURL* /* handle */, curl_infotype type, char* data, size_t size, void* userptr)
{ {
auto* logger = (spdlog::logger*) (userptr); auto* logger = (spdlog::logger*) (userptr);
auto log = Console::hide_secrets(std::string_view(data, size)); auto log = Console::hide_secrets(std::string_view(data, size));
@ -399,8 +403,11 @@ namespace mamba
m_headers = curl_slist_append(m_headers, "Content-Type: application/json"); m_headers = curl_slist_append(m_headers, "Content-Type: application/json");
} }
std::string user_agent std::string user_agent = fmt::format(
= fmt::format("User-Agent: {} {}", Context::instance().user_agent, curl_version()); "User-Agent: {} {}",
Context::instance().user_agent,
curl_version()
);
m_headers = curl_slist_append(m_headers, user_agent.c_str()); m_headers = curl_slist_append(m_headers, user_agent.c_str());
curl_easy_setopt(m_handle, CURLOPT_HTTPHEADER, m_headers); curl_easy_setopt(m_handle, CURLOPT_HTTPHEADER, m_headers);
@ -458,8 +465,7 @@ namespace mamba
init_curl_target(m_url); init_curl_target(m_url);
if (m_has_progress_bar) if (m_has_progress_bar)
{ {
curl_easy_setopt( curl_easy_setopt(m_handle, CURLOPT_XFERINFOFUNCTION, &DownloadTarget::progress_callback);
m_handle, CURLOPT_XFERINFOFUNCTION, &DownloadTarget::progress_callback);
curl_easy_setopt(m_handle, CURLOPT_XFERINFODATA, this); curl_easy_setopt(m_handle, CURLOPT_XFERINFODATA, this);
} }
m_retry_wait_seconds = m_retry_wait_seconds * Context::instance().retry_backoff; m_retry_wait_seconds = m_retry_wait_seconds * Context::instance().retry_backoff;
@ -544,19 +550,25 @@ namespace mamba
return [&](ProgressBarRepr& r) -> void return [&](ProgressBarRepr& r) -> void
{ {
r.current.set_value( r.current.set_value(
fmt::format("{:>7}", to_human_readable_filesize(m_progress_bar.current(), 1))); fmt::format("{:>7}", to_human_readable_filesize(m_progress_bar.current(), 1))
);
std::string total_str; std::string total_str;
if (!m_progress_bar.total() if (!m_progress_bar.total()
|| (m_progress_bar.total() == std::numeric_limits<std::size_t>::max())) || (m_progress_bar.total() == std::numeric_limits<std::size_t>::max()))
{
total_str = "??.?MB"; total_str = "??.?MB";
}
else else
{
total_str = to_human_readable_filesize(m_progress_bar.total(), 1); total_str = to_human_readable_filesize(m_progress_bar.total(), 1);
}
r.total.set_value(fmt::format("{:>7}", total_str)); r.total.set_value(fmt::format("{:>7}", total_str));
auto speed = m_progress_bar.speed(); auto speed = m_progress_bar.speed();
r.speed.set_value( r.speed.set_value(
fmt::format("@ {:>7}/s", speed ? to_human_readable_filesize(speed, 1) : "??.?MB")); fmt::format("@ {:>7}/s", speed ? to_human_readable_filesize(speed, 1) : "??.?MB")
);
r.separator.set_value("/"); r.separator.set_value("/");
}; };
@ -567,32 +579,48 @@ namespace mamba
return m_progress_throttle_time; return m_progress_throttle_time;
} }
void DownloadTarget::set_progress_throttle_time( void DownloadTarget::set_progress_throttle_time(const std::chrono::steady_clock::time_point& time)
const std::chrono::steady_clock::time_point& time)
{ {
m_progress_throttle_time = time; m_progress_throttle_time = time;
} }
int DownloadTarget::progress_callback( int DownloadTarget::progress_callback(
void* f, curl_off_t total_to_download, curl_off_t now_downloaded, curl_off_t, curl_off_t) void* f,
curl_off_t total_to_download,
curl_off_t now_downloaded,
curl_off_t,
curl_off_t
)
{ {
auto* target = static_cast<DownloadTarget*>(f); auto* target = static_cast<DownloadTarget*>(f);
auto now = std::chrono::steady_clock::now(); auto now = std::chrono::steady_clock::now();
if (now - target->progress_throttle_time() < std::chrono::milliseconds(50)) if (now - target->progress_throttle_time() < std::chrono::milliseconds(50))
{
return 0; return 0;
}
else else
{
target->set_progress_throttle_time(now); target->set_progress_throttle_time(now);
}
if (!total_to_download && !target->expected_size()) if (!total_to_download && !target->expected_size())
{
target->m_progress_bar.activate_spinner(); target->m_progress_bar.activate_spinner();
}
else else
{
target->m_progress_bar.deactivate_spinner(); target->m_progress_bar.deactivate_spinner();
}
if (!total_to_download && target->expected_size()) if (!total_to_download && target->expected_size())
{
target->m_progress_bar.update_current(now_downloaded); target->m_progress_bar.update_current(now_downloaded);
}
else else
{
target->m_progress_bar.update_progress(now_downloaded, total_to_download); target->m_progress_bar.update_progress(now_downloaded, total_to_download);
}
target->m_progress_bar.set_speed(target->get_speed()); target->m_progress_bar.set_speed(target->get_speed());
@ -659,7 +687,9 @@ namespace mamba
curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1L); curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(handle, CURLOPT_NOBODY, 1L); curl_easy_setopt(handle, CURLOPT_NOBODY, 1L);
if (curl_easy_perform(handle) == CURLE_OK) if (curl_easy_perform(handle) == CURLE_OK)
{
return true; return true;
}
long response_code; long response_code;
curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &response_code); curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &response_code);
@ -674,7 +704,9 @@ namespace mamba
return curl_easy_perform(handle) == CURLE_OK; return curl_easy_perform(handle) == CURLE_OK;
} }
else else
{
return false; return false;
}
} }
bool DownloadTarget::perform() bool DownloadTarget::perform()
@ -698,9 +730,13 @@ namespace mamba
if (res != CURLE_OK) if (res != CURLE_OK)
{ {
if (m_has_progress_bar) if (m_has_progress_bar)
{
speed = m_progress_bar.avg_speed(); speed = m_progress_bar.avg_speed();
}
else else
{
speed = 0; speed = 0;
}
} }
return speed; return speed;
} }
@ -722,8 +758,8 @@ namespace mamba
} }
LOG_INFO << err.str(); LOG_INFO << err.str();
m_next_retry m_next_retry = std::chrono::steady_clock::now()
= std::chrono::steady_clock::now() + std::chrono::seconds(m_retry_wait_seconds); + std::chrono::seconds(m_retry_wait_seconds);
if (m_has_progress_bar) if (m_has_progress_bar)
{ {
@ -758,8 +794,8 @@ namespace mamba
m_retry_wait_seconds = get_default_retry_timeout(); m_retry_wait_seconds = get_default_retry_timeout();
} }
m_next_retry m_next_retry = std::chrono::steady_clock::now()
= std::chrono::steady_clock::now() + std::chrono::seconds(m_retry_wait_seconds); + std::chrono::seconds(m_retry_wait_seconds);
std::stringstream msg; std::stringstream msg;
msg << "Failed (" << http_status << "), retry in " << m_retry_wait_seconds << "s"; msg << "Failed (" << http_status << "), retry in " << m_retry_wait_seconds << "s";
if (m_has_progress_bar) if (m_has_progress_bar)
@ -789,9 +825,13 @@ namespace mamba
else else
{ {
if (m_has_progress_bar) if (m_has_progress_bar)
{
m_progress_bar.mark_as_completed(); m_progress_bar.mark_as_completed();
}
else else
{
Console::instance().print(name() + " completed"); Console::instance().print(name() + " completed");
}
} }
if (m_has_progress_bar) if (m_has_progress_bar)
@ -828,8 +868,7 @@ namespace mamba
MultiDownloadTarget::MultiDownloadTarget() MultiDownloadTarget::MultiDownloadTarget()
{ {
m_handle = curl_multi_init(); m_handle = curl_multi_init();
curl_multi_setopt( curl_multi_setopt(m_handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, Context::instance().download_threads);
m_handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, Context::instance().download_threads);
} }
MultiDownloadTarget::~MultiDownloadTarget() MultiDownloadTarget::~MultiDownloadTarget()
@ -840,7 +879,9 @@ namespace mamba
void MultiDownloadTarget::add(DownloadTarget* target) void MultiDownloadTarget::add(DownloadTarget* target)
{ {
if (!target) if (!target)
{
return; return;
}
CURLMcode code = curl_multi_add_handle(m_handle, target->handle()); CURLMcode code = curl_multi_add_handle(m_handle, target->handle());
if (code != CURLM_CALL_MULTI_PERFORM) if (code != CURLM_CALL_MULTI_PERFORM)
{ {
@ -902,8 +943,9 @@ namespace mamba
{ {
if (failfast && current_target->ignore_failure() == false) if (failfast && current_target->ignore_failure() == false)
{ {
throw std::runtime_error("Multi-download failed. Reason: " throw std::runtime_error(
+ current_target->get_transfer_msg()); "Multi-download failed. Reason: " + current_target->get_transfer_msg()
);
} }
} }
} }
@ -927,10 +969,14 @@ namespace mamba
} }
if (sort) if (sort)
std::sort(m_targets.begin(), {
m_targets.end(), std::sort(
[](DownloadTarget* a, DownloadTarget* b) -> bool m_targets.begin(),
{ return a->expected_size() > b->expected_size(); }); m_targets.end(),
[](DownloadTarget* a, DownloadTarget* b) -> bool
{ return a->expected_size() > b->expected_size(); }
);
}
LOG_INFO << "Starting to download targets"; LOG_INFO << "Starting to download targets";
@ -983,11 +1029,15 @@ namespace mamba
throw std::runtime_error(curl_multi_strerror(code)); throw std::runtime_error(curl_multi_strerror(code));
} }
if (curl_timeout == 0) // No wait if (curl_timeout == 0)
{ // No wait
continue; continue;
}
if (curl_timeout < 0 || curl_timeout > max_wait_msecs) // Wait no more than 1s if (curl_timeout < 0 || curl_timeout > max_wait_msecs)
{ // Wait no more than 1s
curl_timeout = max_wait_msecs; curl_timeout = max_wait_msecs;
}
int numfds; int numfds;
code = curl_multi_wait(m_handle, NULL, 0, curl_timeout, &numfds); code = curl_multi_wait(m_handle, NULL, 0, curl_timeout, &numfds);
@ -1020,7 +1070,9 @@ namespace mamba
{ {
pbar_manager.terminate(); pbar_manager.terminate();
if (!no_clear_progress_bars) if (!no_clear_progress_bars)
{
pbar_manager.clear_progress_bars(); pbar_manager.clear_progress_bars();
}
} }
return true; return true;

View File

@ -4,11 +4,12 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/history.hpp"
#include <regex> #include <regex>
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/fsutil.hpp" #include "mamba/core/fsutil.hpp"
#include "mamba/core/history.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
namespace mamba namespace mamba
@ -51,7 +52,9 @@ namespace mamba
while (getline(in_file, line)) while (getline(in_file, line))
{ {
if (line.size() == 0) if (line.size() == 0)
{
continue; continue;
}
std::smatch base_match; std::smatch base_match;
if (std::regex_match(line, base_match, head_re)) if (std::regex_match(line, base_match, head_re))
{ {
@ -91,7 +94,9 @@ namespace mamba
{ {
std::size_t colon_idx = line.find_first_of(':'); std::size_t colon_idx = line.find_first_of(':');
if (colon_idx == std::string::npos) if (colon_idx == std::string::npos)
{
return false; return false;
}
std::string key(strip(line.substr(1, colon_idx - 1))); std::string key(strip(line.substr(1, colon_idx - 1)));
std::string value(strip(line.substr(colon_idx + 1))); std::string value(strip(line.substr(colon_idx + 1)));
@ -266,7 +271,9 @@ namespace mamba
const std::vector<std::string>& specs) -> std::string const std::vector<std::string>& specs) -> std::string
{ {
if (specs.empty()) if (specs.empty())
{
return ""; return "";
}
std::stringstream spec_ss; std::stringstream spec_ss;
spec_ss << "# " << action << " specs: ["; spec_ss << "# " << action << " specs: [";
for (auto spec : specs) for (auto spec : specs)

View File

@ -4,24 +4,25 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/link.hpp"
#include <iostream>
#include <regex> #include <regex>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include <iostream>
#include <reproc++/run.hpp>
#include <reproc++/reproc.hpp> #include <reproc++/reproc.hpp>
#include <reproc++/run.hpp>
#include "mamba/core/environment.hpp" #include "mamba/core/environment.hpp"
#include "mamba/core/menuinst.hpp"
#include "mamba/core/link.hpp"
#include "mamba/core/match_spec.hpp" #include "mamba/core/match_spec.hpp"
#include "mamba/core/menuinst.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/transaction_context.hpp" #include "mamba/core/transaction_context.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/core/validate.hpp"
#include "mamba/core/util_os.hpp" #include "mamba/core/util_os.hpp"
#include "mamba/core/validate.hpp"
#if _WIN32 #if _WIN32
#include "../data/conda_exe.hpp" #include "../data/conda_exe.hpp"
@ -46,8 +47,7 @@ namespace mamba
out << " sys.exit(" << p.func << "())\n"; out << " sys.exit(" << p.func << "())\n";
} }
void application_entry_point_template(std::ostream& out, void application_entry_point_template(std::ostream& out, const std::string_view& source_full_path)
const std::string_view& source_full_path)
{ {
out << "# -*- coding: utf-8 -*-\n"; out << "# -*- coding: utf-8 -*-\n";
out << "if __name__ == '__main__':\n"; out << "if __name__ == '__main__':\n";
@ -135,8 +135,10 @@ namespace mamba
} }
// for noarch python packages that have entry points // for noarch python packages that have entry points
auto LinkPackage::create_python_entry_point(const fs::u8path& path, auto LinkPackage::create_python_entry_point(
const python_entry_point_parsed& entry_point) const fs::u8path& path,
const python_entry_point_parsed& entry_point
)
{ {
#ifdef _WIN32 #ifdef _WIN32
// We add -script.py to WIN32, and link the conda.exe launcher which will // We add -script.py to WIN32, and link the conda.exe launcher which will
@ -148,8 +150,7 @@ namespace mamba
#endif #endif
if (fs::exists(script_path)) if (fs::exists(script_path))
{ {
m_clobber_warnings.push_back( m_clobber_warnings.push_back(fs::relative(script_path, m_context->target_prefix).string());
fs::relative(script_path, m_context->target_prefix).string());
fs::remove(script_path); fs::remove(script_path);
} }
std::ofstream out_file = open_ofstream(script_path); std::ofstream out_file = open_ofstream(script_path);
@ -177,8 +178,10 @@ namespace mamba
fs::remove(m_context->target_prefix / script_exe); fs::remove(m_context->target_prefix / script_exe);
} }
std::ofstream conda_exe_f std::ofstream conda_exe_f = open_ofstream(
= open_ofstream(m_context->target_prefix / script_exe, std::ios::binary); m_context->target_prefix / script_exe,
std::ios::binary
);
conda_exe_f.write(reinterpret_cast<char*>(conda_exe), conda_exe_len); conda_exe_f.write(reinterpret_cast<char*>(conda_exe), conda_exe_len);
conda_exe_f.close(); conda_exe_f.close();
make_executable(m_context->target_prefix / script_exe); make_executable(m_context->target_prefix / script_exe);
@ -226,9 +229,11 @@ namespace mamba
#endif #endif
} }
void LinkPackage::create_application_entry_point(const fs::u8path& source_full_path, void LinkPackage::create_application_entry_point(
const fs::u8path& target_full_path, const fs::u8path& source_full_path,
const fs::u8path& python_full_path) const fs::u8path& target_full_path,
const fs::u8path& python_full_path
)
{ {
// source_full_path: where the entry point file points to // source_full_path: where the entry point file points to
// target_full_path: the location of the new entry point file being created // target_full_path: the location of the new entry point file being created
@ -244,8 +249,7 @@ namespace mamba
std::ofstream out_file = open_ofstream(target_full_path); std::ofstream out_file = open_ofstream(target_full_path);
out_file << "!#" << python_full_path.string() << "\n"; out_file << "!#" << python_full_path.string() << "\n";
application_entry_point_template(out_file, application_entry_point_template(out_file, win_path_double_escape(source_full_path.string()));
win_path_double_escape(source_full_path.string()));
out_file.close(); out_file.close();
make_executable(target_full_path); make_executable(target_full_path);
@ -283,9 +287,11 @@ namespace mamba
{ {
std::ifstream msgs = open_ifstream(messages_file); std::ifstream msgs = open_ifstream(messages_file);
std::stringstream res; std::stringstream res;
std::copy(std::istreambuf_iterator<char>(msgs), std::copy(
std::istreambuf_iterator<char>(), std::istreambuf_iterator<char>(msgs),
std::ostreambuf_iterator<char>(res)); std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(res)
);
return res.str(); return res.str();
} }
catch (...) catch (...)
@ -301,11 +307,13 @@ namespace mamba
call the post-link or pre-unlink script and return true / false on success / call the post-link or pre-unlink script and return true / false on success /
failure failure
*/ */
bool run_script(const fs::u8path& prefix, bool run_script(
const PackageInfo& pkg_info, const fs::u8path& prefix,
const std::string& action = "post-link", const PackageInfo& pkg_info,
const std::string& env_prefix = "", const std::string& action = "post-link",
bool activate = false) const std::string& env_prefix = "",
bool activate = false
)
{ {
fs::u8path path; fs::u8path path;
if (on_win) if (on_win)
@ -351,11 +359,13 @@ namespace mamba
if (activate) if (activate)
{ {
script_file = wrap_call(Context::instance().root_prefix, script_file = wrap_call(
prefix, Context::instance().root_prefix,
Context::instance().dev, prefix,
false, Context::instance().dev,
{ "@CALL", path.string() }); false,
{ "@CALL", path.string() }
);
command_args = { comspec.value(), "/d", "/c", script_file->path().string() }; command_args = { comspec.value(), "/d", "/c", script_file->path().string() };
} }
@ -377,11 +387,13 @@ namespace mamba
if (activate) if (activate)
{ {
// std::string caller // std::string caller
script_file = wrap_call(Context::instance().root_prefix.string(), script_file = wrap_call(
prefix, Context::instance().root_prefix.string(),
Context::instance().dev, prefix,
false, Context::instance().dev,
{ ".", path.string() }); false,
{ ".", path.string() }
);
command_args.push_back(shell_path.string()); command_args.push_back(shell_path.string());
command_args.push_back(script_file->path().string()); command_args.push_back(script_file->path().string());
} }
@ -450,9 +462,11 @@ namespace mamba
return true; return true;
} }
UnlinkPackage::UnlinkPackage(const PackageInfo& pkg_info, UnlinkPackage::UnlinkPackage(
const fs::u8path& cache_path, const PackageInfo& pkg_info,
TransactionContext* context) const fs::u8path& cache_path,
TransactionContext* context
)
: m_pkg_info(pkg_info) : m_pkg_info(pkg_info)
, m_cache_path(cache_path) , m_cache_path(cache_path)
, m_specifier(m_pkg_info.str()) , m_specifier(m_pkg_info.str())
@ -469,7 +483,9 @@ namespace mamba
std::error_code err; std::error_code err;
if (remove_or_rename(dst) == 0) if (remove_or_rename(dst) == 0)
{
LOG_DEBUG << "Error when removing file '" << dst.string() << "' will be ignored"; LOG_DEBUG << "Error when removing file '" << dst.string() << "' will be ignored";
}
// TODO what do we do with empty directories? // TODO what do we do with empty directories?
// remove empty parent path // remove empty parent path
@ -478,12 +494,16 @@ namespace mamba
{ {
bool exists = fs::exists(parent_path, err); bool exists = fs::exists(parent_path, err);
if (err) if (err)
{
break; break;
}
if (exists) if (exists)
{ {
bool is_empty = fs::is_empty(parent_path, err); bool is_empty = fs::is_empty(parent_path, err);
if (err) if (err)
{
break; break;
}
if (is_empty) if (is_empty)
{ {
remove_or_rename(parent_path); remove_or_rename(parent_path);
@ -537,9 +557,11 @@ namespace mamba
return lp.execute(); return lp.execute();
} }
LinkPackage::LinkPackage(const PackageInfo& pkg_info, LinkPackage::LinkPackage(
const fs::u8path& cache_path, const PackageInfo& pkg_info,
TransactionContext* context) const fs::u8path& cache_path,
TransactionContext* context
)
: m_pkg_info(pkg_info) : m_pkg_info(pkg_info)
, m_cache_path(cache_path) , m_cache_path(cache_path)
, m_source(cache_path / m_pkg_info.str()) , m_source(cache_path / m_pkg_info.str())
@ -547,8 +569,8 @@ namespace mamba
{ {
} }
std::tuple<std::string, std::string> LinkPackage::link_path(const PathData& path_data, std::tuple<std::string, std::string>
bool noarch_python) LinkPackage::link_path(const PathData& path_data, bool noarch_python)
{ {
std::string subtarget = path_data.path; std::string subtarget = path_data.path;
LOG_TRACE << "linking '" << subtarget << "'"; LOG_TRACE << "linking '" << subtarget << "'";
@ -627,8 +649,8 @@ namespace mamba
buffer = read_contents(src, std::ios::in | std::ios::binary); buffer = read_contents(src, std::ios::in | std::ios::binary);
#ifdef _WIN32 #ifdef _WIN32
auto has_pyzzer_entrypoint auto has_pyzzer_entrypoint = [](const std::string& data)
= [](const std::string& data) { return data.rfind("PK\x05\x06"); }; { return data.rfind("PK\x05\x06"); };
// on win we only replace pyzzer entrypoints apparently // on win we only replace pyzzer entrypoints apparently
auto entry_point = has_pyzzer_entrypoint(buffer); auto entry_point = has_pyzzer_entrypoint(buffer);
@ -642,10 +664,11 @@ namespace mamba
if (entry_point != std::string::npos) if (entry_point != std::string::npos)
{ {
std::string launcher, shebang; std::string launcher, shebang;
pyzzer_entry pyzzer_entry = *reinterpret_cast<const pyzzer_struct*>(
= *reinterpret_cast<const pyzzer_struct*>(buffer.c_str() + entry_point); buffer.c_str() + entry_point
std::size_t arc_pos );
= entry_point - pyzzer_entry.cdr_size - pyzzer_entry.cdr_offset; std::size_t arc_pos = entry_point - pyzzer_entry.cdr_size
- pyzzer_entry.cdr_offset;
if (arc_pos > 0) if (arc_pos > 0)
{ {
@ -670,10 +693,10 @@ namespace mamba
return std::make_tuple(validate::sha256sum(dst), rel_dst.string()); return std::make_tuple(validate::sha256sum(dst), rel_dst.string());
} }
#else #else
std::size_t padding_size std::size_t padding_size = (path_data.prefix_placeholder.size() > new_prefix.size())
= (path_data.prefix_placeholder.size() > new_prefix.size()) ? path_data.prefix_placeholder.size()
? path_data.prefix_placeholder.size() - new_prefix.size() - new_prefix.size()
: 0; : 0;
std::string padding(padding_size, '\0'); std::string padding(padding_size, '\0');
std::size_t pos = buffer.find(path_data.prefix_placeholder); std::size_t pos = buffer.find(path_data.prefix_placeholder);
@ -706,7 +729,9 @@ namespace mamba
std::error_code ec; std::error_code ec;
fs::permissions(dst, fs::status(src).permissions(), ec); fs::permissions(dst, fs::status(src).permissions(), ec);
if (ec) if (ec)
{
LOG_WARNING << "Could not set permissions on [" << dst << "]: " << ec.message(); LOG_WARNING << "Could not set permissions on [" << dst << "]: " << ec.message();
}
#if defined(__APPLE__) #if defined(__APPLE__)
if (binary_changed && m_pkg_info.subdir == "osx-arm64") if (binary_changed && m_pkg_info.subdir == "osx-arm64")
@ -770,18 +795,23 @@ namespace mamba
} }
else else
{ {
throw std::runtime_error(std::string("Path type not implemented: ") throw std::runtime_error(
+ std::to_string(static_cast<int>(path_data.path_type))); std::string("Path type not implemented: ")
+ std::to_string(static_cast<int>(path_data.path_type))
);
} }
return std::make_tuple(path_data.sha256.empty() ? validate::sha256sum(dst) return std::make_tuple(
: path_data.sha256, path_data.sha256.empty() ? validate::sha256sum(dst) : path_data.sha256,
rel_dst.string()); rel_dst.string()
);
} }
std::vector<fs::u8path> LinkPackage::compile_pyc_files(const std::vector<fs::u8path>& py_files) std::vector<fs::u8path> LinkPackage::compile_pyc_files(const std::vector<fs::u8path>& py_files)
{ {
if (py_files.size() == 0) if (py_files.size() == 0)
{
return {}; return {};
}
std::vector<fs::u8path> pyc_files; std::vector<fs::u8path> pyc_files;
for (auto& f : py_files) for (auto& f : py_files)
@ -850,12 +880,11 @@ namespace mamba
for (auto& path : paths_data) for (auto& path : paths_data)
{ {
auto [sha256_in_prefix, final_path] auto [sha256_in_prefix, final_path] = link_path(path, noarch_type == NoarchType::PYTHON);
= link_path(path, noarch_type == NoarchType::PYTHON);
files_record.push_back(final_path); files_record.push_back(final_path);
nlohmann::json json_record nlohmann::json json_record = { { "_path", final_path },
= { { "_path", final_path }, { "sha256_in_prefix", sha256_in_prefix } }; { "sha256_in_prefix", sha256_in_prefix } };
if (!path.sha256.empty()) if (!path.sha256.empty())
{ {
@ -908,8 +937,8 @@ namespace mamba
LOG_TRACE << "Found symlink and target " << files_record[i] LOG_TRACE << "Found symlink and target " << files_record[i]
<< " -> " << files_record[pix]; << " -> " << files_record[pix];
// use already computed value // use already computed value
paths_json["paths"][i]["sha256_in_prefix"] paths_json["paths"][i]["sha256_in_prefix"] = paths_json["paths"][pix]
= paths_json["paths"][pix]["sha256_in_prefix"]; ["sha256_in_prefix"];
found = true; found = true;
break; break;
} }
@ -928,8 +957,9 @@ namespace mamba
if (exists) if (exists)
{ {
paths_json["paths"][i]["sha256_in_prefix"] paths_json["paths"][i]["sha256_in_prefix"] = validate::sha256sum(
= validate::sha256sum(m_context->target_prefix / files_record[i]); m_context->target_prefix / files_record[i]
);
} }
else else
{ {
@ -978,16 +1008,17 @@ namespace mamba
{ {
if (std::regex_match(sub_path_json.path, py_file_re)) if (std::regex_match(sub_path_json.path, py_file_re))
{ {
for_compilation.push_back(get_python_noarch_target_path( for_compilation.push_back(
sub_path_json.path, m_context->site_packages_path)); get_python_noarch_target_path(sub_path_json.path, m_context->site_packages_path)
);
} }
} }
std::vector<fs::u8path> pyc_files = compile_pyc_files(for_compilation); std::vector<fs::u8path> pyc_files = compile_pyc_files(for_compilation);
for (const fs::u8path& pyc_path : pyc_files) for (const fs::u8path& pyc_path : pyc_files)
{ {
out_json["paths_data"]["paths"].push_back( out_json["paths_data"]["paths"].push_back({ { "_path", pyc_path.string() },
{ { "_path", pyc_path.string() }, { "path_type", "pyc_file" } }); { "path_type", "pyc_file" } });
out_json["files"].push_back(pyc_path.string()); out_json["files"].push_back(pyc_path.string());
} }
@ -999,23 +1030,24 @@ namespace mamba
{ {
// install entry points // install entry points
auto entry_point_parsed = parse_entry_point(ep.get<std::string>()); auto entry_point_parsed = parse_entry_point(ep.get<std::string>());
auto entry_point_path auto entry_point_path = get_bin_directory_short_path()
= get_bin_directory_short_path() / entry_point_parsed.command; / entry_point_parsed.command;
LOG_TRACE << "entry point path: " << entry_point_path << std::endl; LOG_TRACE << "entry point path: " << entry_point_path << std::endl;
auto files = create_python_entry_point(entry_point_path, entry_point_parsed); auto files = create_python_entry_point(entry_point_path, entry_point_parsed);
#ifdef _WIN32 #ifdef _WIN32
out_json["paths_data"]["paths"].push_back( out_json["paths_data"]["paths"].push_back(
{ { "_path", files[0] }, { { "_path", files[0] }, { "path_type", "windows_python_entry_point_script" } }
{ "path_type", "windows_python_entry_point_script" } }); );
out_json["paths_data"]["paths"].push_back( out_json["paths_data"]["paths"].push_back(
{ { "_path", files[1] }, { { "_path", files[1] }, { "path_type", "windows_python_entry_point_exe" } }
{ "path_type", "windows_python_entry_point_exe" } }); );
out_json["files"].push_back(files[0]); out_json["files"].push_back(files[0]);
out_json["files"].push_back(files[1]); out_json["files"].push_back(files[1]);
#else #else
out_json["paths_data"]["paths"].push_back( out_json["paths_data"]["paths"].push_back(
{ { "_path", files }, { "path_type", "unix_python_entry_point" } }); { { "_path", files }, { "path_type", "unix_python_entry_point" } }
);
out_json["files"].push_back(files); out_json["files"].push_back(files);
#endif #endif
} }

View File

@ -4,14 +4,15 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/match_spec.hpp"
#include <regex> #include <regex>
#include "mamba/core/match_spec.hpp" #include "mamba/core/channel.hpp"
#include "mamba/core/environment.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/url.hpp" #include "mamba/core/url.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/core/channel.hpp"
#include "mamba/core/environment.hpp"
namespace mamba namespace mamba
{ {
@ -50,8 +51,7 @@ namespace mamba
{ {
std::size_t pm1 = pos - 1; std::size_t pm1 = pos - 1;
char d = s[pm1]; char d = s[pm1];
if (d == '=' || d == '!' || d == '|' || d == ',' || d == '<' || d == '>' if (d == '=' || d == '!' || d == '|' || d == ',' || d == '<' || d == '>' || d == '~')
|| d == '~')
{ {
std::string tmp = s; std::string tmp = s;
replace_all(tmp, " ", ""); replace_all(tmp, " ", "");
@ -215,7 +215,8 @@ namespace mamba
if (version.find("[") != version.npos) if (version.find("[") != version.npos)
{ {
throw std::runtime_error( throw std::runtime_error(
"Invalid match spec: multiple bracket sections not allowed " + spec); "Invalid match spec: multiple bracket sections not allowed " + spec
);
} }
version = std::string(strip(version)); version = std::string(strip(version));
@ -344,8 +345,8 @@ namespace mamba
std::vector<std::string> formatted_brackets; std::vector<std::string> formatted_brackets;
bool version_exact = false; bool version_exact = false;
auto is_complex_relation auto is_complex_relation = [](const std::string& s)
= [](const std::string& s) { return s.find_first_of("><$^|,") != s.npos; }; { return s.find_first_of("><$^|,") != s.npos; };
if (!version.empty()) if (!version.empty())
{ {
@ -415,9 +416,10 @@ namespace mamba
} }
} }
std::vector<std::string> check std::vector<std::string> check = {
= { "build_number", "track_features", "features", "url", "build_number", "track_features", "features", "url",
"md5", "license", "license_family", "fn" }; "md5", "license", "license_family", "fn"
};
if (!url.empty()) if (!url.empty())
{ {

View File

@ -6,8 +6,8 @@
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h>
#include <shlobj.h> #include <shlobj.h>
#include <windows.h>
#endif #endif
namespace mamba namespace mamba
@ -42,13 +42,15 @@ namespace mamba
* icon_path: path to an .ico file * icon_path: path to an .ico file
* icon_index: index for icon * icon_index: index for icon
*/ */
void create_shortcut(const fs::u8path& path, void create_shortcut(
const std::string& description, const fs::u8path& path,
const fs::u8path& filename, const std::string& description,
const std::string& arguments, const fs::u8path& filename,
const fs::u8path& work_dir, const std::string& arguments,
const fs::u8path& icon_path, const fs::u8path& work_dir,
int icon_index) const fs::u8path& icon_path,
int icon_index
)
{ {
IShellLink* pShellLink = nullptr; IShellLink* pShellLink = nullptr;
IPersistFile* pPersistFile = nullptr; IPersistFile* pPersistFile = nullptr;
@ -66,11 +68,13 @@ namespace mamba
{ {
throw std::runtime_error("Could not initialize COM"); throw std::runtime_error("Could not initialize COM");
} }
hres = CoCreateInstance(CLSID_ShellLink, hres = CoCreateInstance(
nullptr, CLSID_ShellLink,
CLSCTX_INPROC_SERVER, nullptr,
IID_IShellLink, CLSCTX_INPROC_SERVER,
(void**) &pShellLink); IID_IShellLink,
(void**) &pShellLink
);
if (FAILED(hres)) if (FAILED(hres))
{ {
throw std::runtime_error("CoCreateInstance failed."); throw std::runtime_error("CoCreateInstance failed.");
@ -79,8 +83,9 @@ namespace mamba
hres = pShellLink->QueryInterface(IID_IPersistFile, (void**) &pPersistFile); hres = pShellLink->QueryInterface(IID_IPersistFile, (void**) &pPersistFile);
if (FAILED(hres)) if (FAILED(hres))
{ {
throw std::runtime_error("QueryInterface(IPersistFile) error 0x" throw std::runtime_error(
+ std::to_string(hres)); "QueryInterface(IPersistFile) error 0x" + std::to_string(hres)
);
} }
hres = pShellLink->SetPath(path.string().c_str()); hres = pShellLink->SetPath(path.string().c_str());
@ -92,8 +97,9 @@ namespace mamba
hres = pShellLink->SetDescription(description.c_str()); hres = pShellLink->SetDescription(description.c_str());
if (FAILED(hres)) if (FAILED(hres))
{ {
throw std::runtime_error("SetDescription() failed, error 0x" throw std::runtime_error(
+ std::to_string(hres)); "SetDescription() failed, error 0x" + std::to_string(hres)
);
} }
if (!arguments.empty()) if (!arguments.empty())
@ -110,8 +116,7 @@ namespace mamba
hres = pShellLink->SetIconLocation(icon_path.string().c_str(), icon_index); hres = pShellLink->SetIconLocation(icon_path.string().c_str(), icon_index);
if (FAILED(hres)) if (FAILED(hres))
{ {
throw std::runtime_error("SetIconLocation() error 0x" throw std::runtime_error("SetIconLocation() error 0x" + std::to_string(hres));
+ std::to_string(hres));
} }
} }
@ -120,16 +125,18 @@ namespace mamba
hres = pShellLink->SetWorkingDirectory(work_dir.string().c_str()); hres = pShellLink->SetWorkingDirectory(work_dir.string().c_str());
if (FAILED(hres)) if (FAILED(hres))
{ {
throw std::runtime_error("SetWorkingDirectory() error 0x" throw std::runtime_error(
+ std::to_string(hres)); "SetWorkingDirectory() error 0x" + std::to_string(hres)
);
} }
} }
hres = pPersistFile->Save(filename.wstring().c_str(), true); hres = pPersistFile->Save(filename.wstring().c_str(), true);
if (FAILED(hres)) if (FAILED(hres))
{ {
throw std::runtime_error(concat( throw std::runtime_error(
"Failed to create shortcut: ", filename.string(), std::to_string(hres))); concat("Failed to create shortcut: ", filename.string(), std::to_string(hres))
);
} }
} }
catch (const std::runtime_error& e) catch (const std::runtime_error& e)
@ -164,8 +171,7 @@ namespace mamba
wchar_t* localAppData; wchar_t* localAppData;
HRESULT hres; HRESULT hres;
hres = SHGetKnownFolderPath( hres = SHGetKnownFolderPath(knownfolders.at(id), KF_FLAG_DONT_VERIFY, nullptr, &localAppData);
knownfolders.at(id), KF_FLAG_DONT_VERIFY, nullptr, &localAppData);
if (FAILED(hres)) if (FAILED(hres))
{ {
@ -261,9 +267,11 @@ namespace mamba
namespace detail namespace detail
{ {
void create_remove_shortcut_impl(const fs::u8path& json_file, void create_remove_shortcut_impl(
TransactionContext* transaction_context, const fs::u8path& json_file,
bool remove) TransactionContext* transaction_context,
bool remove
)
{ {
std::string json_content = mamba::read_contents(json_file); std::string json_content = mamba::read_contents(json_file);
replace_variables(json_content, transaction_context); replace_variables(json_content, transaction_context);
@ -305,9 +313,11 @@ namespace mamba
const fs::u8path env_pyw = target_prefix / "pythonw.exe"; const fs::u8path env_pyw = target_prefix / "pythonw.exe";
const auto cwp_path = root_prefix / "cwp.py"; const auto cwp_path = root_prefix / "cwp.py";
std::vector<std::string> cwp_py_args( std::vector<std::string> cwp_py_args(
{ cwp_path.string(), target_prefix.string(), env_py.string() }); { cwp_path.string(), target_prefix.string(), env_py.string() }
);
std::vector<std::string> cwp_pyw_args( std::vector<std::string> cwp_pyw_args(
{ cwp_path.string(), target_prefix.string(), env_pyw.string() }); { cwp_path.string(), target_prefix.string(), env_pyw.string() }
);
fs::u8path target_dir = win::get_folder("programs") / menu_name; fs::u8path target_dir = win::get_folder("programs") / menu_name;
if (!fs::exists(target_dir)) if (!fs::exists(target_dir))
@ -427,8 +437,7 @@ namespace mamba
workdir = "%HOMEPATH%"; workdir = "%HOMEPATH%";
} }
mamba::win::create_shortcut( mamba::win::create_shortcut(script, full_name, dst, argstring, workdir, iconpath, 0);
script, full_name, dst, argstring, workdir, iconpath, 0);
} }
else else
{ {

View File

@ -10,22 +10,22 @@
#include <map> #include <map>
#include <string> #include <string>
#include <fmt/format.h>
#include <fmt/color.h> #include <fmt/color.h>
#include <fmt/format.h>
#include <fmt/ostream.h> #include <fmt/ostream.h>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h> #include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#endif #endif
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/tasksync.hpp"
#include "mamba/core/thread_utils.hpp" #include "mamba/core/thread_utils.hpp"
#include "mamba/core/url.hpp" #include "mamba/core/url.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/tasksync.hpp"
#include "progress_bar_impl.hpp" #include "progress_bar_impl.hpp"
@ -74,34 +74,46 @@ namespace mamba
m_table.push_back(r); m_table.push_back(r);
} }
void Table::add_rows(const std::string& header, void
const std::vector<std::vector<FormattedString>>& rs) Table::add_rows(const std::string& header, const std::vector<std::vector<FormattedString>>& rs)
{ {
m_table.push_back({ header }); m_table.push_back({ header });
for (auto& r : rs) for (auto& r : rs)
{
m_table.push_back(r); m_table.push_back(r);
}
} }
std::ostream& Table::print(std::ostream& out) std::ostream& Table::print(std::ostream& out)
{ {
if (m_table.size() == 0) if (m_table.size() == 0)
{
return out; return out;
}
std::size_t n_col = m_header.size(); std::size_t n_col = m_header.size();
if (m_align.size() == 0) if (m_align.size() == 0)
{
m_align = std::vector<alignment>(n_col, alignment::left); m_align = std::vector<alignment>(n_col, alignment::left);
}
std::vector<std::size_t> cell_sizes(n_col); std::vector<std::size_t> cell_sizes(n_col);
for (size_t i = 0; i < n_col; ++i) for (size_t i = 0; i < n_col; ++i)
{
cell_sizes[i] = m_header[i].size(); cell_sizes[i] = m_header[i].size();
}
for (size_t i = 0; i < m_table.size(); ++i) for (size_t i = 0; i < m_table.size(); ++i)
{ {
if (m_table[i].size() == 1) if (m_table[i].size() == 1)
{
continue; continue;
}
for (size_t j = 0; j < m_table[i].size(); ++j) for (size_t j = 0; j < m_table[i].size(); ++j)
{
cell_sizes[j] = std::max(cell_sizes[j], m_table[i][j].size()); cell_sizes[j] = std::max(cell_sizes[j], m_table[i][j].size());
}
} }
if (m_padding.empty()) if (m_padding.empty())
@ -118,19 +130,23 @@ namespace mamba
{ {
if (this->m_align[j] == alignment::left) if (this->m_align[j] == alignment::left)
{ {
fmt::print(out, fmt::print(
"{: ^{}}{: <{}}", out,
"", "{: ^{}}{: <{}}",
this->m_padding[j], "",
fmt::styled(row[j].s, row[j].style), this->m_padding[j],
cell_sizes[j]); fmt::styled(row[j].s, row[j].style),
cell_sizes[j]
);
} }
else else
{ {
fmt::print(out, fmt::print(
"{: >{}}", out,
fmt::styled(row[j].s, row[j].style), "{: >{}}",
cell_sizes[j] + m_padding[j]); fmt::styled(row[j].s, row[j].style),
cell_sizes[j] + m_padding[j]
);
} }
} }
}; };
@ -156,7 +172,9 @@ namespace mamba
{ {
// print header // print header
if (i != 0) if (i != 0)
{
out << "\n"; out << "\n";
}
for (int x = 0; x < m_padding[0]; ++x) for (int x = 0; x < m_padding[0]; ++x)
{ {
@ -194,8 +212,12 @@ namespace mamba
std::ostringstream out; std::ostringstream out;
for (const auto& d : data) for (const auto& d : data)
{
if (d.size() > data_max_width) if (d.size() > data_max_width)
{
data_max_width = d.size(); data_max_width = d.size();
}
}
max_width -= max_width % (data_max_width + padding); max_width -= max_width % (data_max_width + padding);
int block_width = padding + data_max_width; int block_width = padding + data_max_width;
@ -237,6 +259,7 @@ namespace mamba
class ConsoleData class ConsoleData
{ {
public: public:
std::mutex m_mutex; std::mutex m_mutex;
std::unique_ptr<ProgressBarManager> p_progress_bar_manager; std::unique_ptr<ProgressBarManager> p_progress_bar_manager;
@ -255,7 +278,8 @@ namespace mamba
{ {
init_progress_bar_manager(ProgressBarMode::multi); init_progress_bar_manager(ProgressBarMode::multi);
MainExecutor::instance().on_close( MainExecutor::instance().on_close(
p_data->tasksync.synchronized([this] { terminate_progress_bar_manager(); })); p_data->tasksync.synchronized([this] { terminate_progress_bar_manager(); })
);
#ifdef _WIN32 #ifdef _WIN32
// initialize ANSI codes on Win terminals // initialize ANSI codes on Win terminals
auto hStdout = GetStdHandle(STD_OUTPUT_HANDLE); auto hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
@ -265,9 +289,11 @@ namespace mamba
Console::~Console() Console::~Console()
{ {
if (!p_data->is_json_print_cancelled if (!p_data->is_json_print_cancelled && !p_data->json_log.is_null()) // Note: we cannot
&& !p_data->json_log.is_null()) // Note: we cannot rely on Context::instance() to still // rely on
// be valid at this point. // Context::instance()
// to still be valid
// at this point.
{ {
this->json_print(); this->json_print();
} }
@ -310,7 +336,9 @@ namespace mamba
{ {
auto& data = instance().p_data; auto& data = instance().p_data;
for (auto& message : data->m_buffer) for (auto& message : data->m_buffer)
{
ostream << message << '\n'; ostream << message << '\n';
}
const std::lock_guard<std::mutex> lock(data->m_mutex); const std::lock_guard<std::mutex> lock(data->m_mutex);
data->m_buffer.clear(); data->m_buffer.clear();
@ -372,9 +400,13 @@ namespace mamba
ProgressProxy Console::add_progress_bar(const std::string& name, size_t expected_total) ProgressProxy Console::add_progress_bar(const std::string& name, size_t expected_total)
{ {
if (Context::instance().no_progress_bars) if (Context::instance().no_progress_bars)
{
return ProgressProxy(); return ProgressProxy();
}
else 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, expected_total);
}
} }
void Console::clear_progress_bars() void Console::clear_progress_bars()
@ -430,7 +462,9 @@ namespace mamba
{ {
nlohmann::json tmp = j.flatten(); nlohmann::json tmp = j.flatten();
for (auto it = tmp.begin(); it != tmp.end(); ++it) for (auto it = tmp.begin(); it != tmp.end(); ++it)
{
p_data->json_log[p_data->json_hier + it.key()] = it.value(); p_data->json_log[p_data->json_hier + it.key()] = it.value();
}
} }
} }
@ -451,9 +485,10 @@ namespace mamba
{ {
nlohmann::json tmp = j.flatten(); nlohmann::json tmp = j.flatten();
for (auto it = tmp.begin(); it != tmp.end(); ++it) for (auto it = tmp.begin(); it != tmp.end(); ++it)
p_data->json_log[p_data->json_hier + '/' + std::to_string(p_data->json_index) {
+ it.key()] p_data->json_log[p_data->json_hier + '/' + std::to_string(p_data->json_index) + it.key()] = it.value(
= it.value(); );
}
p_data->json_index += 1; p_data->json_index += 1;
} }
} }
@ -472,7 +507,9 @@ namespace mamba
void Console::json_up() void Console::json_up()
{ {
if (Context::instance().json && !p_data->json_hier.empty()) if (Context::instance().json && !p_data->json_hier.empty())
{
p_data->json_hier.erase(p_data->json_hier.rfind('/')); p_data->json_hier.erase(p_data->json_hier.rfind('/'));
}
} }
/***************** /*****************
@ -497,7 +534,9 @@ namespace mamba
MessageLogger::~MessageLogger() MessageLogger::~MessageLogger()
{ {
if (!MessageLoggerData::use_buffer) if (!MessageLoggerData::use_buffer)
{
emit(m_stream.str(), m_level); emit(m_stream.str(), m_level);
}
else else
{ {
const std::lock_guard<std::mutex> lock(MessageLoggerData::m_mutex); const std::lock_guard<std::mutex> lock(MessageLoggerData::m_mutex);
@ -513,7 +552,9 @@ namespace mamba
case log_level::critical: case log_level::critical:
SPDLOG_CRITICAL(prepend(str, "", std::string(4, ' ').c_str())); SPDLOG_CRITICAL(prepend(str, "", std::string(4, ' ').c_str()));
if (Context::instance().logging_level != log_level::off) if (Context::instance().logging_level != log_level::off)
{
spdlog::dump_backtrace(); spdlog::dump_backtrace();
}
break; break;
case log_level::err: case log_level::err:
SPDLOG_ERROR(prepend(str, "", std::string(4, ' ').c_str())); SPDLOG_ERROR(prepend(str, "", std::string(4, ' ').c_str()));
@ -553,7 +594,9 @@ namespace mamba
void MessageLogger::print_buffer(std::ostream& /*ostream*/) void MessageLogger::print_buffer(std::ostream& /*ostream*/)
{ {
for (auto& [msg, level] : MessageLoggerData::m_buffer) for (auto& [msg, level] : MessageLoggerData::m_buffer)
{
emit(msg, level); emit(msg, level);
}
spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->flush(); }); spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->flush(); });

View File

@ -4,13 +4,15 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "nlohmann/json.hpp" #include "mamba/core/package_cache.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/package_cache.hpp"
#include "mamba/core/package_handling.hpp" #include "mamba/core/package_handling.hpp"
#include "mamba/core/validate.hpp"
#include "mamba/core/url.hpp" #include "mamba/core/url.hpp"
#include "mamba/core/validate.hpp"
#include "nlohmann/json.hpp"
namespace mamba namespace mamba
{ {
@ -25,9 +27,11 @@ namespace mamba
{ {
LOG_DEBUG << "Attempt to create package cache directory '" << m_path.string() << "'"; LOG_DEBUG << "Attempt to create package cache directory '" << m_path.string() << "'";
bool sudo_safe = path::starts_with_home(m_path); bool sudo_safe = path::starts_with_home(m_path);
path::touch(m_path / PACKAGE_CACHE_MAGIC_FILE, path::touch(
/*mkdir*/ true, m_path / PACKAGE_CACHE_MAGIC_FILE,
sudo_safe); /*mkdir*/ true,
sudo_safe
);
return true; return true;
} }
catch (...) catch (...)
@ -45,7 +49,9 @@ namespace mamba
auto PackageCacheData::is_writable() -> Writable auto PackageCacheData::is_writable() -> Writable
{ {
if (m_writable == Writable::UNKNOWN) if (m_writable == Writable::UNKNOWN)
{
check_writable(); check_writable();
}
return m_writable; return m_writable;
} }
@ -87,7 +93,9 @@ namespace mamba
} }
} }
else else
{
LOG_TRACE << "Cache path does not exists or is not writable"; LOG_TRACE << "Cache path does not exists or is not writable";
}
try try
{ {
@ -145,14 +153,19 @@ namespace mamba
throw std::runtime_error( throw std::runtime_error(
"Could not validate package '" + tarball_path.string() "Could not validate package '" + tarball_path.string()
+ "': md5 and sha256 sum unknown.\n" + "': md5 and sha256 sum unknown.\n"
"Set safety_checks to warn or disabled to override this error."); "Set safety_checks to warn or disabled to override this error."
);
} }
} }
if (valid) if (valid)
{
LOG_TRACE << "Package tarball '" << tarball_path.string() << "' is valid"; LOG_TRACE << "Package tarball '" << tarball_path.string() << "' is valid";
}
else else
{
LOG_WARNING << "Package tarball '" << tarball_path.string() << "' is invalid"; LOG_WARNING << "Package tarball '" << tarball_path.string() << "' is invalid";
}
m_valid_tarballs[pkg] = valid; m_valid_tarballs[pkg] = valid;
} }
@ -206,7 +219,8 @@ namespace mamba
throw std::runtime_error( throw std::runtime_error(
"Could not validate package '" + repodata_record_path.string() "Could not validate package '" + repodata_record_path.string()
+ "': md5 and sha256 sum unknown.\n" + "': md5 and sha256 sum unknown.\n"
"Set safety_checks to warn or disabled to override this error."); "Set safety_checks to warn or disabled to override this error."
);
} }
} }
@ -267,8 +281,7 @@ namespace mamba
{ {
if (!repodata_record["url"].get<std::string>().empty()) if (!repodata_record["url"].get<std::string>().empty())
{ {
if (!compare_cleaned_url(repodata_record["url"].get<std::string>(), if (!compare_cleaned_url(repodata_record["url"].get<std::string>(), s.url))
s.url))
{ {
LOG_WARNING << "Extracted package cache '" << extracted_dir.string() LOG_WARNING << "Extracted package cache '" << extracted_dir.string()
<< "' has invalid url"; << "' has invalid url";
@ -372,8 +385,12 @@ namespace mamba
fs::u8path MultiPackageCache::first_writable_path() fs::u8path MultiPackageCache::first_writable_path()
{ {
for (auto& pc : m_caches) for (auto& pc : m_caches)
{
if (pc.is_writable() == Writable::WRITABLE) if (pc.is_writable() == Writable::WRITABLE)
{
return pc.path(); return pc.path();
}
}
return fs::u8path(); return fs::u8path();
} }
@ -388,14 +405,18 @@ namespace mamba
} }
for (PackageCacheData& c : m_caches) for (PackageCacheData& c : m_caches)
{
if (c.has_valid_tarball(s)) if (c.has_valid_tarball(s))
{ {
m_cached_tarballs[pkg] = c.path(); m_cached_tarballs[pkg] = c.path();
return c.path(); return c.path();
} }
}
if (return_empty) if (return_empty)
{
return fs::u8path(); return fs::u8path();
}
else else
{ {
LOG_ERROR << "Cannot find tarball cache for '" << s.fn << "'"; LOG_ERROR << "Cannot find tarball cache for '" << s.fn << "'";
@ -414,14 +435,18 @@ namespace mamba
} }
for (auto& c : m_caches) for (auto& c : m_caches)
{
if (c.has_valid_extracted_dir(s)) if (c.has_valid_extracted_dir(s))
{ {
m_cached_extracted_dirs[pkg] = c.path(); m_cached_extracted_dirs[pkg] = c.path();
return c.path(); return c.path();
} }
}
if (return_empty) if (return_empty)
{
return fs::u8path(); return fs::u8path();
}
else else
{ {
LOG_ERROR << "Cannot find a valid extracted directory cache for '" << s.fn << "'"; LOG_ERROR << "Cannot find a valid extracted directory cache for '" << s.fn << "'";
@ -433,7 +458,9 @@ namespace mamba
{ {
std::vector<fs::u8path> paths; std::vector<fs::u8path> paths;
for (auto& c : m_caches) for (auto& c : m_caches)
{
paths.push_back(c.path()); paths.push_back(c.path());
}
return paths; return paths;
} }
@ -441,6 +468,8 @@ namespace mamba
void MultiPackageCache::clear_query_cache(const PackageInfo& s) void MultiPackageCache::clear_query_cache(const PackageInfo& s)
{ {
for (auto& c : m_caches) for (auto& c : m_caches)
{
c.clear_query_cache(s); c.clear_query_cache(s);
}
} }
} // namespace mamba } // namespace mamba

View File

@ -5,29 +5,31 @@
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include <archive.h> #include "mamba/core/package_handling.hpp"
#include <archive_entry.h>
#include <zstd.h>
#include <sstream> #include <sstream>
#include <archive.h>
#include <archive_entry.h>
#include <reproc++/run.hpp> #include <reproc++/run.hpp>
#include <zstd.h>
#include "nlohmann/json.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/package_handling.hpp"
#include "mamba/core/package_paths.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/package_paths.hpp"
#include "mamba/core/thread_utils.hpp" #include "mamba/core/thread_utils.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/core/util_os.hpp" #include "mamba/core/util_os.hpp"
#include "mamba/core/validate.hpp" #include "mamba/core/validate.hpp"
#include "nlohmann/json.hpp"
namespace mamba namespace mamba
{ {
class extraction_guard class extraction_guard
{ {
public: public:
explicit extraction_guard(const fs::u8path& file) explicit extraction_guard(const fs::u8path& file)
: m_file(file) : m_file(file)
{ {
@ -55,12 +57,14 @@ namespace mamba
extraction_guard& operator=(extraction_guard&&) = delete; extraction_guard& operator=(extraction_guard&&) = delete;
private: private:
const fs::u8path& m_file; const fs::u8path& m_file;
}; };
class scoped_archive_read : non_copyable_base class scoped_archive_read : non_copyable_base
{ {
public: public:
scoped_archive_read() scoped_archive_read()
: scoped_archive_read(archive_read_new()){}; : scoped_archive_read(archive_read_new()){};
static scoped_archive_read read_disk() static scoped_archive_read read_disk()
@ -79,6 +83,7 @@ namespace mamba
} }
private: private:
explicit scoped_archive_read(archive* a) explicit scoped_archive_read(archive* a)
: m_archive(a) : m_archive(a)
{ {
@ -94,6 +99,7 @@ namespace mamba
class scoped_archive_write : non_copyable_base class scoped_archive_write : non_copyable_base
{ {
public: public:
scoped_archive_write() scoped_archive_write()
: scoped_archive_write(archive_write_new()) : scoped_archive_write(archive_write_new())
{ {
@ -115,6 +121,7 @@ namespace mamba
} }
private: private:
explicit scoped_archive_write(archive* a) explicit scoped_archive_write(archive* a)
: m_archive(a) : m_archive(a)
{ {
@ -130,6 +137,7 @@ namespace mamba
class scoped_archive_entry : non_copyable_base class scoped_archive_entry : non_copyable_base
{ {
public: public:
scoped_archive_entry() scoped_archive_entry()
: m_entry(archive_entry_new()) : m_entry(archive_entry_new())
{ {
@ -150,6 +158,7 @@ namespace mamba
} }
private: private:
archive_entry* m_entry; archive_entry* m_entry;
}; };
@ -184,10 +193,12 @@ namespace mamba
bool path_has_prefix(const fs::u8path& path, const fs::u8path& prefix) bool path_has_prefix(const fs::u8path& path, const fs::u8path& prefix)
{ {
auto pair = std::mismatch(path.std_path().begin(), auto pair = std::mismatch(
path.std_path().end(), path.std_path().begin(),
prefix.std_path().begin(), path.std_path().end(),
prefix.std_path().end()); prefix.std_path().begin(),
prefix.std_path().end()
);
return pair.second == prefix.std_path().end(); return pair.second == prefix.std_path().end();
} }
@ -203,17 +214,21 @@ namespace mamba
int init_order = starts_with(path.filename().string(), "info-"); int init_order = starts_with(path.filename().string(), "info-");
// sort metadata.json first in zip folder // sort metadata.json first in zip folder
if (path.filename().string() == "metadata.json") if (path.filename().string() == "metadata.json")
{
init_order = -1; init_order = -1;
}
return init_order; return init_order;
} }
// Bundle up all files in directory and create destination archive // Bundle up all files in directory and create destination archive
void create_archive(const fs::u8path& directory, void create_archive(
const fs::u8path& destination, const fs::u8path& directory,
compression_algorithm ca, const fs::u8path& destination,
int compression_level, compression_algorithm ca,
int compression_threads, int compression_level,
bool (*filter)(const fs::u8path&)) int compression_threads,
bool (*filter)(const fs::u8path&)
)
{ {
int r; int r;
@ -228,9 +243,11 @@ namespace mamba
archive_write_add_filter_bzip2(a); archive_write_add_filter_bzip2(a);
if (compression_level < 0 || compression_level > 9) if (compression_level < 0 || compression_level > 9)
{
throw std::runtime_error("bzip2 compression level should be between 0 and 9"); throw std::runtime_error("bzip2 compression level should be between 0 and 9");
std::string comp_level }
= std::string("bzip2:compression-level=") + std::to_string(compression_level); std::string comp_level = std::string("bzip2:compression-level=")
+ std::to_string(compression_level);
archive_write_set_options(a, comp_level.c_str()); archive_write_set_options(a, comp_level.c_str());
} }
if (ca == compression_algorithm::zip) if (ca == compression_algorithm::zip)
@ -238,9 +255,11 @@ namespace mamba
archive_write_set_format_zip(a); archive_write_set_format_zip(a);
if (compression_level < 0 || compression_level > 9) if (compression_level < 0 || compression_level > 9)
{
throw std::runtime_error("zip compression level should be between 0 and 9"); throw std::runtime_error("zip compression level should be between 0 and 9");
std::string comp_level }
= std::string("zip:compression-level=") + std::to_string(compression_level); std::string comp_level = std::string("zip:compression-level=")
+ std::to_string(compression_level);
archive_write_set_options(a, comp_level.c_str()); archive_write_set_options(a, comp_level.c_str());
} }
if (ca == compression_algorithm::zstd) if (ca == compression_algorithm::zstd)
@ -250,10 +269,12 @@ namespace mamba
archive_write_add_filter_zstd(a); archive_write_add_filter_zstd(a);
if (compression_level < 1 || compression_level > 22) if (compression_level < 1 || compression_level > 22)
{
throw std::runtime_error("zstd compression level should be between 1 and 22"); throw std::runtime_error("zstd compression level should be between 1 and 22");
}
std::string comp_level std::string comp_level = std::string("zstd:compression-level=")
= std::string("zstd:compression-level=") + std::to_string(compression_level); + std::to_string(compression_level);
int res = archive_write_set_options(a, comp_level.c_str()); int res = archive_write_set_options(a, comp_level.c_str());
if (res != 0) if (res != 0)
@ -263,8 +284,8 @@ namespace mamba
if (compression_threads > 2) if (compression_threads > 2)
{ {
std::string comp_threads_level std::string comp_threads_level = std::string("zstd:threads=")
= std::string("zstd:threads=") + std::to_string(compression_threads); + std::to_string(compression_threads);
res = archive_write_set_options(a, comp_threads_level.c_str()); res = archive_write_set_options(a, comp_threads_level.c_str());
if (res != 0) if (res != 0)
{ {
@ -381,42 +402,50 @@ namespace mamba
} }
// note the info folder must have already been created! // note the info folder must have already been created!
void create_package(const fs::u8path& directory, void create_package(
const fs::u8path& out_file, const fs::u8path& directory,
int compression_level, const fs::u8path& out_file,
int compression_threads) int compression_level,
int compression_threads
)
{ {
fs::u8path out_file_abs = fs::absolute(out_file); fs::u8path out_file_abs = fs::absolute(out_file);
if (ends_with(out_file.string(), ".tar.bz2")) if (ends_with(out_file.string(), ".tar.bz2"))
{ {
create_archive(directory, create_archive(
out_file_abs, directory,
bzip2, out_file_abs,
compression_level, bzip2,
compression_threads, compression_level,
[](const fs::u8path&) { return false; }); compression_threads,
[](const fs::u8path&) { return false; }
);
} }
else if (ends_with(out_file.string(), ".conda")) else if (ends_with(out_file.string(), ".conda"))
{ {
TemporaryDirectory tdir; TemporaryDirectory tdir;
create_archive(directory, create_archive(
tdir.path() / concat("info-", out_file.stem().string(), ".tar.zst"), directory,
zstd, tdir.path() / concat("info-", out_file.stem().string(), ".tar.zst"),
compression_level, zstd,
compression_threads, compression_level,
[](const fs::u8path& p) -> bool { compression_threads,
return p.std_path().begin() != p.std_path().end() [](const fs::u8path& p) -> bool {
&& *p.std_path().begin() != "info"; return p.std_path().begin() != p.std_path().end()
}); && *p.std_path().begin() != "info";
create_archive(directory, }
tdir.path() / concat("pkg-", out_file.stem().string(), ".tar.zst"), );
zstd, create_archive(
compression_level, directory,
compression_threads, tdir.path() / concat("pkg-", out_file.stem().string(), ".tar.zst"),
[](const fs::u8path& p) -> bool { zstd,
return p.std_path().begin() != p.std_path().end() compression_level,
&& *p.std_path().begin() == "info"; compression_threads,
}); [](const fs::u8path& p) -> bool {
return p.std_path().begin() != p.std_path().end()
&& *p.std_path().begin() == "info";
}
);
nlohmann::json pkg_metadata; nlohmann::json pkg_metadata;
pkg_metadata["conda_pkg_format_version"] = 2; pkg_metadata["conda_pkg_format_version"] = 2;
@ -425,12 +454,14 @@ namespace mamba
metadata_file << pkg_metadata; metadata_file << pkg_metadata;
metadata_file.close(); metadata_file.close();
create_archive(tdir.path(), create_archive(
out_file_abs, tdir.path(),
zip, out_file_abs,
0, zip,
compression_threads, 0,
[](const fs::u8path&) { return false; }); compression_threads,
[](const fs::u8path&) { return false; }
);
} }
} }
@ -562,7 +593,8 @@ namespace mamba
if (read < 0) if (read < 0)
{ {
throw std::runtime_error( throw std::runtime_error(
fmt::format("Error reading from archive: {}", archive_error_string(mine->source))); fmt::format("Error reading from archive: {}", archive_error_string(mine->source))
);
} }
return read; return read;
} }
@ -576,9 +608,8 @@ namespace mamba
} }
void extract_conda(const fs::u8path& file, void
const fs::u8path& dest_dir, extract_conda(const fs::u8path& file, const fs::u8path& dest_dir, const std::vector<std::string>& parts)
const std::vector<std::string>& parts)
{ {
scoped_archive_read a; scoped_archive_read a;
archive_read_support_format_zip(a); archive_read_support_format_zip(a);
@ -595,7 +626,9 @@ namespace mamba
{ {
std::size_t pos = name.find_first_of('-'); std::size_t pos = name.find_first_of('-');
if (pos == std::string::npos) if (pos == std::string::npos)
{
return false; return false;
}
std::string part = name.substr(0, pos); std::string part = name.substr(0, pos);
if (std::find(parts.begin(), parts.end(), part) != parts.end()) if (std::find(parts.begin(), parts.end(), part) != parts.end())
{ {
@ -681,9 +714,13 @@ namespace mamba
std::lock_guard<std::mutex> lock(extract_mutex); std::lock_guard<std::mutex> lock(extract_mutex);
if (ends_with(file.string(), ".tar.bz2")) if (ends_with(file.string(), ".tar.bz2"))
{
extract_archive(file, dest); extract_archive(file, dest);
}
else if (ends_with(file.string(), ".conda")) else if (ends_with(file.string(), ".conda"))
{
extract_conda(file, dest); extract_conda(file, dest);
}
else else
{ {
LOG_ERROR << "Unknown package format '" << file.string() << "'"; LOG_ERROR << "Unknown package format '" << file.string() << "'";
@ -703,9 +740,7 @@ namespace mamba
std::vector<std::string> args; std::vector<std::string> args;
if (Context::instance().is_micromamba) if (Context::instance().is_micromamba)
{ {
args = { args = { get_self_exe_path().string(), "package", "extract", file.string(), dest.string() };
get_self_exe_path().string(), "package", "extract", file.string(), dest.string()
};
} }
else else
{ {
@ -715,7 +750,11 @@ namespace mamba
std::string out, err; std::string out, err;
LOG_DEBUG << "Running subprocess extraction '" << join(" ", args) << "'"; LOG_DEBUG << "Running subprocess extraction '" << join(" ", args) << "'";
auto [status, ec] = reproc::run( auto [status, ec] = reproc::run(
args, reproc::options{}, reproc::sink::string(out), reproc::sink::string(err)); args,
reproc::options{},
reproc::sink::string(out),
reproc::sink::string(err)
);
if (ec) if (ec)
{ {
@ -726,10 +765,8 @@ namespace mamba
} }
} }
bool transmute(const fs::u8path& pkg_file, bool
const fs::u8path& target, transmute(const fs::u8path& pkg_file, const fs::u8path& target, int compression_level, int compression_threads)
int compression_level,
int compression_threads)
{ {
TemporaryDirectory extract_dir; TemporaryDirectory extract_dir;

View File

@ -4,11 +4,12 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/package_info.hpp"
#include <functional> #include <functional>
#include <map> #include <map>
#include <tuple> #include <tuple>
#include "mamba/core/package_info.hpp"
#include "mamba/core/channel.hpp" #include "mamba/core/channel.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
@ -20,15 +21,14 @@ namespace mamba
std::string get_package_info_field(const PackageInfo&, T PackageInfo::*field); std::string get_package_info_field(const PackageInfo&, T PackageInfo::*field);
template <> template <>
std::string get_package_info_field<std::string>(const PackageInfo& pkg, std::string
std::string PackageInfo::*field) get_package_info_field<std::string>(const PackageInfo& pkg, std::string PackageInfo::*field)
{ {
return pkg.*field; return pkg.*field;
} }
template <> template <>
std::string get_package_info_field<size_t>(const PackageInfo& pkg, std::string get_package_info_field<size_t>(const PackageInfo& pkg, size_t PackageInfo::*field)
size_t PackageInfo::*field)
{ {
return std::to_string(pkg.*field); return std::to_string(pkg.*field);
} }
@ -102,7 +102,9 @@ namespace mamba
version = pool_id2str(pool, s->evr); version = pool_id2str(pool, s->evr);
str = solvable_lookup_str(s, SOLVABLE_BUILDFLAVOR); str = solvable_lookup_str(s, SOLVABLE_BUILDFLAVOR);
if (str) if (str)
{
build_string = str; build_string = str;
}
str = solvable_lookup_str(s, SOLVABLE_BUILDVERSION); str = solvable_lookup_str(s, SOLVABLE_BUILDVERSION);
if (str) if (str)
{ {
@ -135,22 +137,32 @@ namespace mamba
fn = check_char(solvable_lookup_str(s, SOLVABLE_MEDIAFILE)); fn = check_char(solvable_lookup_str(s, SOLVABLE_MEDIAFILE));
str = check_char(solvable_lookup_str(s, SOLVABLE_LICENSE)); str = check_char(solvable_lookup_str(s, SOLVABLE_LICENSE));
if (str) if (str)
{
license = str; license = str;
}
size = solvable_lookup_num(s, SOLVABLE_DOWNLOADSIZE, 0); size = solvable_lookup_num(s, SOLVABLE_DOWNLOADSIZE, 0);
timestamp = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0); timestamp = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
str = solvable_lookup_checksum(s, SOLVABLE_PKGID, &check_type); str = solvable_lookup_checksum(s, SOLVABLE_PKGID, &check_type);
if (str) if (str)
{
md5 = str; md5 = str;
}
str = solvable_lookup_checksum(s, SOLVABLE_CHECKSUM, &check_type); str = solvable_lookup_checksum(s, SOLVABLE_CHECKSUM, &check_type);
if (str) if (str)
{
sha256 = str; sha256 = str;
}
signatures = check_char(solvable_lookup_str(s, SIGNATURE_DATA)); signatures = check_char(solvable_lookup_str(s, SIGNATURE_DATA));
if (signatures.empty()) if (signatures.empty())
{
signatures = "{}"; signatures = "{}";
}
queue_init(&q); queue_init(&q);
if (!solvable_lookup_deparray(s, SOLVABLE_REQUIRES, &q, -1)) if (!solvable_lookup_deparray(s, SOLVABLE_REQUIRES, &q, -1))
{
defaulted_keys.insert("depends"); defaulted_keys.insert("depends");
}
depends.resize(q.count); depends.resize(q.count);
for (int i = 0; i < q.count; ++i) for (int i = 0; i < q.count; ++i)
{ {
@ -158,7 +170,9 @@ namespace mamba
} }
queue_empty(&q); queue_empty(&q);
if (!solvable_lookup_deparray(s, SOLVABLE_CONSTRAINS, &q, -1)) if (!solvable_lookup_deparray(s, SOLVABLE_CONSTRAINS, &q, -1))
{
defaulted_keys.insert("constrains"); defaulted_keys.insert("constrains");
}
constrains.resize(q.count); constrains.resize(q.count);
for (int i = 0; i < q.count; ++i) for (int i = 0; i < q.count; ++i)
{ {
@ -185,14 +199,18 @@ namespace mamba
solvable_lookup_idarray(s, extra_keys_id, &q); solvable_lookup_idarray(s, extra_keys_id, &q);
std::vector<std::string> extra_keys; std::vector<std::string> extra_keys;
for (int i = 0; i < q.count; ++i) for (int i = 0; i < q.count; ++i)
{
extra_keys.push_back(pool_dep2str(pool, q.elements[i])); extra_keys.push_back(pool_dep2str(pool, q.elements[i]));
}
// Get extra signed values // Get extra signed values
queue_empty(&q); queue_empty(&q);
solvable_lookup_idarray(s, extra_values_id, &q); solvable_lookup_idarray(s, extra_values_id, &q);
std::vector<std::string> extra_values; std::vector<std::string> extra_values;
for (int i = 0; i < q.count; ++i) for (int i = 0; i < q.count; ++i)
{
extra_values.push_back(pool_dep2str(pool, q.elements[i])); extra_values.push_back(pool_dep2str(pool, q.elements[i]));
}
// Build a JSON string for extra signed metadata // Build a JSON string for extra signed metadata
if (!extra_keys.empty() && (extra_keys.size() == extra_values.size())) if (!extra_keys.empty() && (extra_keys.size() == extra_values.size()))
@ -206,7 +224,9 @@ namespace mamba
} }
} }
else else
{
extra_metadata = "{}"; extra_metadata = "{}";
}
queue_free(&q); queue_free(&q);
} }
@ -268,10 +288,7 @@ namespace mamba
{ {
} }
PackageInfo::PackageInfo(const std::string& n, PackageInfo::PackageInfo(const std::string& n, const std::string& v, const std::string b, std::size_t bn)
const std::string& v,
const std::string b,
std::size_t bn)
: name(n) : name(n)
, version(v) , version(v)
, build_string(b) , build_string(b)
@ -279,30 +296,32 @@ namespace mamba
{ {
} }
bool PackageInfo::operator==(PackageInfo const& other) const bool PackageInfo::operator==(const PackageInfo& other) const
{ {
auto attrs = [](PackageInfo const& p) auto attrs = [](const PackageInfo& p)
{ {
return std::tie(p.name, return std::tie(
p.version, p.name,
p.build_string, p.version,
p.noarch, p.build_string,
p.build_number, p.noarch,
p.channel, p.build_number,
p.url, p.channel,
p.subdir, p.url,
p.fn, p.subdir,
p.license, p.fn,
p.size, p.license,
p.timestamp, p.size,
p.md5, p.timestamp,
p.sha256, p.md5,
p.track_features, p.sha256,
p.depends, p.track_features,
p.constrains, p.depends,
p.signatures, p.constrains,
p.extra_metadata, p.signatures,
p.defaulted_keys); p.extra_metadata,
p.defaulted_keys
);
}; };
return attrs(*this) == attrs(other); return attrs(*this) == attrs(other);
} }
@ -371,7 +390,9 @@ namespace mamba
if (depends.empty()) if (depends.empty())
{ {
if (defaulted_keys.find("depends") == defaulted_keys.end()) if (defaulted_keys.find("depends") == defaulted_keys.end())
{
j["depends"] = nlohmann::json::array(); j["depends"] = nlohmann::json::array();
}
} }
else else
{ {
@ -380,7 +401,9 @@ namespace mamba
if (constrains.empty()) if (constrains.empty())
{ {
if (defaulted_keys.find("constrains") == defaulted_keys.end()) if (defaulted_keys.find("constrains") == defaulted_keys.end())
{
j["constrains"] = nlohmann::json::array(); j["constrains"] = nlohmann::json::array();
}
} }
else else
{ {

View File

@ -4,11 +4,12 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/package_paths.hpp"
#include <map> #include <map>
#include <set> #include <set>
#include <string> #include <string>
#include "mamba/core/package_paths.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
namespace mamba namespace mamba

View File

@ -4,12 +4,13 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/output.hpp"
#include "mamba/core/pinning.hpp" #include "mamba/core/pinning.hpp"
#include "mamba/core/util.hpp"
#include <fstream> #include <fstream>
#include "mamba/core/output.hpp"
#include "mamba/core/util.hpp"
namespace mamba namespace mamba
{ {

View File

@ -4,16 +4,17 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/pool.hpp"
#include <list> #include <list>
#include <solv/pool.h>
#include <solv/solver.h>
#include <solv/selection.h>
#include <solv/evr.h> #include <solv/evr.h>
#include <solv/pool.h>
#include <solv/selection.h>
#include <solv/solver.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/queue.hpp" #include "mamba/core/queue.hpp"
@ -80,7 +81,7 @@ namespace mamba
return m_data->pool.get(); return m_data->pool.get();
} }
Pool const* MPool::pool() const const Pool* MPool::pool() const
{ {
return m_data->pool.get(); return m_data->pool.get();
} }
@ -108,7 +109,7 @@ namespace mamba
return pool(); return pool();
} }
MPool::operator Pool const*() const MPool::operator const Pool*() const
{ {
return pool(); return pool();
} }
@ -121,14 +122,16 @@ namespace mamba
if (sorted) if (sorted)
{ {
std::sort(solvables.begin(), std::sort(
solvables.end(), solvables.begin(),
[this](Id a, Id b) solvables.end(),
{ [this](Id a, Id b)
Solvable* sa = pool_id2solvable(pool(), a); {
Solvable* sb = pool_id2solvable(pool(), b); Solvable* sa = pool_id2solvable(pool(), a);
return (pool_evrcmp(this->pool(), sa->evr, sb->evr, EVRCMP_COMPARE) > 0); Solvable* sb = pool_id2solvable(pool(), b);
}); return (pool_evrcmp(this->pool(), sa->evr, sb->evr, EVRCMP_COMPARE) > 0);
}
);
} }
return solvables.as<std::vector>(); return solvables.as<std::vector>();
} }
@ -137,7 +140,9 @@ namespace mamba
{ {
Id id = pool_conda_matchspec(pool(), ms.c_str()); Id id = pool_conda_matchspec(pool(), ms.c_str());
if (!id) if (!id)
{
throw std::runtime_error("libsolv error: could not create matchspec from string"); throw std::runtime_error("libsolv error: could not create matchspec from string");
}
return id; return id;
} }

View File

@ -9,10 +9,9 @@ extern "C"
#include <solv/transaction.h> #include <solv/transaction.h>
} }
#include "mamba/core/prefix_data.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/pool.hpp" #include "mamba/core/pool.hpp"
#include "mamba/core/prefix_data.hpp"
#include "mamba/core/queue.hpp" #include "mamba/core/queue.hpp"
#include "mamba/core/repo.hpp" #include "mamba/core/repo.hpp"
@ -26,14 +25,15 @@ namespace mamba
} }
catch (std::exception& e) catch (std::exception& e)
{ {
return tl::make_unexpected( return tl::make_unexpected(mamba_error(e.what(), mamba_error_code::prefix_data_not_loaded)
mamba_error(e.what(), mamba_error_code::prefix_data_not_loaded)); );
} }
catch (...) catch (...)
{ {
return tl::make_unexpected( return tl::make_unexpected(mamba_error(
mamba_error("Unknown error when trying to load prefix data " + prefix_path.string(), "Unknown error when trying to load prefix data " + prefix_path.string(),
mamba_error_code::unknown)); mamba_error_code::unknown
));
} }
} }
@ -119,7 +119,8 @@ namespace mamba
} }
default: default:
throw std::runtime_error( throw std::runtime_error(
"Package not found in prefix records or other unexpected condition"); "Package not found in prefix records or other unexpected condition"
);
} }
} }
return result; return result;

View File

@ -1,4 +1,5 @@
#include "mamba/core/progress_bar.hpp" #include "mamba/core/progress_bar.hpp"
#include "progress_bar_impl.hpp" #include "progress_bar_impl.hpp"
namespace mamba namespace mamba

File diff suppressed because it is too large Load Diff

View File

@ -7,16 +7,16 @@
#ifndef MAMBA_CORE_PROGRESS_BAR_IMPL_HPP #ifndef MAMBA_CORE_PROGRESS_BAR_IMPL_HPP
#define MAMBA_CORE_PROGRESS_BAR_IMPL_HPP #define MAMBA_CORE_PROGRESS_BAR_IMPL_HPP
#include <iosfwd>
#include <mutex>
#include <atomic> #include <atomic>
#include <iosfwd>
#include <map>
#include <mutex>
#include <set> #include <set>
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#include <map>
#include <spdlog/spdlog.h>
#include <fmt/color.h> #include <fmt/color.h>
#include <spdlog/spdlog.h>
#include "mamba/core/progress_bar.hpp" #include "mamba/core/progress_bar.hpp"
@ -44,9 +44,9 @@ namespace mamba
class Chrono class Chrono
{ {
public: public:
using duration_t = std::chrono::milliseconds; using duration_t = std::chrono::milliseconds;
using time_point_t using time_point_t = std::chrono::time_point<std::chrono::high_resolution_clock, duration_t>;
= std::chrono::time_point<std::chrono::high_resolution_clock, duration_t>;
Chrono() = default; Chrono() = default;
@ -75,6 +75,7 @@ namespace mamba
std::unique_lock<std::mutex> chrono_lock(); std::unique_lock<std::mutex> chrono_lock();
private: private:
time_point_t m_start; time_point_t m_start;
duration_t m_elapsed_ns = duration_t::zero(); duration_t m_elapsed_ns = duration_t::zero();
ChronoState m_state = ChronoState::unset; ChronoState m_state = ChronoState::unset;
@ -83,12 +84,14 @@ namespace mamba
void compute_elapsed(); void compute_elapsed();
protected: protected:
static time_point_t now(); static time_point_t now();
}; };
class FieldRepr class FieldRepr
{ {
public: public:
bool active() const; bool active() const;
bool defined() const; bool defined() const;
operator bool() const; operator bool() const;
@ -109,6 +112,7 @@ namespace mamba
FieldRepr& resize(std::size_t size); FieldRepr& resize(std::size_t size);
private: private:
std::string m_value = ""; std::string m_value = "";
std::size_t m_width = 0; std::size_t m_width = 0;
std::string m_format = ""; std::string m_format = "";
@ -123,6 +127,7 @@ namespace mamba
class ProgressBarRepr class ProgressBarRepr
{ {
public: public:
ProgressBarRepr(); ProgressBarRepr();
ProgressBarRepr(ProgressBar* pbar); ProgressBarRepr(ProgressBar* pbar);
@ -136,7 +141,7 @@ namespace mamba
ProgressBarRepr& set_width(std::size_t width); ProgressBarRepr& set_width(std::size_t width);
std::size_t width() const; std::size_t width() const;
fmt::text_style const& style() const; const fmt::text_style& style() const;
void clear_style(); void clear_style();
void reset_style(); void reset_style();
@ -145,6 +150,7 @@ namespace mamba
const ProgressBar& progress_bar() const; const ProgressBar& progress_bar() const;
private: private:
fmt::text_style m_style_none; fmt::text_style m_style_none;
fmt::text_style m_style_downloaded; fmt::text_style m_style_downloaded;
fmt::text_style m_style_extracted; fmt::text_style m_style_extracted;
@ -170,6 +176,7 @@ namespace mamba
class ProgressBarManager : public Chrono class ProgressBarManager : public Chrono
{ {
public: public:
virtual ~ProgressBarManager(); virtual ~ProgressBarManager();
ProgressBarManager(const ProgressBarManager&) = delete; ProgressBarManager(const ProgressBarManager&) = delete;
@ -177,17 +184,17 @@ namespace mamba
ProgressBarManager(ProgressBarManager&&) = delete; ProgressBarManager(ProgressBarManager&&) = delete;
ProgressBarManager& operator=(ProgressBarManager&&) = delete; ProgressBarManager& operator=(ProgressBarManager&&) = delete;
virtual ProgressProxy add_progress_bar(const std::string& name, size_t expected_total = 0) virtual ProgressProxy add_progress_bar(const std::string& name, size_t expected_total = 0) = 0;
= 0;
virtual void clear_progress_bars(); virtual void clear_progress_bars();
virtual void add_label(const std::string& label, const ProgressProxy& progress_bar); virtual void add_label(const std::string& label, const ProgressProxy& progress_bar);
void watch_print(const duration_t& period = std::chrono::milliseconds(100)); void watch_print(const duration_t& period = std::chrono::milliseconds(100));
virtual std::size_t print(std::ostream& os, virtual std::size_t print(
std::size_t width = 0, std::ostream& os,
std::size_t max_lines = std::numeric_limits<std::size_t>::max(), std::size_t width = 0,
bool with_endl = true) std::size_t max_lines = std::numeric_limits<std::size_t>::max(),
= 0; bool with_endl = true
) = 0;
void start(); void start();
void terminate(); void terminate();
@ -201,6 +208,7 @@ namespace mamba
void deactivate_sorting(); void deactivate_sorting();
protected: protected:
using progress_bar_ptr = std::unique_ptr<ProgressBar>; using progress_bar_ptr = std::unique_ptr<ProgressBar>;
ProgressBarManager() = default; ProgressBarManager() = default;
@ -240,27 +248,30 @@ namespace mamba
class MultiBarManager : public ProgressBarManager class MultiBarManager : public ProgressBarManager
{ {
public: public:
MultiBarManager(); MultiBarManager();
MultiBarManager(std::size_t width); MultiBarManager(std::size_t width);
virtual ~MultiBarManager() = default; virtual ~MultiBarManager() = default;
ProgressProxy add_progress_bar(const std::string& name, size_t expected_total) override; ProgressProxy add_progress_bar(const std::string& name, size_t expected_total) override;
std::size_t print(std::ostream& os, std::size_t print(
std::size_t width = 0, std::ostream& os,
std::size_t max_lines = std::numeric_limits<std::size_t>::max(), std::size_t width = 0,
bool with_endl = true) override; std::size_t max_lines = std::numeric_limits<std::size_t>::max(),
bool with_endl = true
) override;
}; };
class AggregatedBarManager : public ProgressBarManager class AggregatedBarManager : public ProgressBarManager
{ {
public: public:
AggregatedBarManager(); AggregatedBarManager();
AggregatedBarManager(std::size_t width); AggregatedBarManager(std::size_t width);
virtual ~AggregatedBarManager() = default; virtual ~AggregatedBarManager() = default;
ProgressProxy add_progress_bar(const std::string& name, ProgressProxy add_progress_bar(const std::string& name, std::size_t expected_total) override;
std::size_t expected_total) override;
void update_download_bar(std::size_t current_diff); void update_download_bar(std::size_t current_diff);
void update_extract_bar(); void update_extract_bar();
@ -273,12 +284,15 @@ namespace mamba
ProgressBar* aggregated_bar(const std::string& label); ProgressBar* aggregated_bar(const std::string& label);
std::size_t print(std::ostream& os, std::size_t print(
std::size_t width = 0, std::ostream& os,
std::size_t max_lines = std::numeric_limits<std::size_t>::max(), std::size_t width = 0,
bool with_endl = true) override; std::size_t max_lines = std::numeric_limits<std::size_t>::max(),
bool with_endl = true
) override;
private: private:
std::map<std::string, progress_bar_ptr> m_aggregated_bars; std::map<std::string, progress_bar_ptr> m_aggregated_bars;
bool m_print_sub_bars = false; bool m_print_sub_bars = false;
@ -290,6 +304,7 @@ namespace mamba
class ProgressBar : public Chrono class ProgressBar : public Chrono
{ {
public: public:
virtual ~ProgressBar(); virtual ~ProgressBar();
ProgressBar(const ProgressBar&) = delete; ProgressBar(const ProgressBar&) = delete;
@ -315,15 +330,15 @@ namespace mamba
ProgressBar& activate_spinner(); ProgressBar& activate_spinner();
ProgressBar& deactivate_spinner(); ProgressBar& deactivate_spinner();
ProgressBar& mark_as_completed(const std::chrono::milliseconds& delay ProgressBar&
= std::chrono::milliseconds::zero()); mark_as_completed(const std::chrono::milliseconds& delay = std::chrono::milliseconds::zero());
std::size_t current() const; std::size_t current() const;
std::size_t in_progress() const; std::size_t in_progress() const;
std::size_t total() const; std::size_t total() const;
std::size_t speed() const; std::size_t speed() const;
std::size_t avg_speed(const std::chrono::milliseconds& ref_duration std::size_t
= std::chrono::milliseconds::max()); avg_speed(const std::chrono::milliseconds& ref_duration = std::chrono::milliseconds::max());
double progress() const; double progress() const;
bool completed() const; bool completed() const;
bool is_spinner() const; bool is_spinner() const;
@ -347,6 +362,7 @@ namespace mamba
int width() const; int width() const;
protected: protected:
ProgressBar(const std::string& prefix, std::size_t total, int width = 0); ProgressBar(const std::string& prefix, std::size_t total, int width = 0);
double m_progress = 0.; double m_progress = 0.;
@ -380,6 +396,7 @@ namespace mamba
class DefaultProgressBar : public ProgressBar class DefaultProgressBar : public ProgressBar
{ {
public: public:
DefaultProgressBar(const std::string& prefix, std::size_t total, int width = 0); DefaultProgressBar(const std::string& prefix, std::size_t total, int width = 0);
virtual ~DefaultProgressBar() = default; virtual ~DefaultProgressBar() = default;
@ -389,10 +406,13 @@ namespace mamba
class HiddenProgressBar : public ProgressBar class HiddenProgressBar : public ProgressBar
{ {
public: public:
HiddenProgressBar(const std::string& prefix,
AggregatedBarManager* manager, HiddenProgressBar(
std::size_t total, const std::string& prefix,
int width = 0); AggregatedBarManager* manager,
std::size_t total,
int width = 0
);
virtual ~HiddenProgressBar() = default; virtual ~HiddenProgressBar() = default;
void print(std::ostream& stream, std::size_t width = 0, bool with_endl = true) override; void print(std::ostream& stream, std::size_t width = 0, bool with_endl = true) override;

View File

@ -4,33 +4,36 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/query.hpp"
#include <iostream> #include <iostream>
#include <stack> #include <stack>
#include <spdlog/spdlog.h>
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include <fmt/color.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <fmt/ostream.h> #include <fmt/ostream.h>
#include <fmt/color.h>
#include <solv/evr.h> #include <solv/evr.h>
#include <spdlog/spdlog.h>
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/query.hpp"
#include "mamba/core/match_spec.hpp" #include "mamba/core/match_spec.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/package_info.hpp" #include "mamba/core/package_info.hpp"
#include "mamba/core/queue.hpp" #include "mamba/core/queue.hpp"
#include "mamba/core/util.hpp"
#include "mamba/core/url.hpp" #include "mamba/core/url.hpp"
#include "mamba/core/util.hpp"
namespace mamba namespace mamba
{ {
void walk_graph(query_result::dependency_graph& dep_graph, void walk_graph(
query_result::dependency_graph::node_id parent, query_result::dependency_graph& dep_graph,
Solvable* s, query_result::dependency_graph::node_id parent,
std::map<Solvable*, size_t>& visited, Solvable* s,
std::map<std::string, size_t>& not_found, std::map<Solvable*, size_t>& visited,
int depth = -1) std::map<std::string, size_t>& not_found,
int depth = -1
)
{ {
if (depth == 0) if (depth == 0)
{ {
@ -82,8 +85,9 @@ namespace mamba
auto it = not_found.find(name); auto it = not_found.find(name);
if (it == not_found.end()) if (it == not_found.end())
{ {
auto dep_id auto dep_id = dep_graph.add_node(
= dep_graph.add_node(PackageInfo(concat(name, " >>> NOT FOUND <<<"))); PackageInfo(concat(name, " >>> NOT FOUND <<<"))
);
dep_graph.add_edge(parent, dep_id); dep_graph.add_edge(parent, dep_id);
not_found.insert(std::make_pair(name, dep_id)); not_found.insert(std::make_pair(name, dep_id));
} }
@ -98,10 +102,12 @@ namespace mamba
} }
} }
void reverse_walk_graph(query_result::dependency_graph& dep_graph, void reverse_walk_graph(
query_result::dependency_graph::node_id parent, query_result::dependency_graph& dep_graph,
Solvable* s, query_result::dependency_graph::node_id parent,
std::map<Solvable*, size_t>& visited) Solvable* s,
std::map<Solvable*, size_t>& visited
)
{ {
if (s) if (s)
{ {
@ -214,16 +220,18 @@ namespace mamba
query_result::dependency_graph g; query_result::dependency_graph g;
Pool* pool = m_pool.get(); Pool* pool = m_pool.get();
std::sort(solvables.begin(), std::sort(
solvables.end(), solvables.begin(),
[pool](Id a, Id b) solvables.end(),
{ [pool](Id a, Id b)
Solvable* sa; {
Solvable* sb; Solvable* sa;
sa = pool_id2solvable(pool, a); Solvable* sb;
sb = pool_id2solvable(pool, b); sa = pool_id2solvable(pool, a);
return (pool_evrcmp(pool, sa->evr, sb->evr, EVRCMP_COMPARE) > 0); sb = pool_id2solvable(pool, b);
}); return (pool_evrcmp(pool, sa->evr, sb->evr, EVRCMP_COMPARE) > 0);
}
);
for (auto& el : solvables) for (auto& el : solvables)
{ {
@ -322,9 +330,7 @@ namespace mamba
* query_result implementation * * query_result implementation *
*******************************/ *******************************/
query_result::query_result(QueryType type, query_result::query_result(QueryType type, const std::string& query, dependency_graph&& dep_graph)
const std::string& query,
dependency_graph&& dep_graph)
: m_type(type) : m_type(type)
, m_query(query) , m_query(query)
, m_dep_graph(std::move(dep_graph)) , m_dep_graph(std::move(dep_graph))
@ -347,22 +353,25 @@ namespace mamba
{ {
package_view_list tmp(rhs.m_pkg_view_list.size()); package_view_list tmp(rhs.m_pkg_view_list.size());
std::transform( std::transform(rhs.m_pkg_view_list.begin(), rhs.m_pkg_view_list.end(), tmp.begin(), offset_lbd);
rhs.m_pkg_view_list.begin(), rhs.m_pkg_view_list.end(), tmp.begin(), offset_lbd);
swap(tmp, m_pkg_view_list); swap(tmp, m_pkg_view_list);
} }
if (!rhs.m_ordered_pkg_list.empty()) if (!rhs.m_ordered_pkg_list.empty())
{ {
auto tmp(rhs.m_ordered_pkg_list); auto tmp(rhs.m_ordered_pkg_list);
std::for_each(tmp.begin(), std::for_each(
tmp.end(), tmp.begin(),
[offset_lbd](auto& entry) { tmp.end(),
std::transform(entry.second.begin(), [offset_lbd](auto& entry) {
entry.second.end(), std::transform(
entry.second.begin(), entry.second.begin(),
offset_lbd); entry.second.end(),
}); entry.second.begin(),
offset_lbd
);
}
);
swap(m_ordered_pkg_list, tmp); swap(m_ordered_pkg_list, tmp);
} }
} }
@ -396,16 +405,20 @@ namespace mamba
{ {
for (auto& entry : m_ordered_pkg_list) for (auto& entry : m_ordered_pkg_list)
{ {
std::sort(entry.second.begin(), std::sort(
entry.second.end(), entry.second.begin(),
[fun](const auto& lhs, const auto& rhs) { return fun(*lhs, *rhs); }); entry.second.end(),
[fun](const auto& lhs, const auto& rhs) { return fun(*lhs, *rhs); }
);
} }
} }
else else
{ {
std::sort(m_pkg_view_list.begin(), std::sort(
m_pkg_view_list.end(), m_pkg_view_list.begin(),
[fun](const auto& lhs, const auto& rhs) { return fun(*lhs, *rhs); }); m_pkg_view_list.end(),
[fun](const auto& lhs, const auto& rhs) { return fun(*lhs, *rhs); }
);
} }
return *this; return *this;
@ -539,6 +552,7 @@ namespace mamba
class graph_printer class graph_printer
{ {
public: public:
using graph_type = query_result::dependency_graph; using graph_type = query_result::dependency_graph;
using node_id = graph_type::node_id; using node_id = graph_type::node_id;
@ -602,6 +616,7 @@ namespace mamba
} }
private: private:
bool is_on_last_stack(node_id node) const bool is_on_last_stack(node_id node) const
{ {
return !m_last_stack.empty() && m_last_stack.top() == node; return !m_last_stack.empty() && m_last_stack.top() == node;
@ -671,8 +686,8 @@ namespace mamba
: (m_type == QueryType::kDEPENDS ? "depends" : "whoneeds"); : (m_type == QueryType::kDEPENDS ? "depends" : "whoneeds");
j["query"] = { { "query", MatchSpec(m_query).conda_build_form() }, { "type", query_type } }; j["query"] = { { "query", MatchSpec(m_query).conda_build_form() }, { "type", query_type } };
std::string msg std::string msg = m_pkg_view_list.empty() ? "No entries matching \"" + m_query + "\" found"
= m_pkg_view_list.empty() ? "No entries matching \"" + m_query + "\" found" : ""; : "";
j["result"] = { { "msg", msg }, { "status", "OK" } }; j["result"] = { { "msg", msg }, { "status", "OK" } };
j["result"]["pkgs"] = nlohmann::json::array(); j["result"]["pkgs"] = nlohmann::json::array();
@ -685,8 +700,9 @@ namespace mamba
{ {
bool has_root = !m_dep_graph.successors(0).empty(); bool has_root = !m_dep_graph.successors(0).empty();
j["result"]["graph_roots"] = nlohmann::json::array(); j["result"]["graph_roots"] = nlohmann::json::array();
j["result"]["graph_roots"].push_back(has_root ? m_dep_graph.nodes()[0].json_record() j["result"]["graph_roots"].push_back(
: nlohmann::json(m_query)); has_root ? m_dep_graph.nodes()[0].json_record() : nlohmann::json(m_query)
);
} }
return j; return j;
} }

View File

@ -4,11 +4,12 @@
// //
// The full license is in the file LICENSE, distributed with this software. // The full license is in the file LICENSE, distributed with this software.
#include "mamba/core/context.hpp"
#include "mamba/core/pool.hpp"
#include "mamba/core/repo.hpp" #include "mamba/core/repo.hpp"
#include "mamba/core/context.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/package_info.hpp" #include "mamba/core/package_info.hpp"
#include "mamba/core/pool.hpp"
extern "C" extern "C"
{ {
@ -30,11 +31,13 @@ namespace mamba
return MTV; return MTV;
} }
MRepo::MRepo(MPool& pool, MRepo::MRepo(
const std::string& /*name*/, MPool& pool,
const fs::u8path& index, const std::string& /*name*/,
const RepoMetadata& metadata, const fs::u8path& index,
const Channel& channel) const RepoMetadata& metadata,
const Channel& channel
)
: m_metadata(metadata) : m_metadata(metadata)
{ {
m_url = rsplit(metadata.url, "/", 1)[0]; m_url = rsplit(metadata.url, "/", 1)[0];
@ -44,10 +47,7 @@ namespace mamba
p_channel = &channel; p_channel = &channel;
} }
MRepo::MRepo(MPool& pool, MRepo::MRepo(MPool& pool, const std::string& name, const std::string& index, const std::string& url)
const std::string& name,
const std::string& index,
const std::string& url)
: m_url(url) : m_url(url)
{ {
m_repo = repo_create(pool, name.c_str()); m_repo = repo_create(pool, name.c_str());
@ -55,9 +55,7 @@ namespace mamba
read_file(index); read_file(index);
} }
MRepo::MRepo(MPool& pool, MRepo::MRepo(MPool& pool, const std::string& name, const std::vector<PackageInfo>& package_infos)
const std::string& name,
const std::vector<PackageInfo>& package_infos)
{ {
m_repo = repo_create(pool, name.c_str()); m_repo = repo_create(pool, name.c_str());
m_repo->appdata = this; m_repo->appdata = this;
@ -154,8 +152,7 @@ namespace mamba
Id handle = repo_add_solvable(m_repo); Id handle = repo_add_solvable(m_repo);
Solvable* s = pool_id2solvable(pool, handle); Solvable* s = pool_id2solvable(pool, handle);
repodata_set_str( repodata_set_str(data, handle, SOLVABLE_BUILDVERSION, std::to_string(info.build_number).c_str());
data, handle, SOLVABLE_BUILDVERSION, std::to_string(info.build_number).c_str());
repodata_add_poolstr_array(data, handle, SOLVABLE_BUILDFLAVOR, info.build_string.c_str()); repodata_add_poolstr_array(data, handle, SOLVABLE_BUILDFLAVOR, info.build_string.c_str());
s->name = pool_str2id(pool, info.name.c_str(), 1); s->name = pool_str2id(pool, info.name.c_str(), 1);
s->evr = pool_str2id(pool, info.version.c_str(), 1); s->evr = pool_str2id(pool, info.version.c_str(), 1);
@ -165,12 +162,13 @@ namespace mamba
solvable_set_str(s, real_repo_key, info.url.c_str()); solvable_set_str(s, real_repo_key, info.url.c_str());
if (!info.noarch.empty()) if (!info.noarch.empty())
{
solvable_set_str(s, noarch_repo_key, info.noarch.c_str()); solvable_set_str(s, noarch_repo_key, info.noarch.c_str());
}
repodata_set_location(data, handle, 0, info.subdir.c_str(), info.fn.c_str()); repodata_set_location(data, handle, 0, info.subdir.c_str(), info.fn.c_str());
repodata_set_checksum( repodata_set_checksum(data, handle, SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, info.sha256.c_str());
data, handle, SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, info.sha256.c_str());
if (!info.depends.empty()) if (!info.depends.empty())
{ {
@ -196,8 +194,12 @@ namespace mamba
} }
} }
s->provides s->provides = repo_addid_dep(
= repo_addid_dep(m_repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); m_repo,
s->provides,
pool_rel2id(pool, s->name, s->evr, REL_EQ, 1),
0
);
} }
Id MRepo::id() const Id MRepo::id() const
@ -261,25 +263,29 @@ namespace mamba
} }
if (pkg_s->name == pip) if (pkg_s->name == pip)
{ {
pkg_s->requires pkg_s->requires = repo_addid_dep(
= repo_addid_dep(m_repo, pkg_s->requires, python_dep, SOLVABLE_PREREQMARKER); m_repo,
pkg_s->requires,
python_dep,
SOLVABLE_PREREQMARKER
);
} }
} }
} }
MRepo& MRepo::create(MPool& pool, MRepo&
const std::string& name, MRepo::create(MPool& pool, const std::string& name, const std::string& filename, const std::string& url)
const std::string& filename,
const std::string& url)
{ {
return pool.add_repo(MRepo(pool, name, filename, url)); return pool.add_repo(MRepo(pool, name, filename, url));
} }
MRepo& MRepo::create(MPool& pool, MRepo& MRepo::create(
const std::string& name, MPool& pool,
const fs::u8path& filename, const std::string& name,
const RepoMetadata& meta, const fs::u8path& filename,
const Channel& channel) const RepoMetadata& meta,
const Channel& channel
)
{ {
return pool.add_repo(MRepo(pool, name, filename, meta, channel)); return pool.add_repo(MRepo(pool, name, filename, meta, channel));
} }
@ -352,16 +358,24 @@ namespace mamba
static constexpr auto failure = std::numeric_limits<unsigned long long>::max(); static constexpr auto failure = std::numeric_limits<unsigned long long>::max();
const char* url = repodata_lookup_str(repodata, SOLVID_META, url_id); const char* url = repodata_lookup_str(repodata, SOLVID_META, url_id);
const auto pip_added const auto pip_added = repodata_lookup_num(
= repodata_lookup_num(repodata, SOLVID_META, pip_added_id, failure); repodata,
SOLVID_META,
pip_added_id,
failure
);
const char* etag = repodata_lookup_str(repodata, SOLVID_META, etag_id); const char* etag = repodata_lookup_str(repodata, SOLVID_META, etag_id);
const char* mod = repodata_lookup_str(repodata, SOLVID_META, mod_id); const char* mod = repodata_lookup_str(repodata, SOLVID_META, mod_id);
const char* tool_version const char* tool_version = repodata_lookup_str(
= repodata_lookup_str(repodata, SOLVID_META, REPOSITORY_TOOLVERSION); repodata,
SOLVID_META,
REPOSITORY_TOOLVERSION
);
LOG_INFO << "Metadata solv file: " << url << " " << pip_added << " " << etag LOG_INFO << "Metadata solv file: " << url << " " << pip_added << " " << etag
<< " " << mod << " " << tool_version; << " " << mod << " " << tool_version;
bool metadata_valid bool metadata_valid = !(
= !(!url || !etag || !mod || !tool_version || pip_added == failure); !url || !etag || !mod || !tool_version || pip_added == failure
);
if (metadata_valid) if (metadata_valid)
{ {
@ -370,8 +384,7 @@ namespace mamba
&& (std::strcmp(tool_version, mamba_tool_version()) == 0); && (std::strcmp(tool_version, mamba_tool_version()) == 0);
} }
LOG_INFO << "Metadata from SOLV are " LOG_INFO << "Metadata from SOLV are " << (metadata_valid ? "valid" : "NOT valid");
<< (metadata_valid ? "valid" : "NOT valid");
if (!metadata_valid) if (!metadata_valid)
{ {
@ -412,8 +425,10 @@ namespace mamba
if (ret != 0) if (ret != 0)
{ {
fclose(fp); fclose(fp);
throw std::runtime_error("Could not read JSON repodata file (" + m_json_file.string() throw std::runtime_error(
+ ") " + std::string(pool_errstr(m_repo->pool))); "Could not read JSON repodata file (" + m_json_file.string() + ") "
+ std::string(pool_errstr(m_repo->pool))
);
} }
// TODO move this to a more structured approach for repodata patching? // TODO move this to a more structured approach for repodata patching?

View File

@ -1,32 +1,32 @@
#include <iostream> #include "mamba/core/run.hpp"
#include <csignal> #include <csignal>
#include <exception> #include <exception>
#include <iostream>
#include <thread> #include <thread>
#include <spdlog/spdlog.h>
#include <fmt/color.h> #include <fmt/color.h>
#include <fmt/ostream.h> #include <fmt/ostream.h>
#include <reproc++/run.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <reproc++/run.hpp>
#include <spdlog/spdlog.h>
#include "mamba/api/configuration.hpp" #include "mamba/api/configuration.hpp"
#include "mamba/api/install.hpp" #include "mamba/api/install.hpp"
#include "mamba/core/error_handling.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/util_os.hpp" #include "mamba/core/util_os.hpp"
#include "mamba/core/util_random.hpp" #include "mamba/core/util_random.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/error_handling.hpp"
#include "mamba/core/run.hpp"
#ifndef _WIN32 #ifndef _WIN32
extern "C" extern "C"
{ {
#include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <sys/types.h>
#include <unistd.h>
} }
#else #else
#include <process.h> #include <process.h>
@ -62,10 +62,8 @@ namespace mamba
if (!prefixes_bag.empty()) if (!prefixes_bag.empty())
{ {
// Pick a random prefix from our bag of prefixes. // Pick a random prefix from our bag of prefixes.
const auto selected_prefix_idx const auto selected_prefix_idx = random_int<std::size_t>(0, prefixes_bag.size() - 1);
= random_int<std::size_t>(0, prefixes_bag.size() - 1); const auto selected_prefix_it = std::next(prefixes_bag.begin(), selected_prefix_idx);
const auto selected_prefix_it
= std::next(prefixes_bag.begin(), selected_prefix_idx);
selected_prefix = *selected_prefix_it; selected_prefix = *selected_prefix_it;
prefixes_bag.erase(selected_prefix_it); prefixes_bag.erase(selected_prefix_it);
} }
@ -90,7 +88,9 @@ namespace mamba
const auto new_process_name = fmt::format("{}_{}", selected_prefix, selected_name); const auto new_process_name = fmt::format("{}_{}", selected_prefix, selected_name);
if (!is_process_name_running(new_process_name)) if (!is_process_name_running(new_process_name))
{
return new_process_name; return new_process_name;
}
} }
} }
@ -112,23 +112,23 @@ namespace mamba
fmt::format( fmt::format(
"'mamba run' failed to lock ({}) or lockfile was not properly deleted - error: {}", "'mamba run' failed to lock ({}) or lockfile was not properly deleted - error: {}",
proc_dir_path.string(), proc_dir_path.string(),
error->what()), error->what()
),
mamba_error_code::lockfile_failure mamba_error_code::lockfile_failure
}; };
} }
else else
{ {
LOG_DEBUG LOG_DEBUG << "`mamba run` file locking attempt ignored because locking is disabled - path: "
<< "`mamba run` file locking attempt ignored because locking is disabled - path: " << proc_dir_path.string();
<< proc_dir_path.string();
} }
} }
return lockfile; return lockfile;
} }
nlohmann::json get_all_running_processes_info( nlohmann::json
const std::function<bool(const nlohmann::json&)>& filter) get_all_running_processes_info(const std::function<bool(const nlohmann::json&)>& filter)
{ {
nlohmann::json all_processes_info; nlohmann::json all_processes_info;
@ -138,7 +138,9 @@ namespace mamba
{ {
const auto file_location = entry.path(); const auto file_location = entry.path();
if (file_location.extension() != ".json") if (file_location.extension() != ".json")
{
continue; continue;
}
std::ifstream pid_file{ file_location.std_path(), open_mode }; std::ifstream pid_file{ file_location.std_path(), open_mode };
if (!pid_file.is_open()) if (!pid_file.is_open())
@ -150,7 +152,9 @@ namespace mamba
auto running_processes_info = nlohmann::json::parse(pid_file); auto running_processes_info = nlohmann::json::parse(pid_file);
running_processes_info["pid"] = file_location.filename().replace_extension().string(); running_processes_info["pid"] = file_location.filename().replace_extension().string();
if (!filter || filter(running_processes_info)) if (!filter || filter(running_processes_info))
{
all_processes_info.push_back(running_processes_info); all_processes_info.push_back(running_processes_info);
}
} }
return all_processes_info; return all_processes_info;
@ -159,25 +163,31 @@ namespace mamba
bool is_process_name_running(const std::string& name) bool is_process_name_running(const std::string& name)
{ {
const auto other_processes_with_same_name = get_all_running_processes_info( const auto other_processes_with_same_name = get_all_running_processes_info(
[&](const nlohmann::json& process_info) { return process_info["name"] == name; }); [&](const nlohmann::json& process_info) { return process_info["name"] == name; }
);
return !other_processes_with_same_name.empty(); return !other_processes_with_same_name.empty();
} }
ScopedProcFile::ScopedProcFile(const std::string& name, ScopedProcFile::ScopedProcFile(
const std::vector<std::string>& command, const std::string& name,
LockFile proc_dir_lock) const std::vector<std::string>& command,
LockFile proc_dir_lock
)
: location{ proc_dir() / fmt::format("{}.json", getpid()) } : location{ proc_dir() / fmt::format("{}.json", getpid()) }
{ {
// Lock must be hold for the duraction of this constructor. // Lock must be hold for the duraction of this constructor.
if (Context::instance().use_lockfiles) if (Context::instance().use_lockfiles)
{
assert(proc_dir_lock); assert(proc_dir_lock);
}
const auto open_mode = std::ios::binary | std::ios::trunc | std::ios::out; const auto open_mode = std::ios::binary | std::ios::trunc | std::ios::out;
std::ofstream pid_file(location.std_path(), open_mode); std::ofstream pid_file(location.std_path(), open_mode);
if (!pid_file.is_open()) if (!pid_file.is_open())
{ {
throw std::runtime_error( throw std::runtime_error(
fmt::format("'mamba run' failed to open/create file: {}", location.string())); fmt::format("'mamba run' failed to open/create file: {}", location.string())
);
} }
nlohmann::json file_json; nlohmann::json file_json;
@ -196,7 +206,10 @@ namespace mamba
if (!is_removed) if (!is_removed)
{ {
LOG_WARNING << fmt::format( LOG_WARNING << fmt::format(
"Failed to remove file '{}' : {}", location.string(), errcode.message()); "Failed to remove file '{}' : {}",
location.string(),
errcode.message()
);
} }
} }
@ -208,22 +221,30 @@ namespace mamba
// already a daemon // already a daemon
if (getppid() == 1) if (getppid() == 1)
{
return; return;
}
// fork parent process // fork parent process
pid = fork(); pid = fork();
if (pid < 0) if (pid < 0)
{
exit(1); exit(1);
}
// exit parent process // exit parent process
if (pid > 0) if (pid > 0)
{
exit(0); exit(0);
}
// at this point we are executing as the child process // at this point we are executing as the child process
// create a new SID for the child process // create a new SID for the child process
sid = setsid(); sid = setsid();
if (sid < 0) if (sid < 0)
{
exit(1); exit(1);
}
fd = open("/dev/null", O_RDWR, 0); fd = open("/dev/null", O_RDWR, 0);
@ -244,18 +265,19 @@ namespace mamba
} }
#endif #endif
int run_in_environment(std::vector<std::string> command, int run_in_environment(
const std::string& cwd, std::vector<std::string> command,
int stream_options, const std::string& cwd,
bool clean_env, int stream_options,
bool detach, bool clean_env,
const std::vector<std::string>& env_vars, bool detach,
const std::string& specific_process_name) const std::vector<std::string>& env_vars,
const std::string& specific_process_name
)
{ {
if (!fs::exists(Context::instance().target_prefix)) if (!fs::exists(Context::instance().target_prefix))
{ {
LOG_CRITICAL << "The given prefix does not exist: " LOG_CRITICAL << "The given prefix does not exist: " << Context::instance().target_prefix;
<< Context::instance().target_prefix;
return 1; return 1;
} }
std::vector<std::string> raw_command = command; std::vector<std::string> raw_command = command;
@ -264,8 +286,7 @@ namespace mamba
bool is_created = fs::create_directories(proc_dir(), ec); bool is_created = fs::create_directories(proc_dir(), ec);
if (!is_created && ec) if (!is_created && ec)
{ {
LOG_WARNING << "Could not create proc dir: " << proc_dir() << " (" << ec.message() LOG_WARNING << "Could not create proc dir: " << proc_dir() << " (" << ec.message() << ")";
<< ")";
} }
LOG_DEBUG << "Currently running processes: " << get_all_running_processes_info(); LOG_DEBUG << "Currently running processes: " << get_all_running_processes_info();
@ -274,11 +295,15 @@ namespace mamba
// replace the wrapping bash with new process entirely // replace the wrapping bash with new process entirely
#ifndef _WIN32 #ifndef _WIN32
if (command.front() != "exec") if (command.front() != "exec")
{
command.insert(command.begin(), "exec"); command.insert(command.begin(), "exec");
}
#endif #endif
auto [wrapped_command, script_file] auto [wrapped_command, script_file] = prepare_wrapped_call(
= prepare_wrapped_call(Context::instance().target_prefix, command); Context::instance().target_prefix,
command
);
LOG_DEBUG << "Running wrapped script: " << join(" ", command); LOG_DEBUG << "Running wrapped script: " << join(" ", command);
@ -317,8 +342,7 @@ namespace mamba
} }
else else
{ {
LOG_WARNING << "Requested env var " << e LOG_WARNING << "Requested env var " << e << " does not exist in environment";
<< " does not exist in environment";
} }
} }
} }
@ -332,9 +356,11 @@ namespace mamba
#ifndef _WIN32 #ifndef _WIN32
if (detach) if (detach)
{ {
Console::stream() << fmt::format(Context::instance().palette.success, Console::stream() << fmt::format(
"Running wrapped script {} in the background\n", Context::instance().palette.success,
fmt::join(command, " ")); "Running wrapped script {} in the background\n",
fmt::join(command, " ")
);
daemonize(); daemonize();
} }
#endif #endif
@ -362,9 +388,10 @@ namespace mamba
{ {
if (is_process_name_running(specific_process_name)) if (is_process_name_running(specific_process_name))
{ {
throw std::runtime_error( throw std::runtime_error(fmt::format(
fmt::format("Another process with name '{}' is currently running.", "Another process with name '{}' is currently running.",
specific_process_name)); specific_process_name
));
} }
command.insert(exe_name_it, { { "-a" }, specific_process_name }); command.insert(exe_name_it, { { "-a" }, specific_process_name });
return specific_process_name; return specific_process_name;
@ -377,7 +404,10 @@ namespace mamba
if (fs::is_directory(proc_dir()) && mamba::path::is_writable(proc_dir())) if (fs::is_directory(proc_dir()) && mamba::path::is_writable(proc_dir()))
{ {
scoped_proc_file = std::make_unique<ScopedProcFile>( scoped_proc_file = std::make_unique<ScopedProcFile>(
process_name, raw_command, std::move(proc_dir_lock)); process_name,
raw_command,
std::move(proc_dir_lock)
);
} }
#endif #endif
PID pid; PID pid;
@ -398,24 +428,25 @@ namespace mamba
MainExecutor::instance().schedule( MainExecutor::instance().schedule(
[]() []()
{ {
signal(SIGTERM, signal(
[](int signum) SIGTERM,
{ [](int signum)
LOG_INFO {
<< "Received SIGTERM on micromamba run - terminating process"; LOG_INFO << "Received SIGTERM on micromamba run - terminating process";
reproc::stop_actions sa; reproc::stop_actions sa;
sa.first = reproc::stop_action{ reproc::stop::terminate, sa.first = reproc::stop_action{ reproc::stop::terminate,
std::chrono::milliseconds(3000) }; std::chrono::milliseconds(3000) };
sa.second = reproc::stop_action{ reproc::stop::kill, sa.second = reproc::stop_action{ reproc::stop::kill,
std::chrono::milliseconds(3000) }; std::chrono::milliseconds(3000) };
proc.stop(sa); proc.stop(sa);
}); }
}); );
}
);
#endif #endif
// check if we need this // check if we need this
if (!opt.redirect.discard && opt.redirect.file == nullptr if (!opt.redirect.discard && opt.redirect.file == nullptr && opt.redirect.path == nullptr)
&& opt.redirect.path == nullptr)
{ {
opt.redirect.parent = true; opt.redirect.parent = true;
} }

File diff suppressed because it is too large Load Diff

View File

@ -7,21 +7,21 @@
#include <regex> #include <regex>
#include <stdexcept> #include <stdexcept>
#include <fmt/format.h>
#include <fmt/color.h> #include <fmt/color.h>
#include <fmt/format.h>
#include <fmt/ostream.h> #include <fmt/ostream.h>
#include <reproc++/run.hpp> #include <reproc++/run.hpp>
#ifdef _WIN32 #ifdef _WIN32
#include <WinReg.hpp> #include <WinReg.hpp>
#endif #endif
#include "mamba/core/shell_init.hpp" #include "mamba/core/activation.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/environment.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/shell_init.hpp"
#include "mamba/core/util.hpp" #include "mamba/core/util.hpp"
#include "mamba/core/util_os.hpp" #include "mamba/core/util_os.hpp"
#include "mamba/core/activation.hpp"
#include "mamba/core/environment.hpp"
#include "progress_bar_impl.hpp" #include "progress_bar_impl.hpp"
@ -29,17 +29,15 @@ namespace mamba
{ {
namespace namespace
{ {
static std::regex const MAMBA_INITIALIZE_RE_BLOCK( static std::regex const MAMBA_INITIALIZE_RE_BLOCK("\n?# >>> mamba initialize >>>(?:\n|\r\n)?"
"\n?# >>> mamba initialize >>>(?:\n|\r\n)?" "([\\s\\S]*?)"
"([\\s\\S]*?)" "# <<< mamba initialize <<<(?:\n|\r\n)?");
"# <<< mamba initialize <<<(?:\n|\r\n)?");
static std::regex const MAMBA_INITIALIZE_PS_RE_BLOCK( static std::regex const MAMBA_INITIALIZE_PS_RE_BLOCK("\n?#region mamba initialize(?:\n|\r\n)?"
"\n?#region mamba initialize(?:\n|\r\n)?" "([\\s\\S]*?)"
"([\\s\\S]*?)" "#endregion(?:\n|\r\n)?");
"#endregion(?:\n|\r\n)?"); static std::wregex const
static std::wregex const MAMBA_CMDEXE_HOOK_REGEX(L"(\"[^\"]*?mamba[-_]hook\\.bat\")", MAMBA_CMDEXE_HOOK_REGEX(L"(\"[^\"]*?mamba[-_]hook\\.bat\")", std::regex_constants::icase);
std::regex_constants::icase);
} }
@ -113,9 +111,11 @@ namespace mamba
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)
{ {
auto out = Console::stream(); auto out = Console::stream();
fmt::print(out, fmt::print(
"Setting cmd.exe AUTORUN to: {}", out,
fmt::styled(to_utf8(value), Context::instance().palette.success)); "Setting cmd.exe AUTORUN to: {}",
fmt::styled(to_utf8(value), Context::instance().palette.success)
);
winreg::RegKey key{ HKEY_CURRENT_USER, reg_path }; winreg::RegKey key{ HKEY_CURRENT_USER, reg_path };
key.SetStringValue(L"AutoRun", value); key.SetStringValue(L"AutoRun", value);
@ -135,10 +135,12 @@ namespace mamba
// modify registry key // modify registry key
std::wstring replace_str(L"__CONDA_REPLACE_ME_123__"); std::wstring replace_str(L"__CONDA_REPLACE_ME_123__");
std::wstring replaced_value = std::regex_replace(prev_value, std::wstring replaced_value = std::regex_replace(
MAMBA_CMDEXE_HOOK_REGEX, prev_value,
replace_str, MAMBA_CMDEXE_HOOK_REGEX,
std::regex_constants::format_first_only); replace_str,
std::regex_constants::format_first_only
);
std::wstring new_value = replaced_value; std::wstring new_value = replaced_value;
@ -169,7 +171,8 @@ namespace mamba
fmt::print( fmt::print(
out, out,
"{}", "{}",
fmt::styled("cmd.exe already initialized.", Context::instance().palette.success)); fmt::styled("cmd.exe already initialized.", Context::instance().palette.success)
);
} }
} }
@ -187,11 +190,14 @@ namespace mamba
autorun_list = split(std::wstring_view(prev_value), std::wstring_view(L"&")); autorun_list = split(std::wstring_view(prev_value), std::wstring_view(L"&"));
// remove the mamba hook from the autorun list // remove the mamba hook from the autorun list
autorun_list.erase(std::remove_if(autorun_list.begin(), autorun_list.erase(
autorun_list.end(), std::remove_if(
[&hook_string](const std::wstring& s) autorun_list.begin(),
{ return strip(s) == hook_string; }), autorun_list.end(),
autorun_list.end()); [&hook_string](const std::wstring& s) { return strip(s) == hook_string; }
),
autorun_list.end()
);
// join the list back into a string // join the list back into a string
std::wstring new_value = join(L" & ", autorun_list); std::wstring new_value = join(L" & ", autorun_list);
@ -207,7 +213,8 @@ namespace mamba
fmt::print( fmt::print(
out, out,
"{}", "{}",
fmt::styled("cmd.exe not initialized yet.", Context::instance().palette.success)); fmt::styled("cmd.exe not initialized yet.", Context::instance().palette.success)
);
} }
} }
#endif // _WIN32 #endif // _WIN32
@ -224,23 +231,31 @@ namespace mamba
fs::u8path bash; fs::u8path bash;
fs::u8path parent_process_name = get_process_name_by_pid(getppid()); fs::u8path parent_process_name = get_process_name_by_pid(getppid());
if (contains(parent_process_name.filename().string(), "bash")) if (contains(parent_process_name.filename().string(), "bash"))
{
bash = parent_process_name; bash = parent_process_name;
}
else else
#ifdef _WIN32 #ifdef _WIN32
bash = env::which("bash.exe"); bash = env::which("bash.exe");
#else #else
bash = env::which("bash"); bash = env::which("bash");
#endif #endif
const std::string command const std::string command = bash.empty() ? "cygpath"
= bash.empty() ? "cygpath" : (bash.parent_path() / "cygpath").string(); : (bash.parent_path() / "cygpath").string();
std::string out, err; std::string out, err;
try try
{ {
std::vector<std::string> args{ command, path }; std::vector<std::string> args{ command, path };
if (is_a_path_env) if (is_a_path_env)
{
args.push_back("--path"); args.push_back("--path");
}
auto [status, ec] = reproc::run( auto [status, ec] = reproc::run(
args, reproc::options{}, reproc::sink::string(out), reproc::sink::string(err)); args,
reproc::options{},
reproc::sink::string(out),
reproc::sink::string(err)
);
if (ec) if (ec)
{ {
throw std::runtime_error(ec.message()); throw std::runtime_error(ec.message());
@ -250,14 +265,14 @@ namespace mamba
catch (...) catch (...)
{ {
throw std::runtime_error( throw std::runtime_error(
"Could not find bash, or use cygpath to convert Windows path to Unix."); "Could not find bash, or use cygpath to convert Windows path to Unix."
);
} }
} }
std::string rcfile_content(const fs::u8path& env_prefix, std::string
const std::string& shell, rcfile_content(const fs::u8path& env_prefix, const std::string& shell, const fs::u8path& mamba_exe)
const fs::u8path& mamba_exe)
{ {
std::stringstream content; std::stringstream content;
@ -303,9 +318,8 @@ namespace mamba
#endif #endif
} }
std::string xonsh_content(const fs::u8path& env_prefix, std::string
const std::string& /*shell*/, xonsh_content(const fs::u8path& env_prefix, const std::string& /*shell*/, const fs::u8path& mamba_exe)
const fs::u8path& mamba_exe)
{ {
std::stringstream content; std::stringstream content;
std::string s_mamba_exe; std::string s_mamba_exe;
@ -326,22 +340,18 @@ namespace mamba
content << "import sys as _sys\n"; content << "import sys as _sys\n";
content << "from types import ModuleType as _ModuleType\n"; content << "from types import ModuleType as _ModuleType\n";
content << "_mod = _ModuleType(\"xontrib.mamba\",\n"; content << "_mod = _ModuleType(\"xontrib.mamba\",\n";
content content << " \'Autogenerated from $($MAMBA_EXE shell hook -s xonsh -p $MAMBA_ROOT_PREFIX)\')\n";
<< " \'Autogenerated from $($MAMBA_EXE shell hook -s xonsh -p $MAMBA_ROOT_PREFIX)\')\n"; content << "__xonsh__.execer.exec($($MAMBA_EXE shell hook -s xonsh -p $MAMBA_ROOT_PREFIX),\n";
content
<< "__xonsh__.execer.exec($($MAMBA_EXE shell hook -s xonsh -p $MAMBA_ROOT_PREFIX),\n";
content << " glbs=_mod.__dict__,\n"; content << " glbs=_mod.__dict__,\n";
content content << " filename=\'$($MAMBA_EXE shell hook -s xonsh -p $MAMBA_ROOT_PREFIX)\')\n";
<< " filename=\'$($MAMBA_EXE shell hook -s xonsh -p $MAMBA_ROOT_PREFIX)\')\n";
content << "_sys.modules[\"xontrib.mamba\"] = _mod\n"; content << "_sys.modules[\"xontrib.mamba\"] = _mod\n";
content << "del _sys, _mod, _ModuleType\n"; content << "del _sys, _mod, _ModuleType\n";
content << "# <<< mamba initialize <<<\n"; content << "# <<< mamba initialize <<<\n";
return content.str(); return content.str();
} }
std::string fish_content(const fs::u8path& env_prefix, std::string
const std::string& /*shell*/, fish_content(const fs::u8path& env_prefix, const std::string& /*shell*/, const fs::u8path& mamba_exe)
const fs::u8path& mamba_exe)
{ {
std::stringstream content; std::stringstream content;
std::string s_mamba_exe; std::string s_mamba_exe;
@ -364,9 +374,8 @@ namespace mamba
return content.str(); return content.str();
} }
std::string csh_content(const fs::u8path& env_prefix, std::string
const std::string& /*shell*/, csh_content(const fs::u8path& env_prefix, const std::string& /*shell*/, const fs::u8path& mamba_exe)
const fs::u8path& mamba_exe)
{ {
std::stringstream content; std::stringstream content;
std::string s_mamba_exe; std::string s_mamba_exe;
@ -389,19 +398,23 @@ namespace mamba
return content.str(); return content.str();
} }
void modify_rc_file(const fs::u8path& file_path, void modify_rc_file(
const fs::u8path& conda_prefix, const fs::u8path& file_path,
const std::string& shell, const fs::u8path& conda_prefix,
const fs::u8path& mamba_exe) const std::string& shell,
const fs::u8path& mamba_exe
)
{ {
auto out = Console::stream(); auto out = Console::stream();
fmt::print(out, fmt::print(
"Modifying RC file {}\n" out,
"Generating config for root prefix {}\n" "Modifying RC file {}\n"
"Setting mamba executable to: {}", "Generating config for root prefix {}\n"
fmt::streamed(file_path), "Setting mamba executable to: {}",
fmt::styled(fmt::streamed(conda_prefix), fmt::emphasis::bold), fmt::streamed(file_path),
fmt::styled(fmt::streamed(mamba_exe), fmt::emphasis::bold)); fmt::styled(fmt::streamed(conda_prefix), fmt::emphasis::bold),
fmt::styled(fmt::streamed(mamba_exe), fmt::emphasis::bold)
);
// TODO do we need binary or not? // TODO do we need binary or not?
std::string conda_init_content, rc_content; std::string conda_init_content, rc_content;
@ -432,18 +445,19 @@ namespace mamba
conda_init_content = rcfile_content(conda_prefix, shell, mamba_exe); conda_init_content = rcfile_content(conda_prefix, shell, mamba_exe);
} }
fmt::print(out, fmt::print(
"Adding (or replacing) the following in your {} file\n{}", out,
fmt::streamed(file_path), "Adding (or replacing) the following in your {} file\n{}",
fmt::styled(conda_init_content, Context::instance().palette.success)); fmt::streamed(file_path),
fmt::styled(conda_init_content, Context::instance().palette.success)
);
if (Context::instance().dry_run) if (Context::instance().dry_run)
{ {
return; return;
} }
std::string result std::string result = std::regex_replace(rc_content, MAMBA_INITIALIZE_RE_BLOCK, conda_init_content);
= std::regex_replace(rc_content, MAMBA_INITIALIZE_RE_BLOCK, conda_init_content);
if (result.find("# >>> mamba initialize >>>") == std::string::npos) if (result.find("# >>> mamba initialize >>>") == std::string::npos)
{ {
@ -457,12 +471,10 @@ namespace mamba
} }
} }
void reset_rc_file(const fs::u8path& file_path, void
const std::string& shell, reset_rc_file(const fs::u8path& file_path, const std::string& shell, const fs::u8path& mamba_exe)
const fs::u8path& mamba_exe)
{ {
Console::stream() << "Resetting RC file " << file_path Console::stream() << "Resetting RC file " << file_path << "\nDeleting config for root prefix "
<< "\nDeleting config for root prefix "
<< "\nClearing mamba executable environment variable"; << "\nClearing mamba executable environment variable";
std::string conda_init_content, rc_content; std::string conda_init_content, rc_content;
@ -478,11 +490,15 @@ namespace mamba
} }
auto out = Console::stream(); auto out = Console::stream();
fmt::print(out, fmt::print(
"Removing the following in your {} file\n{}", out,
fmt::streamed(file_path), "Removing the following in your {} file\n{}",
fmt::styled("# >>> mamba initialize >>>\n...\n# <<< mamba initialize <<<", fmt::streamed(file_path),
Context::instance().palette.success)); fmt::styled(
"# >>> mamba initialize >>>\n...\n# <<< mamba initialize <<<",
Context::instance().palette.success
)
);
if (rc_content.find("# >>> mamba initialize >>>") == std::string::npos) if (rc_content.find("# >>> mamba initialize >>>") == std::string::npos)
{ {
@ -538,10 +554,10 @@ namespace mamba
{ {
init_root_prefix_cmdexe(Context::instance().root_prefix); init_root_prefix_cmdexe(Context::instance().root_prefix);
LOG_WARNING << "Hook installed, now 'manually' execute:"; LOG_WARNING << "Hook installed, now 'manually' execute:";
LOG_WARNING LOG_WARNING << " CALL "
<< " CALL " << std::quoted(
<< std::quoted( (Context::instance().root_prefix / "condabin" / "mamba_hook.bat").string()
(Context::instance().root_prefix / "condabin" / "mamba_hook.bat").string()); );
} }
else if (shell == "fish") else if (shell == "fish")
{ {
@ -568,40 +584,51 @@ namespace mamba
std::ofstream mamba_bat_f = open_ofstream(root_prefix / "condabin" / "micromamba.bat"); std::ofstream mamba_bat_f = open_ofstream(root_prefix / "condabin" / "micromamba.bat");
std::string mamba_bat_contents(data_micromamba_bat); std::string mamba_bat_contents(data_micromamba_bat);
replace_all(mamba_bat_contents, replace_all(
std::string("__MAMBA_INSERT_ROOT_PREFIX__"), mamba_bat_contents,
std::string("@SET \"MAMBA_ROOT_PREFIX=" + root_prefix.string() + "\"")); std::string("__MAMBA_INSERT_ROOT_PREFIX__"),
replace_all(mamba_bat_contents, std::string("@SET \"MAMBA_ROOT_PREFIX=" + root_prefix.string() + "\"")
std::string("__MAMBA_INSERT_MAMBA_EXE__"), );
std::string("@SET \"MAMBA_EXE=" + exe.string() + "\"")); replace_all(
mamba_bat_contents,
std::string("__MAMBA_INSERT_MAMBA_EXE__"),
std::string("@SET \"MAMBA_EXE=" + exe.string() + "\"")
);
mamba_bat_f << mamba_bat_contents; mamba_bat_f << mamba_bat_contents;
std::ofstream _mamba_activate_bat_f std::ofstream _mamba_activate_bat_f = open_ofstream(
= open_ofstream(root_prefix / "condabin" / "_mamba_activate.bat"); root_prefix / "condabin" / "_mamba_activate.bat"
);
_mamba_activate_bat_f << data__mamba_activate_bat; _mamba_activate_bat_f << data__mamba_activate_bat;
std::string activate_bat_contents(data_activate_bat); std::string activate_bat_contents(data_activate_bat);
replace_all(activate_bat_contents, replace_all(
std::string("__MAMBA_INSERT_ROOT_PREFIX__"), activate_bat_contents,
std::string("@SET \"MAMBA_ROOT_PREFIX=" + root_prefix.string() + "\"")); std::string("__MAMBA_INSERT_ROOT_PREFIX__"),
replace_all(activate_bat_contents, std::string("@SET \"MAMBA_ROOT_PREFIX=" + root_prefix.string() + "\"")
std::string("__MAMBA_INSERT_MAMBA_EXE__"), );
std::string("@SET \"MAMBA_EXE=" + exe.string() + "\"")); replace_all(
activate_bat_contents,
std::string("__MAMBA_INSERT_MAMBA_EXE__"),
std::string("@SET \"MAMBA_EXE=" + exe.string() + "\"")
);
std::ofstream condabin_activate_bat_f std::ofstream condabin_activate_bat_f = open_ofstream(
= open_ofstream(root_prefix / "condabin" / "activate.bat"); root_prefix / "condabin" / "activate.bat"
);
condabin_activate_bat_f << activate_bat_contents; condabin_activate_bat_f << activate_bat_contents;
std::ofstream scripts_activate_bat_f std::ofstream scripts_activate_bat_f = open_ofstream(root_prefix / "Scripts" / "activate.bat");
= open_ofstream(root_prefix / "Scripts" / "activate.bat");
scripts_activate_bat_f << activate_bat_contents; scripts_activate_bat_f << activate_bat_contents;
std::string hook_content = data_mamba_hook_bat; std::string hook_content = data_mamba_hook_bat;
replace_all(hook_content, replace_all(
std::string("__MAMBA_INSERT_MAMBA_EXE__"), hook_content,
std::string("@SET \"MAMBA_EXE=" + exe.string() + "\"")); std::string("__MAMBA_INSERT_MAMBA_EXE__"),
std::string("@SET \"MAMBA_EXE=" + exe.string() + "\"")
);
std::ofstream mamba_hook_bat_f = open_ofstream(root_prefix / "condabin" / "mamba_hook.bat"); std::ofstream mamba_hook_bat_f = open_ofstream(root_prefix / "condabin" / "mamba_hook.bat");
mamba_hook_bat_f << hook_content; mamba_hook_bat_f << hook_content;
@ -832,21 +859,26 @@ namespace mamba
std::string conda_init_content = powershell_contents(conda_prefix); std::string conda_init_content = powershell_contents(conda_prefix);
bool found_mamba_initialize bool found_mamba_initialize = profile_content.find("#region mamba initialize")
= profile_content.find("#region mamba initialize") != std::string::npos; != std::string::npos;
// Find what content we need to add. // Find what content we need to add.
auto out = Console::stream(); auto out = Console::stream();
fmt::print(out, fmt::print(
"Adding (or replacing) the following in your {} file\n{}", out,
fmt::streamed(profile_path), "Adding (or replacing) the following in your {} file\n{}",
fmt::styled(conda_init_content, Context::instance().palette.success)); fmt::streamed(profile_path),
fmt::styled(conda_init_content, Context::instance().palette.success)
);
if (found_mamba_initialize) if (found_mamba_initialize)
{ {
LOG_DEBUG << "Found mamba initialize. Replacing mamba initialize block."; LOG_DEBUG << "Found mamba initialize. Replacing mamba initialize block.";
profile_content = std::regex_replace( profile_content = std::regex_replace(
profile_content, MAMBA_INITIALIZE_PS_RE_BLOCK, conda_init_content); profile_content,
MAMBA_INITIALIZE_PS_RE_BLOCK,
conda_init_content
);
} }
LOG_DEBUG << "Original profile content:\n" << profile_original_content; LOG_DEBUG << "Original profile content:\n" << profile_original_content;
@ -893,11 +925,12 @@ namespace mamba
LOG_DEBUG << "Original profile content:\n" << profile_content; LOG_DEBUG << "Original profile content:\n" << profile_content;
auto out = Console::stream(); auto out = Console::stream();
fmt::print(out, fmt::print(
"Removing the following in your {} file\n{}", out,
fmt::streamed(profile_path), "Removing the following in your {} file\n{}",
fmt::styled("#region mamba initialize\n...\n#endregion\n", fmt::streamed(profile_path),
Context::instance().palette.success)); fmt::styled("#region mamba initialize\n...\n#endregion\n", Context::instance().palette.success)
);
profile_content = std::regex_replace(profile_content, MAMBA_INITIALIZE_PS_RE_BLOCK, ""); profile_content = std::regex_replace(profile_content, MAMBA_INITIALIZE_PS_RE_BLOCK, "");
LOG_DEBUG << "Profile content:\n" << profile_content; LOG_DEBUG << "Profile content:\n" << profile_content;
@ -946,7 +979,8 @@ namespace mamba
std::vector<std::string>{ exe, "-NoProfile", "-Command", profile_var }, std::vector<std::string>{ exe, "-NoProfile", "-Command", profile_var },
reproc::options{}, reproc::options{},
reproc::sink::string(out), reproc::sink::string(out),
reproc::sink::string(err)); reproc::sink::string(err)
);
if (ec) if (ec)
{ {
throw std::runtime_error(ec.message()); throw std::runtime_error(ec.message());
@ -1014,13 +1048,14 @@ namespace mamba
if (!profile_path.empty()) if (!profile_path.empty())
{ {
if (pwsh_profiles.count(profile_path)) if (pwsh_profiles.count(profile_path))
{
Console::stream() Console::stream()
<< exe << " profile already initialized at '" << profile_path << "'"; << exe << " profile already initialized at '" << profile_path << "'";
}
else else
{ {
pwsh_profiles.insert(profile_path); pwsh_profiles.insert(profile_path);
Console::stream() Console::stream() << "Init " << exe << " profile at '" << profile_path << "'";
<< "Init " << exe << " profile at '" << profile_path << "'";
init_powershell(profile_path, conda_prefix); init_powershell(profile_path, conda_prefix);
} }
} }

View File

@ -1,7 +1,7 @@
#include <atomic> #include <atomic>
#include <mutex>
#include <cassert> #include <cassert>
#include <mutex>
#include <regex> #include <regex>
extern "C" extern "C"
@ -9,14 +9,14 @@ extern "C"
#include <curl/urlapi.h> #include <curl/urlapi.h>
} }
#include "spdlog/spdlog.h"
#include "mamba/api/configuration.hpp" #include "mamba/api/configuration.hpp"
#include "mamba/core/channel_builder.hpp"
#include "mamba/core/context.hpp" #include "mamba/core/context.hpp"
#include "mamba/core/execution.hpp"
#include "mamba/core/output.hpp" #include "mamba/core/output.hpp"
#include "mamba/core/validate.hpp" #include "mamba/core/validate.hpp"
#include "mamba/core/channel_builder.hpp"
#include "mamba/core/execution.hpp" #include "spdlog/spdlog.h"
namespace mamba namespace mamba
@ -39,6 +39,7 @@ namespace mamba
class CURLSetup final class CURLSetup final
{ {
public: public:
CURLSetup() CURLSetup()
{ {
#ifdef LIBMAMBA_STATIC_DEPS #ifdef LIBMAMBA_STATIC_DEPS
@ -47,37 +48,38 @@ namespace mamba
if (on_linux) if (on_linux)
{ {
sslset_res sslset_res = curl_global_sslset(CURLSSLBACKEND_OPENSSL, nullptr, &available_backends);
= curl_global_sslset(CURLSSLBACKEND_OPENSSL, nullptr, &available_backends);
} }
else if (on_mac) else if (on_mac)
{ {
sslset_res = curl_global_sslset( sslset_res = curl_global_sslset(
CURLSSLBACKEND_SECURETRANSPORT, nullptr, &available_backends); CURLSSLBACKEND_SECURETRANSPORT,
nullptr,
&available_backends
);
} }
else if (on_win) else if (on_win)
{ {
sslset_res sslset_res = curl_global_sslset(CURLSSLBACKEND_SCHANNEL, nullptr, &available_backends);
= curl_global_sslset(CURLSSLBACKEND_SCHANNEL, nullptr, &available_backends);
} }
if (sslset_res == CURLSSLSET_TOO_LATE) if (sslset_res == CURLSSLSET_TOO_LATE)
{ {
LOG_ERROR << "cURL SSL init called too late, that is a bug."; LOG_ERROR << "cURL SSL init called too late, that is a bug.";
} }
else if (sslset_res == CURLSSLSET_UNKNOWN_BACKEND else if (sslset_res == CURLSSLSET_UNKNOWN_BACKEND || sslset_res == CURLSSLSET_NO_BACKENDS)
|| sslset_res == CURLSSLSET_NO_BACKENDS)
{ {
LOG_WARNING LOG_WARNING << "Could not use preferred SSL backend (Linux: OpenSSL, OS X: SecureTransport, Win: SChannel)"
<< "Could not use preferred SSL backend (Linux: OpenSSL, OS X: SecureTransport, Win: SChannel)" << std::endl;
<< std::endl;
LOG_WARNING << "Please check the cURL library configuration that you are using." LOG_WARNING << "Please check the cURL library configuration that you are using."
<< std::endl; << std::endl;
} }
#endif #endif
if (curl_global_init(CURL_GLOBAL_ALL) != 0) if (curl_global_init(CURL_GLOBAL_ALL) != 0)
{
throw std::runtime_error("failed to initialize curl"); throw std::runtime_error("failed to initialize curl");
}
} }
~CURLSetup() ~CURLSetup()
@ -133,7 +135,9 @@ namespace mamba
{ {
MainExecutor* expected = nullptr; MainExecutor* expected = nullptr;
if (!main_executor.compare_exchange_strong(expected, this)) if (!main_executor.compare_exchange_strong(expected, this))
{
throw MainExecutorError("attempted to create multiple main executors"); throw MainExecutorError("attempted to create multiple main executors");
}
} }
MainExecutor::~MainExecutor() MainExecutor::~MainExecutor()
@ -162,9 +166,12 @@ namespace mamba
if (!ptr) if (!ptr)
{ {
throw mamba::mamba_error( throw mamba::mamba_error(
fmt::format("attempt to use {} singleton instance after destruction", fmt::format(
typeid(T).name()), "attempt to use {} singleton instance after destruction",
mamba_error_code::internal_failure); typeid(T).name()
),
mamba_error_code::internal_failure
);
} }
return *ptr; return *ptr;

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