mirror of https://github.com/mamba-org/mamba.git
Add cpp linter and fix warnings
This commit is contained in:
parent
ffcd4a8f63
commit
98f2530d23
|
@ -0,0 +1,52 @@
|
|||
BasedOnStyle: Mozilla
|
||||
AccessModifierOffset: '-4'
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignEscapedNewlinesLeft: 'false'
|
||||
AllowAllParametersOfDeclarationOnNextLine: 'true'
|
||||
AllowShortBlocksOnASingleLine: 'false'
|
||||
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||
AllowShortFunctionsOnASingleLine: 'false'
|
||||
AllowShortIfStatementsOnASingleLine: 'false'
|
||||
AllowShortLoopsOnASingleLine: 'false'
|
||||
AlwaysBreakTemplateDeclarations: 'true'
|
||||
SpaceAfterTemplateKeyword: 'true'
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakBeforeBraces: Allman
|
||||
BreakBeforeTernaryOperators: 'true'
|
||||
BreakConstructorInitializersBeforeComma: 'true'
|
||||
BreakStringLiterals: 'false'
|
||||
ColumnLimit: '100'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
|
||||
ConstructorInitializerIndentWidth: '4'
|
||||
ContinuationIndentWidth: '4'
|
||||
Cpp11BracedListStyle: 'false'
|
||||
DerivePointerAlignment: 'false'
|
||||
DisableFormat: 'false'
|
||||
ExperimentalAutoDetectBinPacking: 'true'
|
||||
IndentCaseLabels: 'true'
|
||||
IndentWidth: '4'
|
||||
IndentWrappedFunctionNames: 'false'
|
||||
JavaScriptQuotes: Single
|
||||
KeepEmptyLinesAtTheStartOfBlocks: 'false'
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: '2'
|
||||
NamespaceIndentation: All
|
||||
ObjCBlockIndentWidth: '4'
|
||||
ObjCSpaceAfterProperty: 'false'
|
||||
ObjCSpaceBeforeProtocolList: 'false'
|
||||
PointerAlignment: Left
|
||||
ReflowComments: 'true'
|
||||
SortIncludes: 'false'
|
||||
SpaceAfterCStyleCast: 'true'
|
||||
SpaceBeforeAssignmentOperators: 'true'
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: 'false'
|
||||
SpacesBeforeTrailingComments: '2'
|
||||
SpacesInAngles: 'false'
|
||||
SpacesInCStyleCastParentheses: 'false'
|
||||
SpacesInContainerLiterals: 'false'
|
||||
SpacesInParentheses: 'false'
|
||||
SpacesInSquareBrackets: 'false'
|
||||
Standard: Cpp11
|
||||
TabWidth: '4'
|
||||
UseTab: Never
|
|
@ -1,4 +1,4 @@
|
|||
name: linter
|
||||
name: Linters (Python, C++)
|
||||
|
||||
on:
|
||||
push:
|
||||
|
@ -17,11 +17,28 @@ jobs:
|
|||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Setup Miniconda
|
||||
uses: goanpeca/setup-miniconda@v1.0.2
|
||||
with:
|
||||
miniconda-version: 'latest'
|
||||
activate-environment: linters
|
||||
python-version: 3.8
|
||||
auto-update-conda: true
|
||||
- name: Config Channels
|
||||
shell: pwsh
|
||||
run: |
|
||||
conda config --set always_yes yes
|
||||
conda config --add channels conda-forge
|
||||
- name: Install dependencies
|
||||
shell: pwsh
|
||||
run: |
|
||||
python -m pip install pre-commit
|
||||
conda install clang clang-tools=10.0.1 pre-commit
|
||||
- name: Conda info
|
||||
shell: pwsh
|
||||
run: |
|
||||
conda info -a
|
||||
conda list
|
||||
- name: Run all linters
|
||||
shell: pwsh
|
||||
run: |
|
||||
pre-commit run --all-files
|
||||
pre-commit run --all-files --verbose
|
||||
|
|
|
@ -34,10 +34,14 @@ repos:
|
|||
rev: 3.8.3
|
||||
hooks:
|
||||
- id: flake8
|
||||
exclude: tests/data
|
||||
language_version: python3
|
||||
additional_dependencies:
|
||||
- flake8-typing-imports==1.9.0
|
||||
- flake8-builtins==1.5.3
|
||||
- flake8-bugbear==20.1.4
|
||||
- flake8-isort==3.0.1
|
||||
- repo: https://github.com/bmorcos/pre-commit-hooks-cpp
|
||||
rev: master
|
||||
hooks:
|
||||
- id: clang-format
|
||||
args: [--style=file]
|
||||
|
|
|
@ -7,9 +7,14 @@
|
|||
#ifndef MAMBA_ACTIVATION_HPP
|
||||
#define MAMBA_ACTIVATION_HPP
|
||||
|
||||
#include "util.hpp"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "context.hpp"
|
||||
#include "output.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
// TODO write a map that keeps insertion order
|
||||
|
||||
|
@ -35,7 +40,6 @@ namespace mamba
|
|||
class Activator
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~Activator() = default;
|
||||
|
||||
Activator(const Activator&) = delete;
|
||||
|
@ -44,14 +48,17 @@ namespace mamba
|
|||
Activator& operator=(Activator&&) = delete;
|
||||
|
||||
virtual std::string script(const EnvironmentTransform& env) = 0;
|
||||
virtual std::pair<std::string, std::string> update_prompt(const std::string& conda_prompt_modifier) = 0;
|
||||
virtual std::pair<std::string, std::string> update_prompt(
|
||||
const std::string& conda_prompt_modifier)
|
||||
= 0;
|
||||
virtual std::string shell_extension() = 0;
|
||||
|
||||
std::vector<fs::path> get_activate_scripts(const fs::path& prefix);
|
||||
std::vector<fs::path> get_deactivate_scripts(const fs::path& prefix);
|
||||
|
||||
std::string get_default_env(const fs::path& prefix);
|
||||
std::vector<std::pair<std::string, std::string>> get_environment_vars(const fs::path& prefix);
|
||||
std::vector<std::pair<std::string, std::string>> get_environment_vars(
|
||||
const fs::path& prefix);
|
||||
|
||||
std::string get_prompt_modifier(const fs::path& prefix,
|
||||
const std::string& conda_default_env,
|
||||
|
@ -64,8 +71,9 @@ namespace mamba
|
|||
std::string replace_prefix_in_path(const fs::path& old_prefix, const fs::path& new_prefix);
|
||||
std::string remove_prefix_from_path(const fs::path& prefix);
|
||||
|
||||
void get_export_unset_vars(EnvironmentTransform& envt,
|
||||
const std::vector<std::pair<std::string, std::string>>& to_export);
|
||||
void get_export_unset_vars(
|
||||
EnvironmentTransform& envt,
|
||||
const std::vector<std::pair<std::string, std::string>>& to_export);
|
||||
|
||||
EnvironmentTransform build_reactivate();
|
||||
EnvironmentTransform build_deactivate();
|
||||
|
@ -82,7 +90,6 @@ namespace mamba
|
|||
std::string hook();
|
||||
|
||||
protected:
|
||||
|
||||
Activator();
|
||||
|
||||
bool m_stack = false;
|
||||
|
@ -94,12 +101,12 @@ namespace mamba
|
|||
class PosixActivator : public Activator
|
||||
{
|
||||
public:
|
||||
|
||||
PosixActivator() = default;
|
||||
virtual ~PosixActivator() = default;
|
||||
|
||||
std::string script(const EnvironmentTransform& env_transform) override;
|
||||
std::pair<std::string, std::string> update_prompt(const std::string& conda_prompt_modifier) override;
|
||||
std::pair<std::string, std::string> update_prompt(
|
||||
const std::string& conda_prompt_modifier) override;
|
||||
std::string shell_extension() override;
|
||||
|
||||
std::string hook_preamble() override;
|
||||
|
@ -107,16 +114,15 @@ namespace mamba
|
|||
fs::path hook_source_path() override;
|
||||
};
|
||||
|
||||
class CmdExeActivator
|
||||
: public Activator
|
||||
class CmdExeActivator : public Activator
|
||||
{
|
||||
public:
|
||||
|
||||
CmdExeActivator() = default;
|
||||
virtual ~CmdExeActivator() = default;
|
||||
|
||||
std::string script(const EnvironmentTransform& env_transform) override;
|
||||
std::pair<std::string, std::string> update_prompt(const std::string& conda_prompt_modifier) override;
|
||||
std::pair<std::string, std::string> update_prompt(
|
||||
const std::string& conda_prompt_modifier) override;
|
||||
std::string shell_extension() override;
|
||||
|
||||
std::string hook_preamble() override;
|
||||
|
@ -124,15 +130,15 @@ namespace mamba
|
|||
fs::path hook_source_path() override;
|
||||
};
|
||||
|
||||
class PowerShellActivator
|
||||
: public Activator
|
||||
class PowerShellActivator : public Activator
|
||||
{
|
||||
public:
|
||||
PowerShellActivator() = default;
|
||||
virtual ~PowerShellActivator() = default;
|
||||
|
||||
std::string script(const EnvironmentTransform& env_transform) override;
|
||||
std::pair<std::string, std::string> update_prompt(const std::string& conda_prompt_modifier) override;
|
||||
std::pair<std::string, std::string> update_prompt(
|
||||
const std::string& conda_prompt_modifier) override;
|
||||
std::string shell_extension() override;
|
||||
|
||||
std::string hook_preamble() override;
|
||||
|
@ -140,21 +146,21 @@ namespace mamba
|
|||
fs::path hook_source_path() override;
|
||||
};
|
||||
|
||||
class XonshActivator
|
||||
: public Activator
|
||||
class XonshActivator : public Activator
|
||||
{
|
||||
public:
|
||||
XonshActivator() = default;
|
||||
virtual ~XonshActivator() = default;
|
||||
|
||||
std::string script(const EnvironmentTransform& env_transform) override;
|
||||
std::pair<std::string, std::string> update_prompt(const std::string& conda_prompt_modifier) override;
|
||||
std::pair<std::string, std::string> update_prompt(
|
||||
const std::string& conda_prompt_modifier) override;
|
||||
std::string shell_extension() override;
|
||||
|
||||
std::string hook_preamble() override;
|
||||
std::string hook_postamble() override;
|
||||
fs::path hook_source_path() override;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,11 +13,9 @@
|
|||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
class Channel
|
||||
{
|
||||
public:
|
||||
|
||||
Channel(const std::string& scheme = "",
|
||||
const std::string& auth = "",
|
||||
const std::string& location = "",
|
||||
|
@ -52,7 +50,6 @@ namespace mamba
|
|||
static void clear_cache();
|
||||
|
||||
private:
|
||||
|
||||
using cache_type = std::map<std::string, Channel>;
|
||||
static cache_type& get_cache();
|
||||
|
||||
|
@ -60,8 +57,7 @@ namespace mamba
|
|||
static Channel from_name(const std::string& name);
|
||||
static Channel from_value(const std::string& value);
|
||||
|
||||
std::string build_url(const std::string& base,
|
||||
bool with_credential) const;
|
||||
std::string build_url(const std::string& base, bool with_credential) const;
|
||||
|
||||
std::string m_scheme;
|
||||
std::string m_auth;
|
||||
|
@ -89,7 +85,6 @@ namespace mamba
|
|||
class ChannelContext
|
||||
{
|
||||
public:
|
||||
|
||||
using channel_list = std::vector<std::string>;
|
||||
using channel_map = std::map<std::string, Channel>;
|
||||
using multichannel_map = std::map<std::string, std::vector<std::string>>;
|
||||
|
@ -108,7 +103,6 @@ namespace mamba
|
|||
const channel_list& get_whitelist_channels() const;
|
||||
|
||||
private:
|
||||
|
||||
ChannelContext();
|
||||
~ChannelContext() = default;
|
||||
|
||||
|
@ -121,6 +115,6 @@ namespace mamba
|
|||
channel_list m_whitelist_channels;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,13 +26,13 @@ namespace mamba
|
|||
class Context
|
||||
{
|
||||
public:
|
||||
|
||||
std::string conda_version = "3.8.0";
|
||||
std::string current_command = "mamba";
|
||||
|
||||
fs::path target_prefix = std::getenv("CONDA_PREFIX") ? std::getenv("CONDA_PREFIX") : "";;
|
||||
fs::path target_prefix = std::getenv("CONDA_PREFIX") ? std::getenv("CONDA_PREFIX") : "";
|
||||
// Need to prevent circular imports here (otherwise using env::get())
|
||||
fs::path root_prefix = std::getenv("MAMBA_ROOT_PREFIX") ? std::getenv("MAMBA_ROOT_PREFIX") : "";
|
||||
fs::path root_prefix
|
||||
= std::getenv("MAMBA_ROOT_PREFIX") ? std::getenv("MAMBA_ROOT_PREFIX") : "";
|
||||
fs::path conda_prefix = root_prefix;
|
||||
|
||||
// TODO check writable and add other potential dirs
|
||||
|
@ -40,7 +40,7 @@ namespace mamba
|
|||
std::vector<fs::path> pkgs_dirs = { root_prefix / "pkgs" };
|
||||
|
||||
bool use_index_cache = false;
|
||||
std::size_t local_repodata_ttl = 1; // take from header
|
||||
std::size_t local_repodata_ttl = 1; // take from header
|
||||
bool offline = false;
|
||||
bool quiet = false;
|
||||
bool json = false;
|
||||
|
@ -63,9 +63,9 @@ namespace mamba
|
|||
|
||||
int connect_timeout_secs = 10;
|
||||
// int read_timeout_secs = 60;
|
||||
int retry_timeout = 2; // seconds
|
||||
int retry_backoff = 3; // retry_timeout * retry_backoff
|
||||
int max_retries = 3; // max number of retries
|
||||
int retry_timeout = 2; // seconds
|
||||
int retry_backoff = 3; // retry_timeout * retry_backoff
|
||||
int max_retries = 3; // max number of retries
|
||||
|
||||
std::string env_prompt = "({default_env}) ";
|
||||
|
||||
|
@ -93,10 +93,9 @@ namespace mamba
|
|||
Context& operator=(Context&&) = delete;
|
||||
|
||||
private:
|
||||
|
||||
Context();
|
||||
~Context() = default;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif // MAMBA_CONTEXT_HPP
|
||||
#endif // MAMBA_CONTEXT_HPP
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <cassert>
|
||||
#include <string_view>
|
||||
|
||||
#include "util.hpp"
|
||||
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
|
||||
namespace fs = ghc::filesystem;
|
||||
|
@ -29,186 +31,189 @@ namespace fs = ghc::filesystem;
|
|||
|
||||
extern "C"
|
||||
{
|
||||
extern char **environ;
|
||||
extern char** environ;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
namespace env
|
||||
{
|
||||
constexpr inline const char* pathsep()
|
||||
namespace env
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return ";";
|
||||
#else
|
||||
return ":";
|
||||
#endif
|
||||
}
|
||||
|
||||
inline std::string get(const std::string& key)
|
||||
{
|
||||
const char* value = std::getenv(key.c_str());
|
||||
if (!value) return "";
|
||||
return value;
|
||||
}
|
||||
|
||||
inline bool set(const std::string& key, const std::string& value)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return SetEnvironmentVariable(key.c_str(), value.c_str());
|
||||
#else
|
||||
return setenv(key.c_str(), value.c_str(), 1) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline fs::path which(const std::string& exe)
|
||||
{
|
||||
// TODO maybe add a cache?
|
||||
if (std::getenv("PATH"))
|
||||
constexpr inline const char* pathsep()
|
||||
{
|
||||
std::string path = std::getenv("PATH");
|
||||
auto parts = split(path, pathsep());
|
||||
for (auto& p : parts)
|
||||
#ifdef _WIN32
|
||||
return ";";
|
||||
#else
|
||||
return ":";
|
||||
#endif
|
||||
}
|
||||
|
||||
inline std::string get(const std::string& key)
|
||||
{
|
||||
const char* value = std::getenv(key.c_str());
|
||||
if (!value)
|
||||
return "";
|
||||
return value;
|
||||
}
|
||||
|
||||
inline bool set(const std::string& key, const std::string& value)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return SetEnvironmentVariable(key.c_str(), value.c_str());
|
||||
#else
|
||||
return setenv(key.c_str(), value.c_str(), 1) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline fs::path which(const std::string& exe)
|
||||
{
|
||||
// TODO maybe add a cache?
|
||||
if (std::getenv("PATH"))
|
||||
{
|
||||
if (!fs::exists(p) || !fs::is_directory(p))
|
||||
std::string path = std::getenv("PATH");
|
||||
auto parts = mamba::split(path, pathsep());
|
||||
for (auto& p : parts)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (const auto & entry : fs::directory_iterator(p))
|
||||
{
|
||||
if (entry.path().filename() == exe)
|
||||
if (!fs::exists(p) || !fs::is_directory(p))
|
||||
{
|
||||
return entry.path();
|
||||
continue;
|
||||
}
|
||||
for (const auto& entry : fs::directory_iterator(p))
|
||||
{
|
||||
if (entry.path().filename() == exe)
|
||||
{
|
||||
return entry.path();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""; // empty path
|
||||
}
|
||||
|
||||
inline std::map<std::string, std::string> copy()
|
||||
{
|
||||
std::map<std::string, std::string> m;
|
||||
#ifndef _WIN32
|
||||
int i = 1;
|
||||
const char* c = *environ;
|
||||
for (; c; i++)
|
||||
{
|
||||
std::string_view s(c);
|
||||
auto pos = s.find("=");
|
||||
m[std::string(s.substr(0, pos))] = (pos != s.npos) ? std::string(s.substr(pos + 1)) : "";
|
||||
c = *(environ + i);
|
||||
}
|
||||
#else
|
||||
|
||||
// inspired by https://github.com/gennaroprota/breath/blob/0709a9f0fe4e745b1d9fc44ab65d92853820b515
|
||||
// /breath/environment/brt/dep/syst/windows/get_environment_map.cpp#L38-L80
|
||||
char* start = GetEnvironmentStrings();
|
||||
if (start == nullptr)
|
||||
{
|
||||
throw std::runtime_error("GetEnvironmentStrings() failed") ;
|
||||
return ""; // empty path
|
||||
}
|
||||
|
||||
char* current = start;
|
||||
while (*current != '\0')
|
||||
inline std::map<std::string, std::string> copy()
|
||||
{
|
||||
std::string_view s = current;
|
||||
auto pos = s.find("=");
|
||||
assert (pos != std::string_view::npos);
|
||||
std::string_view key = s.substr(0, pos) ;
|
||||
|
||||
if (!key.empty())
|
||||
std::map<std::string, std::string> m;
|
||||
#ifndef _WIN32
|
||||
int i = 1;
|
||||
const char* c = *environ;
|
||||
for (; c; i++)
|
||||
{
|
||||
std::string_view value = (pos != s.npos) ? s.substr(pos + 1) : "";
|
||||
m[std::string(key)] = value;
|
||||
std::string_view s(c);
|
||||
auto pos = s.find("=");
|
||||
m[std::string(s.substr(0, pos))]
|
||||
= (pos != s.npos) ? std::string(s.substr(pos + 1)) : "";
|
||||
c = *(environ + i);
|
||||
}
|
||||
current += s.size() + 1;
|
||||
#else
|
||||
|
||||
// inspired by
|
||||
// https://github.com/gennaroprota/breath/blob/0709a9f0fe4e745b1d9fc44ab65d92853820b515
|
||||
// /breath/environment/brt/dep/syst/windows/get_environment_map.cpp#L38-L80
|
||||
char* start = GetEnvironmentStrings();
|
||||
if (start == nullptr)
|
||||
{
|
||||
throw std::runtime_error("GetEnvironmentStrings() failed");
|
||||
}
|
||||
|
||||
char* current = start;
|
||||
while (*current != '\0')
|
||||
{
|
||||
std::string_view s = current;
|
||||
auto pos = s.find("=");
|
||||
assert(pos != std::string_view::npos);
|
||||
std::string_view key = s.substr(0, pos);
|
||||
|
||||
if (!key.empty())
|
||||
{
|
||||
std::string_view value = (pos != s.npos) ? s.substr(pos + 1) : "";
|
||||
m[std::string(key)] = value;
|
||||
}
|
||||
current += s.size() + 1;
|
||||
}
|
||||
#endif
|
||||
return m;
|
||||
}
|
||||
#endif
|
||||
return m;
|
||||
|
||||
|
||||
inline std::string platform()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
utsname un;
|
||||
int ret = uname(&un);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
throw std::runtime_error("uname() failed");
|
||||
}
|
||||
|
||||
return std::string(un.sysname);
|
||||
#else
|
||||
return "win32";
|
||||
#endif
|
||||
}
|
||||
|
||||
inline fs::path home_directory()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::string maybe_home = env::get("USERPROFILE");
|
||||
if (maybe_home.empty())
|
||||
{
|
||||
maybe_home = concat(env::get("HOMEDRIVE"), env::get("HOMEPATH"));
|
||||
}
|
||||
if (maybe_home.empty())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Cannot determine HOME (checked USERPROFILE, HOMEDRIVE and HOMEPATH env vars)");
|
||||
}
|
||||
#else
|
||||
std::string maybe_home = env::get("HOME");
|
||||
if (maybe_home.empty())
|
||||
{
|
||||
maybe_home = getpwuid(getuid())->pw_dir;
|
||||
}
|
||||
if (maybe_home.empty())
|
||||
{
|
||||
throw std::runtime_error("HOME not set.");
|
||||
}
|
||||
#endif
|
||||
return maybe_home;
|
||||
}
|
||||
|
||||
inline fs::path expand_user(const fs::path& path)
|
||||
{
|
||||
auto p = path.string();
|
||||
if (p[0] == '~')
|
||||
{
|
||||
p.replace(0, 1, home_directory());
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
inline bool is_admin()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return IsUserAnAdmin();
|
||||
#else
|
||||
return geteuid() == 0 || getegid() == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// inline fs::path expand_vars(const fs::path& path)
|
||||
// {
|
||||
// #ifndef _WIN32
|
||||
// wordexp_t w{};
|
||||
// std::unique_ptr<wordexp_t, void(*)(wordexp_t*)> hold{&w, ::wordfree};
|
||||
// ::wordexp(path.c_str(), &w, 0);
|
||||
// if (w.we_wordc != 1)
|
||||
// throw std::runtime_error("Cannot expand path: " + path.string());
|
||||
// fs::path result = fs::absolute(w.we_wordv[0]);
|
||||
// return result;
|
||||
// #else
|
||||
// // ExpandEnvironmentStringsW
|
||||
// #endif
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
inline std::string platform()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
utsname un;
|
||||
int ret = uname(&un);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
throw std::runtime_error("uname() failed");
|
||||
}
|
||||
|
||||
return std::string(un.sysname);
|
||||
#else
|
||||
return "win32";
|
||||
#endif
|
||||
}
|
||||
|
||||
inline fs::path home_directory()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::string maybe_home = env::get("USERPROFILE");
|
||||
if (maybe_home.empty())
|
||||
{
|
||||
maybe_home = concat(env::get("HOMEDRIVE"), env::get("HOMEPATH"));
|
||||
}
|
||||
if (maybe_home.empty())
|
||||
{
|
||||
throw std::runtime_error("Cannot determine HOME (checked USERPROFILE, HOMEDRIVE and HOMEPATH env vars)");
|
||||
}
|
||||
#else
|
||||
std::string maybe_home = env::get("HOME");
|
||||
if (maybe_home.empty())
|
||||
{
|
||||
maybe_home = getpwuid(getuid())->pw_dir;
|
||||
}
|
||||
if (maybe_home.empty())
|
||||
{
|
||||
throw std::runtime_error("HOME not set.");
|
||||
}
|
||||
#endif
|
||||
return maybe_home;
|
||||
}
|
||||
|
||||
inline fs::path expand_user(const fs::path& path)
|
||||
{
|
||||
auto p = path.string();
|
||||
if (p[0] == '~')
|
||||
{
|
||||
p.replace(0, 1, home_directory());
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
inline bool is_admin()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return IsUserAnAdmin();
|
||||
#else
|
||||
return geteuid() == 0 || getegid() == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// inline fs::path expand_vars(const fs::path& path)
|
||||
// {
|
||||
// #ifndef _WIN32
|
||||
// wordexp_t w{};
|
||||
// std::unique_ptr<wordexp_t, void(*)(wordexp_t*)> hold{&w, ::wordfree};
|
||||
// ::wordexp(path.c_str(), &w, 0);
|
||||
// if (w.we_wordc != 1)
|
||||
// throw std::runtime_error("Cannot expand path: " + path.string());
|
||||
// fs::path result = fs::absolute(w.we_wordv[0]);
|
||||
// return result;
|
||||
// #else
|
||||
// // ExpandEnvironmentStringsW
|
||||
// #endif
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,15 +7,18 @@
|
|||
#ifndef MAMBA_ENVIRONMENT_MANAGER
|
||||
#define MAMBA_ENVIRONMENT_MANAGER
|
||||
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "util.hpp"
|
||||
#include "environment.hpp"
|
||||
#include "output.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
const std::string PREFIX_MAGIC_FILE = "conda-meta/history";
|
||||
const char PREFIX_MAGIC_FILE[] = "conda-meta/history";
|
||||
|
||||
inline bool is_conda_environment(const fs::path& prefix)
|
||||
{
|
||||
|
@ -25,7 +28,6 @@ namespace mamba
|
|||
class EnvironmentsManager
|
||||
{
|
||||
public:
|
||||
|
||||
void register_env(const fs::path& location)
|
||||
{
|
||||
fs::path env_txt_file = get_environments_txt_file(env::home_directory());
|
||||
|
@ -37,12 +39,15 @@ namespace mamba
|
|||
try
|
||||
{
|
||||
fs::create_directories(env_txt_file.parent_path());
|
||||
} catch (...) {}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
std::string final_location_string = remove_trailing_slash(final_location);
|
||||
if (final_location_string.find("placehold_pl") != std::string::npos ||
|
||||
final_location_string.find("skeleton_") != std::string::npos)
|
||||
if (final_location_string.find("placehold_pl") != std::string::npos
|
||||
|| final_location_string.find("skeleton_") != std::string::npos)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -51,7 +56,8 @@ namespace mamba
|
|||
|
||||
for (auto& l : lines)
|
||||
{
|
||||
if (l == final_location_string) return;
|
||||
if (l == final_location_string)
|
||||
return;
|
||||
}
|
||||
|
||||
std::ofstream out(env_txt_file, std::ios::app);
|
||||
|
@ -60,11 +66,13 @@ namespace mamba
|
|||
{
|
||||
if (errno == EACCES || errno == EROFS || errno == ENOENT)
|
||||
{
|
||||
LOG_ERROR << "Could not register environment. " << env_txt_file << " not writeable or missing?";
|
||||
LOG_ERROR << "Could not register environment. " << env_txt_file
|
||||
<< " not writeable or missing?";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::system_error(errno, std::system_category(), "failed to open " + env_txt_file.string());
|
||||
throw std::system_error(
|
||||
errno, std::system_category(), "failed to open " + env_txt_file.string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +87,7 @@ namespace mamba
|
|||
std::size_t count = 0;
|
||||
for (auto& _ : fs::directory_iterator(meta_dir))
|
||||
{
|
||||
(void)_;
|
||||
(void) _;
|
||||
++count;
|
||||
}
|
||||
if (count > 1)
|
||||
|
@ -103,17 +111,19 @@ namespace mamba
|
|||
// if (on_win)
|
||||
// {
|
||||
// fs::path home_dir_dir = env::home_directory().parent_path();
|
||||
// search_dirs = tuple(join(home_dir_dir, d) for d in listdir(home_dir_dir))
|
||||
// search_dirs = tuple(join(home_dir_dir, d) for d in
|
||||
// listdir(home_dir_dir))
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// from pwd import getpwall
|
||||
// search_dirs = tuple(pwentry.pw_dir for pwentry in getpwall()) or (expand('~'),)
|
||||
// search_dirs = tuple(pwentry.pw_dir for pwentry in getpwall()) or
|
||||
// (expand('~'),)
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
{
|
||||
search_dirs = std::vector<fs::path> { env::home_directory() };
|
||||
search_dirs = std::vector<fs::path>{ env::home_directory() };
|
||||
}
|
||||
|
||||
std::set<fs::path> all_env_paths;
|
||||
|
@ -147,9 +157,8 @@ namespace mamba
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
std::set<std::string>
|
||||
clean_environments_txt(const fs::path& env_txt_file, const fs::path& location)
|
||||
std::set<std::string> clean_environments_txt(const fs::path& env_txt_file,
|
||||
const fs::path& location)
|
||||
{
|
||||
if (!fs::exists(env_txt_file))
|
||||
return {};
|
||||
|
@ -194,7 +203,6 @@ namespace mamba
|
|||
return home / ".conda" / "environments.txt";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,32 +7,35 @@
|
|||
#ifndef MAMBA_FETCH_HPP
|
||||
#define MAMBA_FETCH_HPP
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
extern "C"
|
||||
{
|
||||
#include <archive.h>
|
||||
#include <curl/curl.h>
|
||||
}
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "output.hpp"
|
||||
#include "validate.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <curl/curl.h>
|
||||
#include <archive.h>
|
||||
}
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
class DownloadTarget
|
||||
{
|
||||
public:
|
||||
|
||||
DownloadTarget() = default;
|
||||
DownloadTarget(const std::string& name, const std::string& url, const std::string& filename);
|
||||
DownloadTarget(const std::string& name,
|
||||
const std::string& url,
|
||||
const std::string& filename);
|
||||
~DownloadTarget();
|
||||
|
||||
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *self);
|
||||
static size_t header_callback(char *buffer, size_t size, size_t nitems, void *self);
|
||||
static size_t write_callback(char* ptr, size_t size, size_t nmemb, void* self);
|
||||
static size_t header_callback(char* buffer, size_t size, size_t nitems, void* self);
|
||||
|
||||
int progress_callback(void*, curl_off_t total_to_download, curl_off_t now_downloaded, curl_off_t, curl_off_t);
|
||||
int progress_callback(
|
||||
void*, curl_off_t total_to_download, curl_off_t now_downloaded, curl_off_t, curl_off_t);
|
||||
void set_mod_etag_headers(const nlohmann::json& mod_etag);
|
||||
void set_progress_bar(ProgressProxy progress_proxy);
|
||||
void set_expected_size(std::size_t size);
|
||||
|
@ -77,7 +80,6 @@ namespace mamba
|
|||
std::string etag, mod, cache_control;
|
||||
|
||||
private:
|
||||
|
||||
std::function<bool()> m_finalize_callback;
|
||||
|
||||
std::string m_name, m_filename, m_url;
|
||||
|
@ -106,7 +108,6 @@ namespace mamba
|
|||
class MultiDownloadTarget
|
||||
{
|
||||
public:
|
||||
|
||||
MultiDownloadTarget();
|
||||
~MultiDownloadTarget();
|
||||
|
||||
|
@ -115,12 +116,11 @@ namespace mamba
|
|||
bool download(bool failfast);
|
||||
|
||||
private:
|
||||
|
||||
std::vector<DownloadTarget*> m_targets;
|
||||
std::vector<DownloadTarget*> m_retry_targets;
|
||||
CURLM* m_handle;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif // MAMBA_FETCH_HPP
|
||||
#endif // MAMBA_FETCH_HPP
|
||||
|
|
|
@ -4,97 +4,100 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
|
||||
#ifndef MAMBA_FS_UTIL
|
||||
#define MAMBA_FS_UTIL
|
||||
|
||||
#include "util.hpp"
|
||||
#include <string>
|
||||
|
||||
#include "environment.hpp"
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace fs = ghc::filesystem;
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
namespace path
|
||||
{
|
||||
inline bool starts_with_home(const fs::path& p)
|
||||
{
|
||||
std::string path = p;
|
||||
return path[0] == '~' || starts_with(env::expand_user(path).string(), env::expand_user("~").string());
|
||||
}
|
||||
namespace path
|
||||
{
|
||||
inline bool starts_with_home(const fs::path& p)
|
||||
{
|
||||
std::string path = p;
|
||||
return path[0] == '~'
|
||||
|| starts_with(env::expand_user(path).string(), env::expand_user("~").string());
|
||||
}
|
||||
|
||||
// TODO more error handling
|
||||
inline void create_directories_sudo_safe(const fs::path& path)
|
||||
{
|
||||
if (fs::is_directory(path)) return;
|
||||
// TODO more error handling
|
||||
inline void create_directories_sudo_safe(const fs::path& path)
|
||||
{
|
||||
if (fs::is_directory(path))
|
||||
return;
|
||||
|
||||
fs::path base_dir = path.parent_path();
|
||||
if (!fs::is_directory(base_dir))
|
||||
{
|
||||
create_directories_sudo_safe(base_dir);
|
||||
}
|
||||
fs::create_directory(path);
|
||||
fs::path base_dir = path.parent_path();
|
||||
if (!fs::is_directory(base_dir))
|
||||
{
|
||||
create_directories_sudo_safe(base_dir);
|
||||
}
|
||||
fs::create_directory(path);
|
||||
|
||||
#ifndef _WIN32
|
||||
// set permissions to 0o2775
|
||||
fs::permissions(path, fs::perms::set_gid |
|
||||
fs::perms::owner_all |
|
||||
fs::perms::group_all |
|
||||
fs::perms::others_read | fs::perms::others_exec);
|
||||
#endif
|
||||
}
|
||||
#ifndef _WIN32
|
||||
// set permissions to 0o2775
|
||||
fs::permissions(path,
|
||||
fs::perms::set_gid | fs::perms::owner_all | fs::perms::group_all
|
||||
| fs::perms::others_read | fs::perms::others_exec);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool touch(fs::path path, bool mkdir=false, bool sudo_safe=false)
|
||||
{
|
||||
// TODO error handling!
|
||||
path = env::expand_user(path);
|
||||
if (lexists(path))
|
||||
{
|
||||
fs::last_write_time(path, fs::file_time_type::clock::now());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dirpath = path.parent_path();
|
||||
if (!fs::is_directory(dirpath) && mkdir)
|
||||
{
|
||||
if (sudo_safe)
|
||||
{
|
||||
create_directories_sudo_safe(dirpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
fs::create_directories(dirpath);
|
||||
}
|
||||
}
|
||||
// directory exists, now create empty file
|
||||
std::ofstream(path, std::ios::out);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
inline bool touch(fs::path path, bool mkdir = false, bool sudo_safe = false)
|
||||
{
|
||||
// TODO error handling!
|
||||
path = env::expand_user(path);
|
||||
if (lexists(path))
|
||||
{
|
||||
fs::last_write_time(path, fs::file_time_type::clock::now());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dirpath = path.parent_path();
|
||||
if (!fs::is_directory(dirpath) && mkdir)
|
||||
{
|
||||
if (sudo_safe)
|
||||
{
|
||||
create_directories_sudo_safe(dirpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
fs::create_directories(dirpath);
|
||||
}
|
||||
}
|
||||
// directory exists, now create empty file
|
||||
std::ofstream(path, std::ios::out);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_writable(const fs::path& path)
|
||||
{
|
||||
if (fs::is_directory(path.parent_path()))
|
||||
{
|
||||
bool path_existed = lexists(path);
|
||||
std::ofstream test;
|
||||
test.open(path);
|
||||
bool is_writable = test.is_open();
|
||||
if (!path_existed)
|
||||
{
|
||||
test.close();
|
||||
fs::remove(path);
|
||||
}
|
||||
return is_writable;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Cannot check file path at " + path.string() + " for accessibility.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
inline bool is_writable(const fs::path& path)
|
||||
{
|
||||
if (fs::is_directory(path.parent_path()))
|
||||
{
|
||||
bool path_existed = lexists(path);
|
||||
std::ofstream test;
|
||||
test.open(path);
|
||||
bool is_writable = test.is_open();
|
||||
if (!path_existed)
|
||||
{
|
||||
test.close();
|
||||
fs::remove(path);
|
||||
}
|
||||
return is_writable;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Cannot check file path at " + path.string()
|
||||
+ " for accessibility.");
|
||||
}
|
||||
}
|
||||
} // namespace path
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
#define MAMBA_GRAPH_UTIL_HPP
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
// Simplified implementation of a directed graph
|
||||
// where a path exists between each node and the
|
||||
// first one (you can think of it as a tree with
|
||||
|
@ -22,7 +22,6 @@ namespace mamba
|
|||
class graph
|
||||
{
|
||||
public:
|
||||
|
||||
using node = T;
|
||||
using node_id = size_t;
|
||||
using node_list = std::vector<node>;
|
||||
|
@ -41,7 +40,6 @@ namespace mamba
|
|||
void depth_first_search(V& visitor, node_id start = node_id(0)) const;
|
||||
|
||||
private:
|
||||
|
||||
enum class color
|
||||
{
|
||||
white,
|
||||
|
@ -65,35 +63,47 @@ namespace mamba
|
|||
class default_visitor
|
||||
{
|
||||
public:
|
||||
|
||||
using graph_type = G;
|
||||
using node_id = typename graph_type::node_id;
|
||||
|
||||
void start_node(node_id, const G&) {}
|
||||
void finish_node(node_id, const G&) {}
|
||||
void start_node(node_id, const G&)
|
||||
{
|
||||
}
|
||||
void finish_node(node_id, const G&)
|
||||
{
|
||||
}
|
||||
|
||||
void start_edge(node_id, node_id, const G&) {}
|
||||
void tree_edge(node_id, node_id, const G&) {}
|
||||
void back_edge(node_id, node_id, const G&) {}
|
||||
void forward_or_cross_edge(node_id, node_id, const G&) {}
|
||||
void finish_edge(node_id, node_id, const G&) {}
|
||||
void start_edge(node_id, node_id, const G&)
|
||||
{
|
||||
}
|
||||
void tree_edge(node_id, node_id, const G&)
|
||||
{
|
||||
}
|
||||
void back_edge(node_id, node_id, const G&)
|
||||
{
|
||||
}
|
||||
void forward_or_cross_edge(node_id, node_id, const G&)
|
||||
{
|
||||
}
|
||||
void finish_edge(node_id, node_id, const G&)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <class G>
|
||||
class predecessor_recorder : private default_visitor<G>
|
||||
{
|
||||
public:
|
||||
|
||||
using base_type = default_visitor<G>;
|
||||
using graph_type = typename base_type::graph_type;
|
||||
using node_id = typename base_type::node_it;
|
||||
using predecessor_map = std::map<node_id, node_id>;
|
||||
|
||||
using base_type::start_node;
|
||||
using base_type::finish_node;
|
||||
using base_type::start_edge;
|
||||
using base_type::back_edge;
|
||||
using base_type::finish_node;
|
||||
using base_type::forward_or_cross_edge;
|
||||
using base_type::start_edge;
|
||||
using base_type::start_node;
|
||||
|
||||
void tree_edge(node_id from, node_id to, const G&);
|
||||
void finish_edge(node_id id, const G&);
|
||||
|
@ -101,7 +111,6 @@ namespace mamba
|
|||
const predecessor_map& get_predecessors() const;
|
||||
|
||||
private:
|
||||
|
||||
predecessor_map m_pred;
|
||||
};
|
||||
|
||||
|
@ -109,7 +118,6 @@ namespace mamba
|
|||
class composite_visitor
|
||||
{
|
||||
public:
|
||||
|
||||
using graph_type = G;
|
||||
using node_id = typename G::node_id;
|
||||
|
||||
|
@ -125,7 +133,6 @@ namespace mamba
|
|||
void finish_edge(node_id, node_id, const G&);
|
||||
|
||||
private:
|
||||
|
||||
V1<G> m_v1;
|
||||
V2<G> m_v2;
|
||||
};
|
||||
|
@ -141,7 +148,7 @@ namespace mamba
|
|||
}
|
||||
|
||||
template <class T>
|
||||
inline auto graph<T>::get_edge_list(node_id id) const -> const edge_list&
|
||||
inline auto graph<T>::get_edge_list(node_id id) const -> const edge_list&
|
||||
{
|
||||
return m_adjacency_list[id];
|
||||
}
|
||||
|
@ -186,11 +193,13 @@ namespace mamba
|
|||
|
||||
template <class T>
|
||||
template <class V>
|
||||
inline void graph<T>::depth_first_search_impl(V& visitor, node_id node, color_list& colors) const
|
||||
inline void graph<T>::depth_first_search_impl(V& visitor,
|
||||
node_id node,
|
||||
color_list& colors) const
|
||||
{
|
||||
colors[node] = color::gray;
|
||||
visitor.start_node(node, *this);
|
||||
for (auto child: m_adjacency_list[node])
|
||||
for (auto child : m_adjacency_list[node])
|
||||
{
|
||||
visitor.start_edge(node, child, *this);
|
||||
if (colors[child] == color::white)
|
||||
|
@ -240,7 +249,8 @@ namespace mamba
|
|||
|
||||
template <class G, template <class> class V1, template <class> class V2>
|
||||
inline composite_visitor<G, V1, V2>::composite_visitor(V1<G> v1, V2<G> v2)
|
||||
: m_v1(v1), m_v2(v2)
|
||||
: m_v1(v1)
|
||||
, m_v2(v2)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -280,7 +290,9 @@ namespace mamba
|
|||
}
|
||||
|
||||
template <class G, template <class> class V1, template <class> class V2>
|
||||
inline void composite_visitor<G, V1, V2>::forward_or_cross_edge(node_id from, node_id to, const G& g)
|
||||
inline void composite_visitor<G, V1, V2>::forward_or_cross_edge(node_id from,
|
||||
node_id to,
|
||||
const G& g)
|
||||
{
|
||||
m_v1.forward_or_cross_edge(from, to, g);
|
||||
m_v2.forward_or_cross_edge(from, to, g);
|
||||
|
@ -292,6 +304,6 @@ namespace mamba
|
|||
m_v1.finish_edge(from, to, g);
|
||||
m_v2.finish_edge(from, to, g);
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
#endif // INCLUDE_GRAPH_UTIL_HPP
|
||||
|
|
|
@ -7,78 +7,70 @@
|
|||
#ifndef MAMBA_HISTORY
|
||||
#define MAMBA_HISTORY
|
||||
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
|
||||
#include "output.hpp"
|
||||
// #include "prefix_data.hpp"
|
||||
#include "match_spec.hpp"
|
||||
#include "output.hpp"
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
|
||||
namespace fs = ghc::filesystem;
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
class History
|
||||
{
|
||||
public:
|
||||
|
||||
// History(const std::shared_ptr<PrefixData>& prefix)
|
||||
// : m_prefix_data(prefix)
|
||||
// {
|
||||
// }
|
||||
|
||||
History(const std::string& prefix);
|
||||
|
||||
struct ParseResult
|
||||
class History
|
||||
{
|
||||
std::string head_line;
|
||||
std::set<std::string> diff;
|
||||
std::vector<std::string> comments;
|
||||
};
|
||||
public:
|
||||
History(const std::string& prefix);
|
||||
|
||||
struct UserRequest
|
||||
{
|
||||
static UserRequest prefilled()
|
||||
struct ParseResult
|
||||
{
|
||||
UserRequest ur;
|
||||
std::time_t t = std::time(nullptr);
|
||||
char mbstr[100];
|
||||
if (std::strftime(mbstr, sizeof(mbstr), "%Y-%m-%d %H:%M:%S", std::localtime(&t)))
|
||||
std::string head_line;
|
||||
std::set<std::string> diff;
|
||||
std::vector<std::string> comments;
|
||||
};
|
||||
|
||||
struct UserRequest
|
||||
{
|
||||
static UserRequest prefilled()
|
||||
{
|
||||
ur.date = mbstr;
|
||||
UserRequest ur;
|
||||
std::time_t t = std::time(nullptr);
|
||||
char mbstr[100];
|
||||
if (std::strftime(mbstr, sizeof(mbstr), "%Y-%m-%d %H:%M:%S", std::localtime(&t)))
|
||||
{
|
||||
ur.date = mbstr;
|
||||
}
|
||||
ur.cmd = Context::instance().current_command;
|
||||
ur.conda_version = Context::instance().conda_version;
|
||||
return ur;
|
||||
}
|
||||
ur.cmd = Context::instance().current_command;
|
||||
ur.conda_version = Context::instance().conda_version;
|
||||
return ur;
|
||||
}
|
||||
|
||||
std::string date;
|
||||
std::string cmd;
|
||||
std::string conda_version;
|
||||
std::string date;
|
||||
std::string cmd;
|
||||
std::string conda_version;
|
||||
|
||||
std::vector<std::string> unlink_dists;
|
||||
std::vector<std::string> link_dists;
|
||||
std::vector<std::string> unlink_dists;
|
||||
std::vector<std::string> link_dists;
|
||||
|
||||
std::vector<std::string> update;
|
||||
std::vector<std::string> remove;
|
||||
std::vector<std::string> neutered;
|
||||
std::vector<std::string> update;
|
||||
std::vector<std::string> remove;
|
||||
std::vector<std::string> neutered;
|
||||
};
|
||||
|
||||
std::vector<ParseResult> parse();
|
||||
bool parse_comment_line(const std::string& line, UserRequest& req);
|
||||
std::vector<UserRequest> get_user_requests();
|
||||
std::unordered_map<std::string, MatchSpec> get_requested_specs_map();
|
||||
void add_entry(const History::UserRequest& entry);
|
||||
|
||||
std::string m_prefix;
|
||||
fs::path m_history_file_path;
|
||||
};
|
||||
|
||||
std::vector<ParseResult> parse();
|
||||
bool parse_comment_line(const std::string& line, UserRequest& req);
|
||||
std::vector<UserRequest> get_user_requests();
|
||||
std::unordered_map<std::string, MatchSpec> get_requested_specs_map();
|
||||
void add_entry(const History::UserRequest& entry);
|
||||
|
||||
// std::shared_ptr<PrefixData> m_prefix_data;
|
||||
std::string m_prefix;
|
||||
fs::path m_history_file_path;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,64 +9,68 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
|
||||
#include "transaction.hpp"
|
||||
#include "match_spec.hpp"
|
||||
#include "transaction_context.hpp"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "package_paths.hpp"
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
#include "transaction.hpp"
|
||||
#include "transaction_context.hpp"
|
||||
|
||||
namespace fs = ghc::filesystem;
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
struct python_entry_point_parsed
|
||||
{
|
||||
std::string command, module, func;
|
||||
};
|
||||
|
||||
struct python_entry_point_parsed
|
||||
{
|
||||
std::string command, module, func;
|
||||
};
|
||||
class UnlinkPackage
|
||||
{
|
||||
public:
|
||||
UnlinkPackage(const PackageInfo& pkg_info,
|
||||
const fs::path& cache_path,
|
||||
TransactionContext* context);
|
||||
|
||||
class UnlinkPackage
|
||||
{
|
||||
public:
|
||||
UnlinkPackage(const PackageInfo& pkg_info, const fs::path& cache_path, TransactionContext* context);
|
||||
bool execute();
|
||||
bool undo();
|
||||
|
||||
bool execute();
|
||||
bool undo();
|
||||
private:
|
||||
bool unlink_path(const nlohmann::json& path_data);
|
||||
|
||||
private:
|
||||
PackageInfo m_pkg_info;
|
||||
fs::path m_cache_path;
|
||||
std::string m_specifier;
|
||||
TransactionContext* m_context;
|
||||
};
|
||||
|
||||
bool unlink_path(const nlohmann::json& path_data);
|
||||
class LinkPackage
|
||||
{
|
||||
public:
|
||||
LinkPackage(const PackageInfo& pkg_info,
|
||||
const fs::path& cache_path,
|
||||
TransactionContext* context);
|
||||
|
||||
PackageInfo m_pkg_info;
|
||||
fs::path m_cache_path;
|
||||
std::string m_specifier;
|
||||
TransactionContext* m_context;
|
||||
};
|
||||
bool execute();
|
||||
bool undo();
|
||||
|
||||
class LinkPackage
|
||||
{
|
||||
public:
|
||||
private:
|
||||
std::tuple<std::string, std::string> link_path(const PathData& path_data,
|
||||
bool noarch_python);
|
||||
std::vector<fs::path> compile_pyc_files(const std::vector<fs::path>& py_files);
|
||||
auto create_python_entry_point(const fs::path& path,
|
||||
const python_entry_point_parsed& entry_point);
|
||||
|
||||
LinkPackage(const PackageInfo& pkg_info, const fs::path& cache_path, TransactionContext* context);
|
||||
PackageInfo m_pkg_info;
|
||||
fs::path m_cache_path;
|
||||
fs::path m_source;
|
||||
TransactionContext* m_context;
|
||||
};
|
||||
|
||||
bool execute();
|
||||
bool undo();
|
||||
|
||||
private:
|
||||
|
||||
std::tuple<std::string, std::string> link_path(const PathData& path_data, bool noarch_python);
|
||||
std::vector<fs::path> compile_pyc_files(const std::vector<fs::path>& py_files);
|
||||
auto create_python_entry_point(const fs::path& path, const python_entry_point_parsed& entry_point);
|
||||
|
||||
PackageInfo m_pkg_info;
|
||||
fs::path m_cache_path;
|
||||
fs::path m_source;
|
||||
TransactionContext* m_context;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace mamba
|
||||
|
@ -16,7 +17,6 @@ namespace mamba
|
|||
class MatchSpec
|
||||
{
|
||||
public:
|
||||
|
||||
MatchSpec() = default;
|
||||
MatchSpec(const std::string& i_spec);
|
||||
|
||||
|
@ -43,6 +43,6 @@ namespace mamba
|
|||
std::unordered_map<std::string, std::string> brackets;
|
||||
std::unordered_map<std::string, std::string> parens;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,35 +7,50 @@
|
|||
#ifndef MAMBA_OUTPUT_HPP
|
||||
#define MAMBA_OUTPUT_HPP
|
||||
|
||||
#include <string_view>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "context.hpp"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#define ENUM_FLAG_OPERATOR(T,X) inline T operator X (T lhs, T rhs) { return (T) (static_cast<std::underlying_type_t <T>>(lhs) X static_cast<std::underlying_type_t <T>>(rhs)); }
|
||||
#define ENUM_FLAGS(T) \
|
||||
enum class T; \
|
||||
inline T operator ~ (T t) { return (T) (~static_cast<std::underlying_type_t <T>>(t)); } \
|
||||
ENUM_FLAG_OPERATOR(T,|) \
|
||||
ENUM_FLAG_OPERATOR(T,^) \
|
||||
ENUM_FLAG_OPERATOR(T,&) \
|
||||
enum class T
|
||||
#define ENUM_FLAG_OPERATOR(T, X) \
|
||||
inline T operator X(T lhs, T rhs) \
|
||||
{ \
|
||||
return (T)(static_cast<std::underlying_type_t<T>>(lhs) \
|
||||
X static_cast<std::underlying_type_t<T>>(rhs)); \
|
||||
}
|
||||
#define ENUM_FLAGS(T) \
|
||||
enum class T; \
|
||||
inline T operator~(T t) \
|
||||
{ \
|
||||
return (T)(~static_cast<std::underlying_type_t<T>>(t)); \
|
||||
} \
|
||||
ENUM_FLAG_OPERATOR(T, |) \
|
||||
ENUM_FLAG_OPERATOR(T, ^) \
|
||||
ENUM_FLAG_OPERATOR(T, &) \
|
||||
enum class T
|
||||
|
||||
#define PREFIX_LENGTH 25
|
||||
|
||||
namespace cursor
|
||||
{
|
||||
class CursorMovementTriple {
|
||||
class CursorMovementTriple
|
||||
{
|
||||
public:
|
||||
CursorMovementTriple(const char* esc, int n, const char* mod)
|
||||
: m_esc(esc), m_mod(mod), m_n(n)
|
||||
{}
|
||||
: m_esc(esc)
|
||||
, m_mod(mod)
|
||||
, m_n(n)
|
||||
{
|
||||
}
|
||||
|
||||
const char* m_esc;
|
||||
const char* m_mod;
|
||||
|
@ -48,11 +63,13 @@ namespace cursor
|
|||
return o;
|
||||
}
|
||||
|
||||
class CursorMod {
|
||||
class CursorMod
|
||||
{
|
||||
public:
|
||||
CursorMod(const char* mod)
|
||||
: m_mod(mod)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o)
|
||||
{
|
||||
|
@ -112,20 +129,19 @@ namespace cursor
|
|||
{
|
||||
return CursorMod("\x1b[?25l");
|
||||
}
|
||||
}
|
||||
} // namespace cursor
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
std::string cut_repo_name(const std::string& reponame);
|
||||
|
||||
namespace printers
|
||||
{
|
||||
|
||||
enum class format : std::size_t {
|
||||
none = 0,
|
||||
red = 1 << 1,
|
||||
green = 1 << 2,
|
||||
enum class format : std::size_t
|
||||
{
|
||||
none = 0,
|
||||
red = 1 << 1,
|
||||
green = 1 << 2,
|
||||
yellow = 1 << 3
|
||||
};
|
||||
|
||||
|
@ -139,12 +155,12 @@ namespace mamba
|
|||
inline FormattedString(const std::string& i)
|
||||
: s(i)
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
inline FormattedString(const char* i)
|
||||
: s(i)
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
inline std::size_t size() const
|
||||
{
|
||||
|
@ -154,21 +170,21 @@ namespace mamba
|
|||
|
||||
enum class alignment : std::size_t
|
||||
{
|
||||
left = 1 << 1,
|
||||
left = 1 << 1,
|
||||
right = 1 << 2,
|
||||
fill = 1 << 3
|
||||
fill = 1 << 3
|
||||
};
|
||||
|
||||
class Table
|
||||
{
|
||||
public:
|
||||
|
||||
Table(const std::vector<FormattedString>& header);
|
||||
|
||||
void set_alignment(const std::vector<alignment>& a);
|
||||
void set_padding(const std::vector<int>& p);
|
||||
void add_row(const std::vector<FormattedString>& r);
|
||||
void add_rows(const std::string& header, const std::vector<std::vector<FormattedString>>& rs);
|
||||
void add_rows(const std::string& header,
|
||||
const std::vector<std::vector<FormattedString>>& rs);
|
||||
|
||||
std::ostream& print(std::ostream& out);
|
||||
|
||||
|
@ -178,18 +194,16 @@ namespace mamba
|
|||
std::vector<int> m_padding;
|
||||
std::vector<std::vector<FormattedString>> m_table;
|
||||
};
|
||||
}
|
||||
} // namespace printers
|
||||
|
||||
// The next two functions / classes were ported from the awesome indicators library
|
||||
// by p-ranav (MIT License)
|
||||
// https://github.com/p-ranav/indicators
|
||||
std::ostream& write_duration(std::ostream &os, std::chrono::nanoseconds ns);
|
||||
// The next two functions / classes were ported from the awesome indicators
|
||||
// library by p-ranav (MIT License) https://github.com/p-ranav/indicators
|
||||
std::ostream& write_duration(std::ostream& os, std::chrono::nanoseconds ns);
|
||||
int get_console_width();
|
||||
|
||||
class ProgressScaleWriter
|
||||
{
|
||||
public:
|
||||
|
||||
inline ProgressScaleWriter(int bar_width,
|
||||
const std::string& fill,
|
||||
const std::string& lead,
|
||||
|
@ -198,7 +212,6 @@ namespace mamba
|
|||
std::ostream& write(std::ostream& os, std::size_t progress) const;
|
||||
|
||||
private:
|
||||
|
||||
int m_bar_width;
|
||||
std::string m_fill;
|
||||
std::string m_lead;
|
||||
|
@ -208,7 +221,6 @@ namespace mamba
|
|||
class ProgressBar
|
||||
{
|
||||
public:
|
||||
|
||||
ProgressBar(const std::string& prefix);
|
||||
|
||||
void set_start();
|
||||
|
@ -220,7 +232,6 @@ namespace mamba
|
|||
const std::string& prefix() const;
|
||||
|
||||
private:
|
||||
|
||||
std::chrono::nanoseconds m_elapsed_ns;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
|
||||
|
||||
|
@ -232,7 +243,6 @@ namespace mamba
|
|||
class ProgressProxy
|
||||
{
|
||||
public:
|
||||
|
||||
ProgressProxy() = default;
|
||||
~ProgressProxy() = default;
|
||||
|
||||
|
@ -247,7 +257,6 @@ namespace mamba
|
|||
void mark_as_completed(const std::string_view& final_message = "");
|
||||
|
||||
private:
|
||||
|
||||
ProgressProxy(ProgressBar* ptr, std::size_t idx);
|
||||
|
||||
ProgressBar* p_bar;
|
||||
|
@ -261,7 +270,6 @@ namespace mamba
|
|||
class ConsoleStream : public std::stringstream
|
||||
{
|
||||
public:
|
||||
|
||||
ConsoleStream() = default;
|
||||
~ConsoleStream();
|
||||
};
|
||||
|
@ -269,7 +277,6 @@ namespace mamba
|
|||
class Console
|
||||
{
|
||||
public:
|
||||
|
||||
Console(const Console&) = delete;
|
||||
Console& operator=(const Console&) = delete;
|
||||
|
||||
|
@ -279,14 +286,13 @@ namespace mamba
|
|||
static Console& instance();
|
||||
|
||||
static ConsoleStream stream();
|
||||
static void print(const std::string_view& str, bool force_print=false);
|
||||
static bool prompt(const std::string_view& message, char fallback='_');
|
||||
static void print(const std::string_view& str, bool force_print = false);
|
||||
static bool prompt(const std::string_view& message, char fallback = '_');
|
||||
|
||||
ProgressProxy add_progress_bar(const std::string& name);
|
||||
void init_multi_progress();
|
||||
|
||||
private:
|
||||
|
||||
using progress_bar_ptr = std::unique_ptr<ProgressBar>;
|
||||
|
||||
Console();
|
||||
|
@ -330,7 +336,6 @@ namespace mamba
|
|||
class MessageLogger
|
||||
{
|
||||
public:
|
||||
|
||||
MessageLogger(const char* file, int line, LogSeverity severity);
|
||||
~MessageLogger();
|
||||
|
||||
|
@ -339,18 +344,15 @@ namespace mamba
|
|||
static LogSeverity& global_log_severity();
|
||||
|
||||
private:
|
||||
|
||||
std::string m_file;
|
||||
int m_line;
|
||||
LogSeverity m_severity;
|
||||
std::stringstream m_stream;
|
||||
|
||||
};
|
||||
|
||||
class JsonLogger
|
||||
{
|
||||
public:
|
||||
|
||||
JsonLogger(const JsonLogger&) = delete;
|
||||
JsonLogger& operator=(const JsonLogger&) = delete;
|
||||
|
||||
|
@ -367,14 +369,13 @@ namespace mamba
|
|||
void json_up();
|
||||
|
||||
private:
|
||||
|
||||
JsonLogger();
|
||||
~JsonLogger() = default;
|
||||
|
||||
std::string json_hier;
|
||||
unsigned int json_index;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#undef ERROR
|
||||
#undef WARNING
|
||||
|
@ -387,4 +388,4 @@ namespace mamba
|
|||
#define LOG_ERROR LOG(mamba::LogSeverity::error)
|
||||
#define LOG_FATAL LOG(mamba::LogSeverity::fatal)
|
||||
|
||||
#endif // MAMBA_OUTPUT_HPP
|
||||
#endif // MAMBA_OUTPUT_HPP
|
||||
|
|
|
@ -7,14 +7,15 @@
|
|||
#ifndef MAMBA_PACKAGE_CACHE
|
||||
#define MAMBA_PACKAGE_CACHE
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "output.hpp"
|
||||
#include "context.hpp"
|
||||
#include "fsutil.hpp"
|
||||
#include "environment.hpp"
|
||||
#include "fsutil.hpp"
|
||||
#include "output.hpp"
|
||||
#include "package_info.hpp"
|
||||
|
||||
#define PACKAGE_CACHE_MAGIC_FILE "urls.txt"
|
||||
|
@ -33,7 +34,6 @@ namespace mamba
|
|||
class PackageCacheData
|
||||
{
|
||||
public:
|
||||
|
||||
PackageCacheData(const fs::path& pkgs_dir);
|
||||
|
||||
bool create_directory();
|
||||
|
@ -46,7 +46,6 @@ namespace mamba
|
|||
static PackageCacheData first_writable(const std::vector<fs::path>* pkgs_dirs = nullptr);
|
||||
|
||||
private:
|
||||
|
||||
void check_writable();
|
||||
|
||||
std::map<std::string, bool> m_valid_cache;
|
||||
|
@ -65,6 +64,6 @@ namespace mamba
|
|||
private:
|
||||
std::vector<PackageCacheData> m_caches;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
#ifndef MAMBA_PACKAGE_HANDLING_HPP
|
||||
#define MAMBA_PACKAGE_HANDLING_HPP
|
||||
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
|
||||
namespace fs = ghc::filesystem;
|
||||
|
@ -15,10 +18,14 @@ namespace fs = ghc::filesystem;
|
|||
namespace mamba
|
||||
{
|
||||
void extract_archive(const fs::path& file, const fs::path& destination);
|
||||
void extract_conda(const fs::path& file, const fs::path& dest_dir, const std::vector<std::string>& parts = {"info", "pkg"});
|
||||
void split_package_extension(const std::string& file, std::string& name, std::string& extension);
|
||||
void extract_conda(const fs::path& file,
|
||||
const fs::path& dest_dir,
|
||||
const std::vector<std::string>& parts = { "info", "pkg" });
|
||||
void split_package_extension(const std::string& file,
|
||||
std::string& name,
|
||||
std::string& extension);
|
||||
fs::path strip_package_extension(const std::string& file);
|
||||
fs::path extract(const fs::path& file);
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif // MAMBA_PACKAGE_HANDLING_HPP
|
||||
#endif // MAMBA_PACKAGE_HANDLING_HPP
|
||||
|
|
|
@ -7,15 +7,17 @@
|
|||
#ifndef MAMBA_PACKAGE_INFO
|
||||
#define MAMBA_PACKAGE_INFO
|
||||
|
||||
#include <string>
|
||||
|
||||
extern "C" {
|
||||
#include <solv/solvable.h>
|
||||
#include <solv/pool.h>
|
||||
#include <solv/repo.h>
|
||||
#include <solv/poolid.h>
|
||||
extern "C"
|
||||
{
|
||||
#include <solv/pool.h>
|
||||
#include <solv/poolid.h>
|
||||
#include <solv/repo.h>
|
||||
#include <solv/solvable.h>
|
||||
}
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
namespace mamba
|
||||
|
@ -23,9 +25,8 @@ namespace mamba
|
|||
class PackageInfo
|
||||
{
|
||||
public:
|
||||
|
||||
using field_getter = std::function<std::string (const PackageInfo&)>;
|
||||
using compare_fun = std::function<bool (const PackageInfo&, const PackageInfo&)>;
|
||||
using field_getter = std::function<std::string(const PackageInfo&)>;
|
||||
using compare_fun = std::function<bool(const PackageInfo&, const PackageInfo&)>;
|
||||
|
||||
static field_getter get_field_getter(const std::string& name);
|
||||
static compare_fun less(const std::string& member);
|
||||
|
@ -34,8 +35,10 @@ namespace mamba
|
|||
PackageInfo(Solvable* s);
|
||||
PackageInfo(nlohmann::json&& j);
|
||||
PackageInfo(const std::string& name);
|
||||
PackageInfo(const std::string& name, const std::string& version,
|
||||
const std::string build_string, std::size_t build_number);
|
||||
PackageInfo(const std::string& name,
|
||||
const std::string& version,
|
||||
const std::string build_string,
|
||||
std::size_t build_number);
|
||||
|
||||
nlohmann::json json() const;
|
||||
std::string str() const;
|
||||
|
@ -57,6 +60,6 @@ namespace mamba
|
|||
std::vector<std::string> depends;
|
||||
std::vector<std::string> constrains;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,19 +7,22 @@
|
|||
#ifndef MAMBA_READ_PATHS_HPP
|
||||
#define MAMBA_READ_PATHS_HPP
|
||||
|
||||
#include "util.hpp"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
const std::string PREFIX_PLACEHOLDER_1("/opt/anaconda1anaconda2");
|
||||
// this is intentionally split into parts, such that running
|
||||
// this program on itself will leave it unchanged
|
||||
const std::string PREFIX_PLACEHOLDER_2("anaconda3");
|
||||
#include "util.hpp"
|
||||
|
||||
const char PREFIX_PLACEHOLDER_1[] = "/opt/anaconda1anaconda2";
|
||||
// this is intentionally split into parts, such that running
|
||||
// this program on itself will leave it unchanged
|
||||
const char PREFIX_PLACEHOLDER_2[] = "anaconda3";
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
struct PrefixFileParse {
|
||||
struct PrefixFileParse
|
||||
{
|
||||
std::string placeholder;
|
||||
std::string file_mode;
|
||||
std::string file_path;
|
||||
|
@ -62,6 +65,6 @@ namespace mamba
|
|||
std::map<std::string, PrefixFileParse> read_has_prefix(const fs::path& path);
|
||||
std::set<std::string> read_no_link(const fs::path& info_dir);
|
||||
std::vector<PathData> read_paths(const fs::path& directory);
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
extern "C"
|
||||
{
|
||||
#include "solv/pool.h"
|
||||
#include "solv/pool.h"
|
||||
}
|
||||
|
||||
namespace mamba
|
||||
|
@ -19,7 +19,6 @@ namespace mamba
|
|||
class MPool
|
||||
{
|
||||
public:
|
||||
|
||||
MPool();
|
||||
~MPool();
|
||||
|
||||
|
@ -34,9 +33,8 @@ namespace mamba
|
|||
operator Pool*();
|
||||
|
||||
private:
|
||||
|
||||
Pool* m_pool;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif // MAMBA_POOL_HPP
|
||||
#endif // MAMBA_POOL_HPP
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
#ifndef MAMBA_PREFIX_DATA_HPP
|
||||
#define MAMBA_PREFIX_DATA_HPP
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "package_info.hpp"
|
||||
#include "history.hpp"
|
||||
#include "package_info.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
|
@ -33,6 +34,6 @@ namespace mamba
|
|||
std::unordered_map<std::string, PackageInfo> m_package_records;
|
||||
fs::path m_prefix_path;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,38 +7,45 @@
|
|||
#ifndef MAMBA_QUERY_HPP
|
||||
#define MAMBA_QUERY_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "graph_util.hpp"
|
||||
#include "output.hpp"
|
||||
#include "package_info.hpp"
|
||||
#include "pool.hpp"
|
||||
#include "graph_util.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "solv/repo.h"
|
||||
#include "solv/conda.h"
|
||||
#include "solv/solver.h"
|
||||
#include "solv/selection.h"
|
||||
#include "solv/conda.h"
|
||||
#include "solv/repo.h"
|
||||
#include "solv/selection.h"
|
||||
#include "solv/solver.h"
|
||||
}
|
||||
|
||||
namespace nl = nlohmann;
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
void print_dep_graph(std::ostream& out, Solvable* s, const std::string& solv_str, int level, int max_level, bool last, const std::string& prefix);
|
||||
void print_dep_graph(std::ostream& out,
|
||||
Solvable* s,
|
||||
const std::string& solv_str,
|
||||
int level,
|
||||
int max_level,
|
||||
bool last,
|
||||
const std::string& prefix);
|
||||
|
||||
class query_result;
|
||||
|
||||
class Query
|
||||
{
|
||||
public:
|
||||
|
||||
Query(MPool& pool);
|
||||
|
||||
query_result find(const std::string& query) const;
|
||||
|
@ -46,7 +53,6 @@ namespace mamba
|
|||
query_result depends(const std::string& query, bool tree) const;
|
||||
|
||||
private:
|
||||
|
||||
std::reference_wrapper<MPool> m_pool;
|
||||
};
|
||||
|
||||
|
@ -60,14 +66,11 @@ namespace mamba
|
|||
class query_result
|
||||
{
|
||||
public:
|
||||
|
||||
using dependency_graph = graph<PackageInfo>;
|
||||
using package_list = dependency_graph::node_list;
|
||||
using package_view_list = std::vector<package_list::const_iterator>;
|
||||
|
||||
query_result(QueryType type,
|
||||
const std::string& query,
|
||||
dependency_graph&& dep_graph);
|
||||
query_result(QueryType type, const std::string& query, dependency_graph&& dep_graph);
|
||||
|
||||
~query_result() = default;
|
||||
|
||||
|
@ -88,7 +91,6 @@ namespace mamba
|
|||
nl::json json() const;
|
||||
|
||||
private:
|
||||
|
||||
void reset_pkg_view_list();
|
||||
std::string get_package_repr(const PackageInfo& pkg) const;
|
||||
|
||||
|
@ -99,6 +101,6 @@ namespace mamba
|
|||
using ordered_package_list = std::map<std::string, package_view_list>;
|
||||
ordered_package_list m_ordered_pkg_list;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif // MAMBA_QUERY_HPP
|
||||
#endif // MAMBA_QUERY_HPP
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
|
||||
extern "C"
|
||||
{
|
||||
#include "solv/repo.h"
|
||||
#include "solv/repo_solv.h"
|
||||
#include "solv/conda.h"
|
||||
#include "solv/repo_conda.h"
|
||||
#include "solv/conda.h"
|
||||
#include "solv/repo.h"
|
||||
#include "solv/repo_conda.h"
|
||||
#include "solv/repo_solv.h"
|
||||
}
|
||||
|
||||
#include "pool.hpp"
|
||||
|
@ -34,17 +34,18 @@ namespace mamba
|
|||
|
||||
inline bool operator==(const RepoMetadata& lhs, const RepoMetadata& rhs)
|
||||
{
|
||||
return lhs.url == rhs.url && lhs.pip_added == rhs.pip_added &&
|
||||
lhs.etag == rhs.etag && lhs.mod == rhs.mod;
|
||||
return lhs.url == rhs.url && lhs.pip_added == rhs.pip_added && lhs.etag == rhs.etag
|
||||
&& lhs.mod == rhs.mod;
|
||||
}
|
||||
|
||||
class MRepo
|
||||
{
|
||||
public:
|
||||
|
||||
MRepo(MPool& pool, const PrefixData& prefix_data);
|
||||
MRepo(MPool& pool, const std::string& name,
|
||||
const std::string& filename, const std::string& url);
|
||||
MRepo(MPool& pool,
|
||||
const std::string& name,
|
||||
const std::string& filename,
|
||||
const std::string& url);
|
||||
MRepo(MPool& pool, const std::string& name, const fs::path& path, const RepoMetadata& meta);
|
||||
~MRepo();
|
||||
|
||||
|
@ -61,7 +62,6 @@ namespace mamba
|
|||
bool clear(bool reuse_ids);
|
||||
|
||||
private:
|
||||
|
||||
bool read_file(const std::string& filename);
|
||||
|
||||
std::string m_json_file, m_solv_file;
|
||||
|
@ -71,6 +71,6 @@ namespace mamba
|
|||
|
||||
Repo* m_repo;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif // MAMBA_REPO_HPP
|
||||
#endif // MAMBA_REPO_HPP
|
||||
|
|
|
@ -22,43 +22,43 @@ namespace fs = ghc::filesystem;
|
|||
#include "thirdparty/termcolor.hpp"
|
||||
|
||||
#ifndef _WIN32
|
||||
#if defined(__APPLE__)
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
#include <inttypes.h>
|
||||
#if defined(__linux__)
|
||||
#include <linux/limits.h>
|
||||
#else
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
#include <inttypes.h>
|
||||
#if defined(__linux__)
|
||||
#include <linux/limits.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
#include "thirdparty/WinReg.hpp"
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
#include "thirdparty/WinReg.hpp"
|
||||
#endif
|
||||
|
||||
// Here we are embedding the shell scripts
|
||||
constexpr const char mamba_sh[] =
|
||||
#include "../data/mamba.sh"
|
||||
;
|
||||
#include "../data/mamba.sh"
|
||||
;
|
||||
constexpr const char mamba_bat[] =
|
||||
#include "../data/mamba.bat"
|
||||
;
|
||||
#include "../data/mamba.bat"
|
||||
;
|
||||
constexpr const char _mamba_activate_bat[] =
|
||||
#include "../data/_mamba_activate.bat"
|
||||
;
|
||||
#include "../data/_mamba_activate.bat"
|
||||
;
|
||||
constexpr const char mamba_hook_bat[] =
|
||||
#include "../data/mamba_hook.bat"
|
||||
;
|
||||
#include "../data/mamba_hook.bat"
|
||||
;
|
||||
constexpr const char mamba_hook_ps1[] =
|
||||
#include "../data/mamba_hook.ps1"
|
||||
;
|
||||
#include "../data/mamba_hook.ps1"
|
||||
;
|
||||
constexpr const char mamba_psm1[] =
|
||||
#include "../data/Mamba.psm1"
|
||||
;
|
||||
#include "../data/Mamba.psm1"
|
||||
;
|
||||
constexpr const char mamba_xsh[] =
|
||||
#include "../data/mamba.xsh"
|
||||
;
|
||||
#include "../data/mamba.xsh"
|
||||
;
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -88,13 +88,17 @@ namespace mamba
|
|||
return "";
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void init_cmd_exe_registry(const std::wstring& reg_path, const fs::path& conda_prefix, bool reverse = false)
|
||||
#ifdef _WIN32
|
||||
void init_cmd_exe_registry(const std::wstring& reg_path,
|
||||
const fs::path& conda_prefix,
|
||||
bool reverse = false)
|
||||
{
|
||||
winreg::RegKey key{ HKEY_CURRENT_USER, reg_path };
|
||||
std::wstring prev_value = key.GetStringValue(L"AutoRun");
|
||||
std::wstring prev_value = key.GetStringValue(L"AutoRun");
|
||||
// std::wstring hook_path = '"%s"' % join(conda_prefix, 'condabin', 'conda_hook.bat')
|
||||
std::wstring hook_string = std::wstring(L"\"") + (conda_prefix / "condabin" / "mamba_hook.bat").wstring() + std::wstring(L"\"");
|
||||
std::wstring hook_string = std::wstring(L"\"")
|
||||
+ (conda_prefix / "condabin" / "mamba_hook.bat").wstring()
|
||||
+ std::wstring(L"\"");
|
||||
|
||||
if (reverse)
|
||||
{
|
||||
|
@ -103,13 +107,10 @@ namespace mamba
|
|||
else
|
||||
{
|
||||
std::wstring replace_str(L"__CONDA_REPLACE_ME_123__");
|
||||
std::wregex hook_regex(L"(\"[^\"]*?mamba[-_]hook\\.bat\")", std::regex_constants::icase);
|
||||
std::wregex hook_regex(L"(\"[^\"]*?mamba[-_]hook\\.bat\")",
|
||||
std::regex_constants::icase);
|
||||
prev_value = std::regex_replace(
|
||||
prev_value,
|
||||
hook_regex,
|
||||
replace_str,
|
||||
std::regex_constants::format_first_only
|
||||
);
|
||||
prev_value, hook_regex, replace_str, std::regex_constants::format_first_only);
|
||||
|
||||
replace_all(prev_value, replace_str, hook_string);
|
||||
std::wstring new_value = prev_value;
|
||||
|
@ -134,13 +135,13 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Heavily inspired by https://github.com/gpakosz/whereami/
|
||||
// check their source to add support for other OS
|
||||
fs::path get_self_exe_path()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
DWORD size;
|
||||
std::wstring buffer(MAX_PATH, '\0');
|
||||
size = GetModuleFileNameW(NULL, (wchar_t*) buffer.c_str(), (DWORD) buffer.size());
|
||||
|
@ -151,14 +152,15 @@ namespace mamba
|
|||
else if (size == buffer.size())
|
||||
{
|
||||
DWORD new_size = size;
|
||||
do {
|
||||
do
|
||||
{
|
||||
new_size *= 2;
|
||||
buffer.reserve(new_size);
|
||||
size = GetModuleFileNameW(NULL, (wchar_t*) buffer.c_str(), (DWORD) buffer.size());
|
||||
} while (new_size == size);
|
||||
}
|
||||
return fs::absolute(buffer);
|
||||
#elif defined(__APPLE__)
|
||||
#elif defined(__APPLE__)
|
||||
uint32_t size = PATH_MAX;
|
||||
std::vector<char> buffer(size);
|
||||
if (_NSGetExecutablePath(buffer.data(), &size) == -1)
|
||||
|
@ -170,13 +172,13 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
return fs::absolute(buffer.data());
|
||||
#else
|
||||
#if defined(__sun)
|
||||
return fs::read_symlink("/proc/self/path/a.out");
|
||||
#else
|
||||
return fs::read_symlink("/proc/self/exe");
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#if defined(__sun)
|
||||
return fs::read_symlink("/proc/self/path/a.out");
|
||||
#else
|
||||
return fs::read_symlink("/proc/self/exe");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::regex CONDA_INITIALIZE_RE_BLOCK("# >>> mamba initialize >>>(?:\n|\r\n)?"
|
||||
|
@ -201,17 +203,22 @@ namespace mamba
|
|||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << termcolor::red << "ERROR: Could not find bash, or use cygpath to convert Windows path to Unix." << termcolor::reset << std::endl;
|
||||
std::cout
|
||||
<< termcolor::red
|
||||
<< "ERROR: Could not find bash, or use cygpath to convert Windows path to Unix."
|
||||
<< termcolor::reset << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
std::string rcfile_content(const fs::path& env_prefix, const std::string& shell, const fs::path& mamba_exe)
|
||||
std::string rcfile_content(const fs::path& env_prefix,
|
||||
const std::string& shell,
|
||||
const fs::path& mamba_exe)
|
||||
{
|
||||
std::stringstream content;
|
||||
|
||||
// todo use get bin dir here!
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
std::string cyg_mamba_exe = native_path_to_unix(mamba_exe);
|
||||
// fs::path cyg_mamba_exe = native_path_to_unix(env_prefix / 'Scripts' / 'micromamba.exe');
|
||||
content << "# >>> mamba initialize >>>\n";
|
||||
|
@ -221,7 +228,7 @@ namespace mamba
|
|||
content << "# <<< mamba initialize <<<\n";
|
||||
return content.str();
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
fs::path env_bin = env_prefix / "bin";
|
||||
|
||||
|
@ -229,12 +236,14 @@ namespace mamba
|
|||
content << "# !! Contents within this block are managed by 'mamba init' !!\n";
|
||||
content << "export MAMBA_EXE=" << mamba_exe << ";\n";
|
||||
content << "export MAMBA_ROOT_PREFIX=" << env_prefix << ";\n";
|
||||
content << "__mamba_setup=\"$(" << std::quoted(mamba_exe.string(), '\'') << " shell hook --shell "
|
||||
<< shell << " --prefix " << std::quoted(env_prefix.string(), '\'') << " 2> /dev/null)\"\n";
|
||||
content << "__mamba_setup=\"$(" << std::quoted(mamba_exe.string(), '\'')
|
||||
<< " shell hook --shell " << shell << " --prefix "
|
||||
<< std::quoted(env_prefix.string(), '\'') << " 2> /dev/null)\"\n";
|
||||
content << "if [ $? -eq 0 ]; then\n";
|
||||
content << " eval \"$__mamba_setup\"\n";
|
||||
content << "else\n";
|
||||
content << " if [ -f " << (env_prefix / "etc" / "profile.d" / "mamba.sh") << " ]; then\n";
|
||||
content << " if [ -f " << (env_prefix / "etc" / "profile.d" / "mamba.sh")
|
||||
<< " ]; then\n";
|
||||
content << " . " << (env_prefix / "etc" / "profile.d" / "mamba.sh") << "\n";
|
||||
content << " else\n";
|
||||
content << " export PATH=\"" << env_bin.c_str() << ":$PATH\"\n";
|
||||
|
@ -245,10 +254,12 @@ namespace mamba
|
|||
|
||||
return content.str();
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string xonsh_content(const fs::path& env_prefix, const std::string& shell, const fs::path& mamba_exe)
|
||||
std::string xonsh_content(const fs::path& env_prefix,
|
||||
const std::string& shell,
|
||||
const fs::path& mamba_exe)
|
||||
{
|
||||
std::stringstream content;
|
||||
std::string s_mamba_exe;
|
||||
|
@ -270,22 +281,29 @@ namespace mamba
|
|||
content << "import sys as _sys\n";
|
||||
content << "from types import ModuleType as _ModuleType\n";
|
||||
content << "_mod = _ModuleType(\"xontrib.mamba\",\n";
|
||||
content << " \'Autogenerated from $(" << mamba_exe << " shell hook -s xonsh -p " << env_prefix << ")\')\n";
|
||||
content << "__xonsh__.execer.exec($(" << mamba_exe << " \"shell\" \"hook\" -s xonsh -p " << env_prefix << "),\n";
|
||||
content << " \'Autogenerated from $(" << mamba_exe
|
||||
<< " shell hook -s xonsh -p " << env_prefix << ")\')\n";
|
||||
content << "__xonsh__.execer.exec($(" << mamba_exe << " \"shell\" \"hook\" -s xonsh -p "
|
||||
<< env_prefix << "),\n";
|
||||
content << " glbs=_mod.__dict__,\n";
|
||||
content << " filename=\'$(" << mamba_exe << " shell hook -s xonsh -p " << env_prefix << ")\')\n";
|
||||
content << " filename=\'$(" << mamba_exe << " shell hook -s xonsh -p "
|
||||
<< env_prefix << ")\')\n";
|
||||
content << "_sys.modules[\"xontrib.mamba\"] = _mod\n";
|
||||
content << "del _sys, _mod, _ModuleType\n";
|
||||
content << "# <<< mamba initialize <<<\n";
|
||||
return content.str();
|
||||
}
|
||||
|
||||
bool modify_rc_file(const fs::path& file_path, const fs::path& conda_prefix,
|
||||
const std::string& shell, const fs::path& mamba_exe)
|
||||
bool modify_rc_file(const fs::path& file_path,
|
||||
const fs::path& conda_prefix,
|
||||
const std::string& shell,
|
||||
const fs::path& mamba_exe)
|
||||
{
|
||||
Console::stream() << "Modifiying RC file " << file_path
|
||||
<< "\nGenerating config for root prefix " << termcolor::bold << conda_prefix << termcolor::reset
|
||||
<< "\nSetting mamba executable to: " << termcolor::bold << mamba_exe << termcolor::reset;
|
||||
<< "\nGenerating config for root prefix " << termcolor::bold
|
||||
<< conda_prefix << termcolor::reset
|
||||
<< "\nSetting mamba executable to: " << termcolor::bold << mamba_exe
|
||||
<< termcolor::reset;
|
||||
|
||||
// TODO do we need binary or not?
|
||||
std::string rc_content = read_contents(file_path, std::ios::in);
|
||||
|
@ -300,14 +318,13 @@ namespace mamba
|
|||
conda_init_content = rcfile_content(conda_prefix, shell, mamba_exe);
|
||||
}
|
||||
|
||||
Console::stream() << "Adding (or replacing) the following in your " << file_path << " file\n"
|
||||
<< termcolor::colorize << termcolor::green << conda_init_content << termcolor::reset;
|
||||
Console::stream() << "Adding (or replacing) the following in your " << file_path
|
||||
<< " file\n"
|
||||
<< termcolor::colorize << termcolor::green << conda_init_content
|
||||
<< termcolor::reset;
|
||||
|
||||
std::string result = std::regex_replace(
|
||||
rc_content,
|
||||
CONDA_INITIALIZE_RE_BLOCK,
|
||||
conda_init_content
|
||||
);
|
||||
std::string result
|
||||
= std::regex_replace(rc_content, CONDA_INITIALIZE_RE_BLOCK, conda_init_content);
|
||||
|
||||
if (result.find("# >>> mamba initialize >>>") == result.npos)
|
||||
{
|
||||
|
@ -327,7 +344,8 @@ namespace mamba
|
|||
Context::instance().root_prefix = root_prefix;
|
||||
if (fs::exists(root_prefix))
|
||||
{
|
||||
if (!Console::prompt("Prefix at " + root_prefix.string() + " already exists, use as root prefix?"))
|
||||
if (!Console::prompt("Prefix at " + root_prefix.string()
|
||||
+ " already exists, use as root prefix?"))
|
||||
{
|
||||
Console::print("OK, exiting.");
|
||||
exit(0);
|
||||
|
@ -357,12 +375,15 @@ namespace mamba
|
|||
fs::path self_path = get_self_exe_path();
|
||||
|
||||
fs::create_directories(root_prefix / "condabin");
|
||||
std::cout << "writing out files to condabin: " << (root_prefix / "condabin") << std::endl;
|
||||
std::cout << "writing out files to condabin: " << (root_prefix / "condabin")
|
||||
<< std::endl;
|
||||
std::ofstream mamba_bat_f(root_prefix / "condabin" / "mamba.bat");
|
||||
std::string mamba_bat_contents(mamba_bat);
|
||||
replace_all(mamba_bat_contents, std::string("__MAMBA_INSERT_ROOT_PREFIX__"),
|
||||
replace_all(mamba_bat_contents,
|
||||
std::string("__MAMBA_INSERT_ROOT_PREFIX__"),
|
||||
std::string("@SET \"MAMBA_ROOT_PREFIX=" + root_prefix.string() + "\""));
|
||||
replace_all(mamba_bat_contents, std::string("__MAMBA_INSERT_MAMBA_EXE__"),
|
||||
replace_all(mamba_bat_contents,
|
||||
std::string("__MAMBA_INSERT_MAMBA_EXE__"),
|
||||
std::string("@SET \"MAMBA_EXE=" + self_path.string() + "\""));
|
||||
|
||||
mamba_bat_f << mamba_bat_contents;
|
||||
|
@ -371,7 +392,8 @@ namespace mamba
|
|||
|
||||
std::string hook_content = mamba_hook_bat;
|
||||
std::cout << "Self exe path: " << self_path << std::endl;
|
||||
replace_all(hook_content, std::string("__MAMBA_INSERT_MAMBA_EXE__"),
|
||||
replace_all(hook_content,
|
||||
std::string("__MAMBA_INSERT_MAMBA_EXE__"),
|
||||
std::string("@SET \"MAMBA_EXE=" + self_path.string() + "\""));
|
||||
|
||||
std::ofstream mamba_hook_bat_f(root_prefix / "condabin" / "mamba_hook.bat");
|
||||
|
@ -397,12 +419,15 @@ namespace mamba
|
|||
out << "# !! Contents within this block are managed by 'mamba shell init' !!\n";
|
||||
out << "$Env:MAMBA_ROOT_PREFIX = " << conda_prefix << "\n";
|
||||
out << "$Env:MAMBA_EXE = " << self_exe << "\n";
|
||||
out << "(& " << self_exe << " 'shell' 'hook' -s 'powershell' -p " << conda_prefix << ") | Out-String | Invoke-Expression\n";
|
||||
out << "(& " << self_exe << " 'shell' 'hook' -s 'powershell' -p " << conda_prefix
|
||||
<< ") | Out-String | Invoke-Expression\n";
|
||||
out << "#endregion\n";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
bool init_powershell(const fs::path& profile_path, const fs::path& conda_prefix, bool reverse=false)
|
||||
bool init_powershell(const fs::path& profile_path,
|
||||
const fs::path& conda_prefix,
|
||||
bool reverse = false)
|
||||
{
|
||||
// NB: the user may not have created a profile. We need to check
|
||||
// if the file exists first.
|
||||
|
@ -415,11 +440,7 @@ namespace mamba
|
|||
|
||||
if (reverse)
|
||||
{
|
||||
profile_content = std::regex_replace(
|
||||
profile_content,
|
||||
CONDA_INITIALIZE_PS_RE_BLOCK,
|
||||
""
|
||||
);
|
||||
profile_content = std::regex_replace(profile_content, CONDA_INITIALIZE_PS_RE_BLOCK, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -427,8 +448,10 @@ namespace mamba
|
|||
std::string conda_init_content = powershell_contents(conda_prefix);
|
||||
std::cout << "Adding: \n" << conda_init_content << std::endl;
|
||||
|
||||
Console::stream() << "Adding (or replacing) the following in your " << profile_path << " file\n"
|
||||
<< termcolor::colorize << termcolor::green << conda_init_content << termcolor::reset;
|
||||
Console::stream() << "Adding (or replacing) the following in your " << profile_path
|
||||
<< " file\n"
|
||||
<< termcolor::colorize << termcolor::green << conda_init_content
|
||||
<< termcolor::reset;
|
||||
|
||||
if (profile_content.find("#region mamba initialize") == profile_content.npos)
|
||||
{
|
||||
|
@ -437,10 +460,7 @@ namespace mamba
|
|||
else
|
||||
{
|
||||
profile_content = std::regex_replace(
|
||||
profile_content,
|
||||
CONDA_INITIALIZE_PS_RE_BLOCK,
|
||||
conda_init_content
|
||||
);
|
||||
profile_content, CONDA_INITIALIZE_PS_RE_BLOCK, conda_init_content);
|
||||
}
|
||||
}
|
||||
if (profile_content != profile_original_content)
|
||||
|
@ -482,11 +502,11 @@ namespace mamba
|
|||
}
|
||||
else if (shell == "cmd.exe")
|
||||
{
|
||||
#ifndef _WIN32
|
||||
#ifndef _WIN32
|
||||
throw std::runtime_error("CMD.EXE can only be initialized on Windows.");
|
||||
#else
|
||||
#else
|
||||
init_cmd_exe_registry(L"Software\\Microsoft\\Command Processor", conda_prefix, false);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else if (shell == "powershell")
|
||||
{
|
||||
|
@ -500,11 +520,11 @@ namespace mamba
|
|||
// just ask different possible installations of PowerShell where their
|
||||
// profiles are.
|
||||
|
||||
auto find_powershell_paths = [&profile_var](const std::string& exe) -> std::string
|
||||
{
|
||||
auto find_powershell_paths = [&profile_var](const std::string& exe) -> std::string {
|
||||
try
|
||||
{
|
||||
auto obuf = subprocess::check_output({exe, "-NoProfile", "-Command", profile_var});
|
||||
auto obuf
|
||||
= subprocess::check_output({ exe, "-NoProfile", "-Command", profile_var });
|
||||
std::string res(obuf.buf.data());
|
||||
return std::string(strip(res));
|
||||
}
|
||||
|
@ -515,7 +535,7 @@ namespace mamba
|
|||
};
|
||||
|
||||
std::string profile_path, exe;
|
||||
for (auto& iter_exe : std::vector<std::string>{"powershell", "pwsh", "pwsh-preview"})
|
||||
for (auto& iter_exe : std::vector<std::string>{ "powershell", "pwsh", "pwsh-preview" })
|
||||
{
|
||||
auto res = find_powershell_paths(iter_exe);
|
||||
if (!res.empty())
|
||||
|
@ -524,7 +544,8 @@ namespace mamba
|
|||
exe = iter_exe;
|
||||
}
|
||||
}
|
||||
std::cout << "Found powershell at " << exe << " and user profile at " << profile_path << std::endl;
|
||||
std::cout << "Found powershell at " << exe << " and user profile at " << profile_path
|
||||
<< std::endl;
|
||||
|
||||
init_powershell(profile_path, conda_prefix, false);
|
||||
}
|
||||
|
|
|
@ -7,26 +7,26 @@
|
|||
#ifndef MAMBA_SOLVER_HPP
|
||||
#define MAMBA_SOLVER_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "pool.hpp"
|
||||
#include "prefix_data.hpp"
|
||||
#include "match_spec.hpp"
|
||||
#include "output.hpp"
|
||||
#include "pool.hpp"
|
||||
#include "prefix_data.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "solv/queue.h"
|
||||
#include "solv/conda.h"
|
||||
#include "solv/solver.h"
|
||||
#include "solv/solverdebug.h"
|
||||
#include "solv/conda.h"
|
||||
#include "solv/queue.h"
|
||||
#include "solv/solver.h"
|
||||
#include "solv/solverdebug.h"
|
||||
}
|
||||
|
||||
#define MAMBA_NO_DEPS 0b0001
|
||||
#define MAMBA_ONLY_DEPS 0b0010
|
||||
#define MAMBA_NO_DEPS 0b0001
|
||||
#define MAMBA_ONLY_DEPS 0b0010
|
||||
#define MAMBA_FORCE_REINSTALL 0b0100
|
||||
|
||||
namespace mamba
|
||||
|
@ -34,8 +34,9 @@ namespace mamba
|
|||
class MSolver
|
||||
{
|
||||
public:
|
||||
|
||||
MSolver(MPool& pool, const std::vector<std::pair<int, int>>& flags = {}, const PrefixData* = nullptr);
|
||||
MSolver(MPool& pool,
|
||||
const std::vector<std::pair<int, int>>& flags = {},
|
||||
const PrefixData* = nullptr);
|
||||
~MSolver();
|
||||
|
||||
MSolver(const MSolver&) = delete;
|
||||
|
@ -62,20 +63,19 @@ namespace mamba
|
|||
bool force_reinstall = false;
|
||||
|
||||
private:
|
||||
|
||||
void add_channel_specific_job(const MatchSpec& ms, int job_flag);
|
||||
void add_reinstall_job(MatchSpec& ms, int job_flag);
|
||||
|
||||
std::vector<std::pair<int, int>> m_flags;
|
||||
std::vector<MatchSpec> m_install_specs;
|
||||
std::vector<MatchSpec> m_remove_specs;
|
||||
std::vector<MatchSpec> m_neuter_specs; // unused for now
|
||||
std::vector<MatchSpec> m_neuter_specs; // unused for now
|
||||
bool m_is_solved;
|
||||
Solver* m_solver;
|
||||
Pool* m_pool;
|
||||
Queue m_jobs;
|
||||
const PrefixData* m_prefix_data = nullptr;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif // MAMBA_SOLVER_HPP
|
||||
#endif // MAMBA_SOLVER_HPP
|
||||
|
|
|
@ -7,17 +7,17 @@
|
|||
#ifndef MAMBA_SUBDIRDATA_HPP
|
||||
#define MAMBA_SUBDIRDATA_HPP
|
||||
|
||||
#include <string>
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
#include <string>
|
||||
|
||||
#include "context.hpp"
|
||||
#include "repo.hpp"
|
||||
#include "util.hpp"
|
||||
#include "fetch.hpp"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "output.hpp"
|
||||
#include "repo.hpp"
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace fs = ghc::filesystem;
|
||||
|
||||
|
@ -31,11 +31,13 @@ namespace mamba
|
|||
class MSubdirData
|
||||
{
|
||||
public:
|
||||
|
||||
MSubdirData(const std::string& name, const std::string& url, const std::string& repodata_fn);
|
||||
MSubdirData(const std::string& name,
|
||||
const std::string& url,
|
||||
const std::string& repodata_fn);
|
||||
|
||||
// TODO return seconds as double
|
||||
fs::file_time_type::duration check_cache(const fs::path& cache_file, const fs::file_time_type::clock::time_point& ref);
|
||||
fs::file_time_type::duration check_cache(const fs::path& cache_file,
|
||||
const fs::file_time_type::clock::time_point& ref);
|
||||
bool loaded();
|
||||
bool forbid_cache();
|
||||
bool load();
|
||||
|
@ -47,7 +49,6 @@ namespace mamba
|
|||
MRepo create_repo(MPool& pool);
|
||||
|
||||
private:
|
||||
|
||||
bool decompress();
|
||||
void create_target(nlohmann::json& mod_etag);
|
||||
std::size_t get_cache_control_max_age(const std::string& val);
|
||||
|
@ -80,6 +81,6 @@ namespace mamba
|
|||
std::string cache_fn_url(const std::string& url);
|
||||
std::string create_cache_dir();
|
||||
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif // MAMBA_SUBDIRDATA_HPP
|
||||
#endif // MAMBA_SUBDIRDATA_HPP
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -16,32 +16,28 @@
|
|||
// defines the appropriate macro that is used to wrap some
|
||||
// platform specific things
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
# define TERMCOLOR_OS_WINDOWS
|
||||
#define TERMCOLOR_OS_WINDOWS
|
||||
#elif defined(__APPLE__)
|
||||
# define TERMCOLOR_OS_MACOS
|
||||
#define TERMCOLOR_OS_MACOS
|
||||
#elif defined(__unix__) || defined(__unix)
|
||||
# define TERMCOLOR_OS_LINUX
|
||||
#define TERMCOLOR_OS_LINUX
|
||||
#else
|
||||
# error unsupported platform
|
||||
#error unsupported platform
|
||||
#endif
|
||||
|
||||
|
||||
// This headers provides the `isatty()`/`fileno()` functions,
|
||||
// which are used for testing whether a standart stream refers
|
||||
// to the terminal. As for Windows, we also need WinApi funcs
|
||||
// for changing colors attributes of the terminal.
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
# include <unistd.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
# include <io.h>
|
||||
# include <windows.h>
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace termcolor
|
||||
{
|
||||
|
@ -57,157 +53,138 @@ namespace termcolor
|
|||
inline bool is_colorized(std::ostream& stream);
|
||||
inline bool is_atty(const std::ostream& stream);
|
||||
|
||||
#if defined(TERMCOLOR_OS_WINDOWS)
|
||||
inline void win_change_attributes(std::ostream& stream, int foreground, int background=-1);
|
||||
#endif
|
||||
}
|
||||
#if defined(TERMCOLOR_OS_WINDOWS)
|
||||
inline void win_change_attributes(std::ostream& stream,
|
||||
int foreground,
|
||||
int background = -1);
|
||||
#endif
|
||||
} // namespace _internal
|
||||
|
||||
inline
|
||||
std::ostream& colorize(std::ostream& stream)
|
||||
inline std::ostream& colorize(std::ostream& stream)
|
||||
{
|
||||
stream.iword(_internal::colorize_index) = 1L;
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& nocolorize(std::ostream& stream)
|
||||
inline std::ostream& nocolorize(std::ostream& stream)
|
||||
{
|
||||
stream.iword(_internal::colorize_index) = 0L;
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& reset(std::ostream& stream)
|
||||
inline std::ostream& reset(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[00m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1, -1);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& bold(std::ostream& stream)
|
||||
inline std::ostream& bold(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[1m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& dark(std::ostream& stream)
|
||||
inline std::ostream& dark(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[2m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& italic(std::ostream& stream)
|
||||
inline std::ostream& italic(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[3m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& underline(std::ostream& stream)
|
||||
inline std::ostream& underline(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[4m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& blink(std::ostream& stream)
|
||||
inline std::ostream& blink(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[5m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& reverse(std::ostream& stream)
|
||||
inline std::ostream& reverse(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[7m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& concealed(std::ostream& stream)
|
||||
inline std::ostream& concealed(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[8m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& crossed(std::ostream& stream)
|
||||
inline std::ostream& crossed(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[9m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
|
||||
template <uint8_t code>
|
||||
inline
|
||||
std::ostream& color(std::ostream& stream)
|
||||
inline std::ostream& color(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
|
@ -220,8 +197,7 @@ namespace termcolor
|
|||
}
|
||||
|
||||
template <uint8_t code>
|
||||
inline
|
||||
std::ostream& on_color(std::ostream& stream)
|
||||
inline std::ostream& on_color(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
|
@ -233,270 +209,224 @@ namespace termcolor
|
|||
return stream;
|
||||
}
|
||||
|
||||
#endif // defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#endif // defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& grey(std::ostream& stream)
|
||||
inline std::ostream& grey(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[30m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
0 // grey (black)
|
||||
0 // grey (black)
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& red(std::ostream& stream)
|
||||
inline std::ostream& red(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[31m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_RED
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, FOREGROUND_RED);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& green(std::ostream& stream)
|
||||
inline std::ostream& green(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[32m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_GREEN
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, FOREGROUND_GREEN);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& yellow(std::ostream& stream)
|
||||
inline std::ostream& yellow(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[33m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_GREEN | FOREGROUND_RED
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, FOREGROUND_GREEN | FOREGROUND_RED);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& blue(std::ostream& stream)
|
||||
inline std::ostream& blue(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[34m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_BLUE
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, FOREGROUND_BLUE);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& magenta(std::ostream& stream)
|
||||
inline std::ostream& magenta(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[35m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_BLUE | FOREGROUND_RED
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, FOREGROUND_BLUE | FOREGROUND_RED);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& cyan(std::ostream& stream)
|
||||
inline std::ostream& cyan(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[36m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_BLUE | FOREGROUND_GREEN
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, FOREGROUND_BLUE | FOREGROUND_GREEN);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& white(std::ostream& stream)
|
||||
inline std::ostream& white(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[37m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
|
||||
);
|
||||
#endif
|
||||
FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline
|
||||
std::ostream& on_grey(std::ostream& stream)
|
||||
inline std::ostream& on_grey(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[40m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
0 // grey (black)
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream,
|
||||
-1,
|
||||
0 // grey (black)
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_red(std::ostream& stream)
|
||||
inline std::ostream& on_red(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[41m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_RED
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1, BACKGROUND_RED);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_green(std::ostream& stream)
|
||||
inline std::ostream& on_green(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[42m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_GREEN
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1, BACKGROUND_GREEN);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_yellow(std::ostream& stream)
|
||||
inline std::ostream& on_yellow(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[43m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_GREEN | BACKGROUND_RED
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1, BACKGROUND_GREEN | BACKGROUND_RED);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_blue(std::ostream& stream)
|
||||
inline std::ostream& on_blue(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[44m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_BLUE
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1, BACKGROUND_BLUE);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_magenta(std::ostream& stream)
|
||||
inline std::ostream& on_magenta(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[45m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_BLUE | BACKGROUND_RED
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1, BACKGROUND_BLUE | BACKGROUND_RED);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_cyan(std::ostream& stream)
|
||||
inline std::ostream& on_cyan(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[46m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1, BACKGROUND_GREEN | BACKGROUND_BLUE);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline
|
||||
std::ostream& on_white(std::ostream& stream)
|
||||
inline std::ostream& on_white(std::ostream& stream)
|
||||
{
|
||||
if (_internal::is_colorized(stream))
|
||||
{
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
stream << "\033[47m";
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(stream, -1,
|
||||
BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
|
||||
);
|
||||
#endif
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
_internal::win_change_attributes(
|
||||
stream, -1, BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED);
|
||||
#endif
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Since C++ hasn't a way to hide something in the header from
|
||||
//! the outer access, I have to introduce this namespace which
|
||||
//! is used for internal purpose and should't be access from
|
||||
|
@ -506,8 +436,7 @@ namespace termcolor
|
|||
//! Since C++ hasn't a true way to extract stream handler
|
||||
//! from the a given `std::ostream` object, I have to write
|
||||
//! this kind of hack.
|
||||
inline
|
||||
FILE* get_standard_stream(const std::ostream& stream)
|
||||
inline FILE* get_standard_stream(const std::ostream& stream)
|
||||
{
|
||||
if (&stream == &std::cout)
|
||||
return stdout;
|
||||
|
@ -520,16 +449,14 @@ namespace termcolor
|
|||
// Say whether a given stream should be colorized or not. It's always
|
||||
// true for ATTY streams and may be true for streams marked with
|
||||
// colorize flag.
|
||||
inline
|
||||
bool is_colorized(std::ostream& stream)
|
||||
inline bool is_colorized(std::ostream& stream)
|
||||
{
|
||||
return is_atty(stream) || static_cast<bool>(stream.iword(colorize_index));
|
||||
}
|
||||
|
||||
//! Test whether a given `std::ostream` object refers to
|
||||
//! a terminal.
|
||||
inline
|
||||
bool is_atty(const std::ostream& stream)
|
||||
inline bool is_atty(const std::ostream& stream)
|
||||
{
|
||||
FILE* std_stream = get_standard_stream(stream);
|
||||
|
||||
|
@ -540,14 +467,14 @@ namespace termcolor
|
|||
if (!std_stream)
|
||||
return false;
|
||||
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
|
||||
return ::isatty(fileno(std_stream));
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
#elif defined(TERMCOLOR_OS_WINDOWS)
|
||||
return ::_isatty(_fileno(std_stream));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(TERMCOLOR_OS_WINDOWS)
|
||||
#if defined(TERMCOLOR_OS_WINDOWS)
|
||||
//! Change Windows Terminal colors attribute. If some
|
||||
//! parameter is `-1` then attribute won't changed.
|
||||
inline void win_change_attributes(std::ostream& stream, int foreground, int background)
|
||||
|
@ -604,15 +531,14 @@ namespace termcolor
|
|||
|
||||
SetConsoleTextAttribute(hTerminal, info.wAttributes);
|
||||
}
|
||||
#endif // TERMCOLOR_OS_WINDOWS
|
||||
#endif // TERMCOLOR_OS_WINDOWS
|
||||
|
||||
} // namespace _internal
|
||||
|
||||
} // namespace termcolor
|
||||
} // namespace _internal
|
||||
|
||||
} // namespace termcolor
|
||||
|
||||
#undef TERMCOLOR_OS_WINDOWS
|
||||
#undef TERMCOLOR_OS_MACOS
|
||||
#undef TERMCOLOR_OS_LINUX
|
||||
|
||||
#endif // TERMCOLOR_HPP_
|
||||
#endif // TERMCOLOR_HPP_
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
#ifdef MAMBA_TEST_SUITE
|
||||
#endif
|
||||
|
||||
|
@ -35,7 +35,6 @@ namespace mamba
|
|||
class thread_interrupted : public std::exception
|
||||
{
|
||||
public:
|
||||
|
||||
thread_interrupted() = default;
|
||||
};
|
||||
|
||||
|
@ -72,7 +71,6 @@ namespace mamba
|
|||
class thread
|
||||
{
|
||||
public:
|
||||
|
||||
thread() = default;
|
||||
~thread() = default;
|
||||
|
||||
|
@ -92,7 +90,6 @@ namespace mamba
|
|||
void detach();
|
||||
|
||||
private:
|
||||
|
||||
std::thread m_thread;
|
||||
};
|
||||
|
||||
|
@ -100,14 +97,13 @@ namespace mamba
|
|||
inline thread::thread(Function&& func, Args&&... args)
|
||||
{
|
||||
auto f = std::bind(std::forward<Function>(func), std::forward<Args>(args)...);
|
||||
m_thread = std::thread([f]()
|
||||
{
|
||||
m_thread = std::thread([f]() {
|
||||
increase_thread_count();
|
||||
try
|
||||
{
|
||||
f();
|
||||
}
|
||||
catch(thread_interrupted&)
|
||||
catch (thread_interrupted&)
|
||||
{
|
||||
}
|
||||
decrease_thread_count();
|
||||
|
@ -121,7 +117,6 @@ namespace mamba
|
|||
class interruption_guard
|
||||
{
|
||||
public:
|
||||
|
||||
template <class Function, class... Args>
|
||||
interruption_guard(Function&& func, Args&&... args);
|
||||
~interruption_guard();
|
||||
|
@ -133,9 +128,8 @@ namespace mamba
|
|||
interruption_guard& operator=(interruption_guard&&) = delete;
|
||||
|
||||
private:
|
||||
|
||||
#ifdef _WIN32
|
||||
static std::function<void ()> m_cleanup_function;
|
||||
static std::function<void()> m_cleanup_function;
|
||||
#else
|
||||
void block_signals() const;
|
||||
void wait_for_signal() const;
|
||||
|
@ -164,8 +158,7 @@ namespace mamba
|
|||
{
|
||||
block_signals();
|
||||
auto f = std::bind(std::forward<Function>(func), std::forward<Args>(args)...);
|
||||
std::thread victor_the_cleaner([f, this]()
|
||||
{
|
||||
std::thread victor_the_cleaner([f, this]() {
|
||||
wait_for_signal();
|
||||
if (m_interrupt.load())
|
||||
{
|
||||
|
@ -177,10 +170,10 @@ namespace mamba
|
|||
});
|
||||
register_cleaning_thread_id(victor_the_cleaner.native_handle());
|
||||
victor_the_cleaner.detach();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,25 +7,27 @@
|
|||
#ifndef MAMBA_TRANSACTION_HPP
|
||||
#define MAMBA_TRANSACTION_HPP
|
||||
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
#include <future>
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
|
||||
#include "repo.hpp"
|
||||
#include "fetch.hpp"
|
||||
#include "package_handling.hpp"
|
||||
#include "package_cache.hpp"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "output.hpp"
|
||||
#include "package_cache.hpp"
|
||||
#include "package_handling.hpp"
|
||||
#include "prefix_data.hpp"
|
||||
#include "repo.hpp"
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
#include "transaction_context.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "solv/transaction.h"
|
||||
#include "solv/transaction.h"
|
||||
}
|
||||
|
||||
#include "solver.hpp"
|
||||
|
@ -40,7 +42,6 @@ namespace mamba
|
|||
class PackageDownloadExtractTarget
|
||||
{
|
||||
public:
|
||||
|
||||
PackageDownloadExtractTarget(const MRepo& repo, Solvable* solvable);
|
||||
|
||||
void write_repodata_record(const fs::path& base_path);
|
||||
|
@ -51,7 +52,6 @@ namespace mamba
|
|||
DownloadTarget* target(const fs::path& cache_path, MultiPackageCache& cache);
|
||||
|
||||
private:
|
||||
|
||||
Solvable* m_solv;
|
||||
|
||||
ProgressProxy m_progress_proxy;
|
||||
|
@ -69,8 +69,8 @@ namespace mamba
|
|||
class MTransaction
|
||||
{
|
||||
public:
|
||||
|
||||
enum class FilterType {
|
||||
enum class FilterType
|
||||
{
|
||||
none,
|
||||
keep_only,
|
||||
ignore
|
||||
|
@ -102,7 +102,6 @@ namespace mamba
|
|||
std::string find_python_version();
|
||||
|
||||
private:
|
||||
|
||||
FilterType m_filter_type = FilterType::none;
|
||||
std::set<Id> m_filter_name_ids;
|
||||
|
||||
|
@ -114,6 +113,6 @@ namespace mamba
|
|||
|
||||
bool m_force_reinstall = false;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif // MAMBA_TRANSACTION_HPP
|
||||
#endif // MAMBA_TRANSACTION_HPP
|
||||
|
|
|
@ -20,22 +20,22 @@ namespace mamba
|
|||
fs::path get_python_short_path(const std::string& python_version);
|
||||
fs::path get_python_site_packages_short_path(const std::string& python_version);
|
||||
fs::path get_bin_directory_short_path();
|
||||
fs::path get_python_noarch_target_path(const std::string& source_short_path, const fs::path& target_site_packages_short_path);
|
||||
fs::path get_python_noarch_target_path(const std::string& source_short_path,
|
||||
const fs::path& target_site_packages_short_path);
|
||||
|
||||
class TransactionContext
|
||||
{
|
||||
public:
|
||||
TransactionContext() = default;
|
||||
TransactionContext(const fs::path& prefix, const std::string& py_version);
|
||||
|
||||
TransactionContext() = default;
|
||||
TransactionContext(const fs::path& prefix, const std::string& py_version);
|
||||
|
||||
bool has_python;
|
||||
fs::path target_prefix;
|
||||
fs::path site_packages_path;
|
||||
fs::path python_path;
|
||||
std::string python_version;
|
||||
std::string short_python_version;
|
||||
bool has_python;
|
||||
fs::path target_prefix;
|
||||
fs::path site_packages_path;
|
||||
fs::path python_path;
|
||||
std::string python_version;
|
||||
std::string short_python_version;
|
||||
};
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,15 +7,16 @@
|
|||
#ifndef MAMBA_URL_HPP
|
||||
#define MAMBA_URL_HPP
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <curl/curl.h>
|
||||
#include <curl/curl.h>
|
||||
}
|
||||
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// typedef enum {
|
||||
// CURLUE_OK,
|
||||
// CURLUE_BAD_HANDLE, /* 1 */
|
||||
|
@ -41,9 +42,7 @@ namespace mamba
|
|||
{
|
||||
bool has_scheme(const std::string& url);
|
||||
|
||||
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,
|
||||
std::string& remaining_url,
|
||||
|
@ -65,7 +64,6 @@ namespace mamba
|
|||
class URLHandler
|
||||
{
|
||||
public:
|
||||
|
||||
URLHandler(const std::string& url = "");
|
||||
~URLHandler();
|
||||
|
||||
|
@ -105,7 +103,6 @@ namespace mamba
|
|||
URLHandler& set_zoneid(const std::string& zoneid);
|
||||
|
||||
private:
|
||||
|
||||
std::string get_part(CURLUPart part);
|
||||
void set_part(CURLUPart part, const std::string& s);
|
||||
|
||||
|
@ -138,7 +135,7 @@ namespace mamba
|
|||
s1 += s2;
|
||||
return join_url_impl(s1, args...);
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
inline std::string join_url()
|
||||
{
|
||||
|
@ -151,6 +148,6 @@ namespace mamba
|
|||
std::string res = s;
|
||||
return detail::join_url_impl(res, args...);
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
|
||||
#include <array>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
|
@ -22,26 +24,25 @@ namespace fs = ghc::filesystem;
|
|||
|
||||
namespace mamba
|
||||
{
|
||||
#if __APPLE__ || __MACH__
|
||||
#if __APPLE__ || __MACH__
|
||||
static constexpr bool on_win = false;
|
||||
static constexpr bool on_linux = false;
|
||||
static constexpr bool on_mac = true;
|
||||
#elif __linux__
|
||||
#elif __linux__
|
||||
static constexpr bool on_win = false;
|
||||
static constexpr bool on_linux = true;
|
||||
static constexpr bool on_mac = false;
|
||||
#elif _WIN32
|
||||
#elif _WIN32
|
||||
static constexpr bool on_win = true;
|
||||
static constexpr bool on_linux = false;
|
||||
static constexpr bool on_mac = false;
|
||||
#else
|
||||
#error "no supported OS detected"
|
||||
#endif
|
||||
#else
|
||||
#error "no supported OS detected"
|
||||
#endif
|
||||
|
||||
class mamba_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
|
@ -52,35 +53,38 @@ namespace mamba
|
|||
std::vector<fs::path> filter_dir(const fs::path& dir, const std::string& suffix);
|
||||
bool paths_equal(const fs::path& lhs, const fs::path& rhs);
|
||||
|
||||
std::string read_contents(const fs::path& path, std::ios::openmode mode = std::ios::in | std::ios::binary);
|
||||
std::string read_contents(const fs::path& path,
|
||||
std::ios::openmode mode = std::ios::in | std::ios::binary);
|
||||
std::vector<std::string> read_lines(const fs::path& path);
|
||||
|
||||
inline void make_executable(const fs::path& p)
|
||||
{
|
||||
fs::permissions(p, fs::perms::owner_all | fs::perms::group_all | fs::perms::others_read | fs::perms::others_exec);
|
||||
fs::permissions(p,
|
||||
fs::perms::owner_all | fs::perms::group_all | fs::perms::others_read
|
||||
| fs::perms::others_exec);
|
||||
}
|
||||
|
||||
template <typename T = std::mt19937>
|
||||
inline auto random_generator() -> T
|
||||
{
|
||||
auto constexpr seed_bits = sizeof(typename T::result_type) * T::state_size;
|
||||
auto constexpr seed_len = seed_bits / std::numeric_limits<std::seed_seq::result_type>::digits;
|
||||
auto constexpr seed_len
|
||||
= seed_bits / std::numeric_limits<std::seed_seq::result_type>::digits;
|
||||
auto seed = std::array<std::seed_seq::result_type, seed_len>{};
|
||||
auto dev = std::random_device{};
|
||||
std::generate_n(begin(seed), seed_len, std::ref(dev));
|
||||
auto seed_seq = std::seed_seq(begin(seed), end(seed));
|
||||
return T{seed_seq};
|
||||
return T{ seed_seq };
|
||||
}
|
||||
|
||||
inline std::string generate_random_alphanumeric_string(std::size_t len)
|
||||
{
|
||||
static constexpr auto chars =
|
||||
"0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
static constexpr auto chars = "0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
thread_local auto rng = random_generator<std::mt19937>();
|
||||
|
||||
auto dist = std::uniform_int_distribution{{}, std::strlen(chars)};
|
||||
auto dist = std::uniform_int_distribution{ {}, std::strlen(chars) };
|
||||
auto result = std::string(len, '\0');
|
||||
std::generate_n(begin(result), len, [&]() { return chars[dist(rng)]; });
|
||||
return result;
|
||||
|
@ -89,7 +93,6 @@ namespace mamba
|
|||
class TemporaryDirectory
|
||||
{
|
||||
public:
|
||||
|
||||
TemporaryDirectory();
|
||||
~TemporaryDirectory();
|
||||
|
||||
|
@ -101,14 +104,12 @@ namespace mamba
|
|||
operator fs::path();
|
||||
|
||||
private:
|
||||
|
||||
fs::path m_path;
|
||||
};
|
||||
|
||||
class TemporaryFile
|
||||
{
|
||||
public:
|
||||
|
||||
TemporaryFile(const std::string& prefix = "mambaf", const std::string& suffix = "");
|
||||
~TemporaryFile();
|
||||
|
||||
|
@ -120,7 +121,6 @@ namespace mamba
|
|||
operator fs::path();
|
||||
|
||||
private:
|
||||
|
||||
fs::path m_path;
|
||||
};
|
||||
|
||||
|
@ -157,7 +157,8 @@ namespace mamba
|
|||
template <class S>
|
||||
inline std::string join(const char* j, const S& container)
|
||||
{
|
||||
if (container.empty()) return "";
|
||||
if (container.empty())
|
||||
return "";
|
||||
std::string result = container[0];
|
||||
for (std::size_t i = 1; i < container.size(); ++i)
|
||||
{
|
||||
|
@ -167,13 +168,9 @@ namespace mamba
|
|||
return result;
|
||||
}
|
||||
|
||||
void replace_all(std::string& data,
|
||||
const std::string& search,
|
||||
const std::string& replace);
|
||||
void replace_all(std::string& data, const std::string& search, const std::string& replace);
|
||||
|
||||
void replace_all(std::wstring& data,
|
||||
const std::wstring& search,
|
||||
const std::wstring& replace);
|
||||
void replace_all(std::wstring& data, const std::wstring& search, const std::wstring& replace);
|
||||
|
||||
// Note: this function only works for non-unicode!
|
||||
std::string to_upper(const std::string_view& input);
|
||||
|
@ -198,26 +195,30 @@ namespace mamba
|
|||
{
|
||||
inline sizer(const char* s)
|
||||
: size(strlen(s))
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
inline sizer(const char s)
|
||||
: size(1)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline sizer(T& s)
|
||||
: size(s.size())
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t size;
|
||||
};
|
||||
}
|
||||
} // namespace concat_impl
|
||||
|
||||
template<typename... Args>
|
||||
template <typename... Args>
|
||||
inline std::string concat(const Args&... args)
|
||||
{
|
||||
size_t len = 0;
|
||||
for (auto s : std::initializer_list<concat_impl::sizer>{args...}) len += s.size;
|
||||
for (auto s : std::initializer_list<concat_impl::sizer>{ args... })
|
||||
len += s.size;
|
||||
|
||||
std::string result;
|
||||
result.reserve(len);
|
||||
|
@ -247,6 +248,6 @@ namespace mamba
|
|||
else
|
||||
target = default_value;
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
||||
#endif // MAMBA_UTIL_HPP
|
||||
#endif // MAMBA_UTIL_HPP
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef MAMBA_VALIDATE_HPP
|
||||
#define MAMBA_VALIDATE_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
|
||||
namespace fs = ghc::filesystem;
|
||||
|
@ -18,6 +20,6 @@ namespace validate
|
|||
bool sha256(const std::string& path, const std::string& validation);
|
||||
bool md5(const std::string& path, const std::string& validation);
|
||||
bool file_size(const fs::path& path, std::uintmax_t validation);
|
||||
}
|
||||
} // namespace validate
|
||||
|
||||
#endif //MAMBA_VALIDATE_HPP
|
||||
#endif // MAMBA_VALIDATE_HPP
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "activation.hpp"
|
||||
|
||||
#include "environment.hpp"
|
||||
|
||||
namespace mamba
|
||||
|
@ -13,8 +14,8 @@ namespace mamba
|
|||
{
|
||||
fs::path PREFIX_STATE_FILE = fs::path("conda-meta") / "state";
|
||||
fs::path PACKAGE_ENV_VARS_DIR = fs::path("etc") / "conda" / "env_vars.d";
|
||||
std::string CONDA_ENV_VARS_UNSET_VAR = "***unset***";
|
||||
}
|
||||
std::string CONDA_ENV_VARS_UNSET_VAR = "***unset***"; // NOLINT(runtime/string)
|
||||
} // namespace
|
||||
|
||||
/****************************
|
||||
* Activator implementation *
|
||||
|
@ -59,7 +60,8 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> Activator::get_environment_vars(const fs::path& prefix)
|
||||
std::vector<std::pair<std::string, std::string>> Activator::get_environment_vars(
|
||||
const fs::path& prefix)
|
||||
{
|
||||
fs::path env_vars_file = prefix / PREFIX_STATE_FILE;
|
||||
fs::path pkg_env_var_dir = prefix / PACKAGE_ENV_VARS_DIR;
|
||||
|
@ -74,7 +76,8 @@ namespace mamba
|
|||
// if exists(pkg_env_var_dir):
|
||||
// for pkg_env_var_file in sorted(os.listdir(pkg_env_var_dir)):
|
||||
// with open(join(pkg_env_var_dir, pkg_env_var_file), 'r') as f:
|
||||
// env_vars.update(json.loads(f.read(), object_pairs_hook=OrderedDict))
|
||||
// env_vars.update(json.loads(f.read(),
|
||||
object_pairs_hook=OrderedDict))
|
||||
}*/
|
||||
|
||||
// Then get env vars from environment specification
|
||||
|
@ -84,9 +87,10 @@ namespace mamba
|
|||
// with open(env_vars_file, 'r') as f:
|
||||
// prefix_state = json.loads(f.read(), object_pairs_hook=OrderedDict)
|
||||
// prefix_state_env_vars = prefix_state.get('env_vars', {})
|
||||
// dup_vars = [ev for ev in env_vars.keys() if ev in prefix_state_env_vars.keys()]
|
||||
// for dup in dup_vars:
|
||||
// print("WARNING: duplicate env vars detected. Vars from the environment "
|
||||
// dup_vars = [ev for ev in env_vars.keys() if ev in
|
||||
// prefix_state_env_vars.keys()] for dup in dup_vars:
|
||||
// print("WARNING: duplicate env vars detected. Vars from the
|
||||
// environment "
|
||||
// "will overwrite those from packages", file=sys.stderr)
|
||||
// print("variable %s duplicated" % dup, file=sys.stderr)
|
||||
// env_vars.update(prefix_state_env_vars)
|
||||
|
@ -105,8 +109,10 @@ namespace mamba
|
|||
std::string env_i;
|
||||
for (int i = 1; i < old_conda_shlvl + 1; ++i)
|
||||
{
|
||||
std::string env_prefix = (i == old_conda_shlvl) ? "CONDA_PREFIX" : "CONDA_PREFIX_" + std::to_string(i);
|
||||
std::string prefix = (m_env.find(env_prefix) != m_env.end()) ? m_env[env_prefix] : "";
|
||||
std::string env_prefix
|
||||
= (i == old_conda_shlvl) ? "CONDA_PREFIX" : "CONDA_PREFIX_" + std::to_string(i);
|
||||
std::string prefix
|
||||
= (m_env.find(env_prefix) != m_env.end()) ? m_env[env_prefix] : "";
|
||||
env_i = get_default_env(prefix);
|
||||
|
||||
bool stacked_i = m_env.find("CONDA_STACKED_" + std::to_string(i)) != m_env.end();
|
||||
|
@ -126,7 +132,8 @@ namespace mamba
|
|||
prompt_stack.pop_back();
|
||||
if (env_stack.size())
|
||||
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())
|
||||
{
|
||||
prompt_stack.push_back(env_stack.back());
|
||||
|
@ -166,13 +173,11 @@ namespace mamba
|
|||
{
|
||||
if (on_win)
|
||||
{
|
||||
return {
|
||||
prefix / "Library" / "mingw-w64" / "bin",
|
||||
prefix / "Library" / "usr" / "bin",
|
||||
prefix / "Library" / "bin",
|
||||
prefix / "Scripts",
|
||||
prefix / "bin"
|
||||
};
|
||||
return { prefix / "Library" / "mingw-w64" / "bin",
|
||||
prefix / "Library" / "usr" / "bin",
|
||||
prefix / "Library" / "bin",
|
||||
prefix / "Scripts",
|
||||
prefix / "bin" };
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -183,13 +188,13 @@ namespace mamba
|
|||
std::vector<fs::path> Activator::get_clean_dirs()
|
||||
{
|
||||
// For isolation, running the conda test suite *without* env. var. inheritance
|
||||
// every so often is a good idea. We should probably make this a pytest fixture
|
||||
// along with one that tests both hardlink-only and copy-only, but before that
|
||||
// conda's testsuite needs to be a lot faster!
|
||||
// clean_paths = {'darwin': '/usr/bin:/bin:/usr/sbin:/sbin',
|
||||
// # You may think 'let us do something more clever here and interpolate
|
||||
// # `%windir%`' but the point here is the the whole env. is cleaned out
|
||||
// 'win32': 'C:\\Windows\\system32;'
|
||||
// every so often is a good idea. We should probably make this a pytest
|
||||
// fixture along with one that tests both hardlink-only and copy-only, but
|
||||
// before that conda's testsuite needs to be a lot faster! clean_paths =
|
||||
// {'darwin': '/usr/bin:/bin:/usr/sbin:/sbin',
|
||||
// # You may think 'let us do something more clever here and
|
||||
// interpolate # `%windir%`' but the point here is the the
|
||||
// whole env. is cleaned out 'win32': 'C:\\Windows\\system32;'
|
||||
// 'C:\\Windows;'
|
||||
// 'C:\\Windows\\System32\\Wbem;'
|
||||
// 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\'
|
||||
|
@ -207,26 +212,25 @@ namespace mamba
|
|||
{
|
||||
if (on_linux)
|
||||
{
|
||||
path = {"/usr/bin"};
|
||||
path = { "/usr/bin" };
|
||||
}
|
||||
else if (on_mac)
|
||||
{
|
||||
path = {"/usr/bin", "/bin", "/usr/sbin", "/sbin"};
|
||||
path = { "/usr/bin", "/bin", "/usr/sbin", "/sbin" };
|
||||
}
|
||||
else
|
||||
{
|
||||
path = {
|
||||
"C:\\Windows\\system32",
|
||||
"C:\\Windows",
|
||||
"C:\\Windows\\System32\\Wbem",
|
||||
"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\"
|
||||
};
|
||||
path = { "C:\\Windows\\system32",
|
||||
"C:\\Windows",
|
||||
"C:\\Windows\\System32\\Wbem",
|
||||
"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\" };
|
||||
}
|
||||
}
|
||||
// We used to prepend sys.prefix\Library\bin to PATH on startup but not anymore.
|
||||
// Instead, in conda 4.6 we add the full suite of entries. This is performed in
|
||||
// condabin\conda.bat and condabin\ _conda_activate.bat. However, we
|
||||
// need to ignore the stuff we add there, and only consider actual PATH entries.
|
||||
// We used to prepend sys.prefix\Library\bin to PATH on startup but not
|
||||
// anymore. Instead, in conda 4.6 we add the full suite of entries. This is
|
||||
// performed in condabin\conda.bat and condabin\ _conda_activate.bat. However,
|
||||
// we need to ignore the stuff we add there, and only consider actual PATH
|
||||
// entries.
|
||||
|
||||
// prefix_dirs = tuple(self._get_path_dirs(sys.prefix))
|
||||
// start_index = 0
|
||||
|
@ -249,15 +253,16 @@ namespace mamba
|
|||
// prefix = self.path_conversion(prefix)
|
||||
// path_list = list(self.path_conversion(self._get_starting_path_list()))
|
||||
auto path_list = get_clean_dirs();
|
||||
// If this is the first time we're activating an environment, we need to ensure that
|
||||
// the condabin directory is included in the path list.
|
||||
// Under normal conditions, if the shell hook is working correctly, this should
|
||||
// If this is the first time we're activating an environment, we need to
|
||||
// ensure that the condabin directory is included in the path list. Under
|
||||
// normal conditions, if the shell hook is working correctly, this should
|
||||
// never trigger.
|
||||
if (old_conda_shlvl == 0)
|
||||
{
|
||||
bool no_condabin = std::none_of(path_list.begin(), path_list.end(),
|
||||
[](const std::string& s) { return ends_with(s, "condabin");}
|
||||
);
|
||||
bool no_condabin
|
||||
= std::none_of(path_list.begin(), path_list.end(), [](const std::string& s) {
|
||||
return ends_with(s, "condabin");
|
||||
});
|
||||
if (no_condabin)
|
||||
{
|
||||
auto condabin_dir = Context::instance().conda_prefix / "condabin";
|
||||
|
@ -275,7 +280,8 @@ namespace mamba
|
|||
return result;
|
||||
}
|
||||
|
||||
std::string Activator::replace_prefix_in_path(const fs::path& old_prefix, const fs::path& new_prefix)
|
||||
std::string Activator::replace_prefix_in_path(const fs::path& old_prefix,
|
||||
const fs::path& new_prefix)
|
||||
{
|
||||
// TODO not done yet.
|
||||
std::vector<fs::path> current_path = get_clean_dirs();
|
||||
|
@ -284,12 +290,15 @@ namespace mamba
|
|||
std::vector<fs::path> old_prefix_dirs = get_path_dirs(old_prefix);
|
||||
|
||||
// remove all old paths
|
||||
current_path.erase(std::remove_if(current_path.begin(), current_path.end(), [&](const fs::path& path_elem) {
|
||||
return std::find_if(old_prefix_dirs.begin(), old_prefix_dirs.end(),
|
||||
[&path_elem](const fs::path& old_dir) {
|
||||
return paths_equal(old_dir, path_elem);
|
||||
}) != old_prefix_dirs.end();
|
||||
}));
|
||||
current_path.erase(std::remove_if(
|
||||
current_path.begin(), current_path.end(), [&](const fs::path& path_elem) {
|
||||
return std::find_if(old_prefix_dirs.begin(),
|
||||
old_prefix_dirs.end(),
|
||||
[&path_elem](const fs::path& old_dir) {
|
||||
return paths_equal(old_dir, path_elem);
|
||||
})
|
||||
!= old_prefix_dirs.end();
|
||||
}));
|
||||
|
||||
// TODO remove `sys.prefix\Library\bin` on Windows?!
|
||||
// Not sure if necessary as we don't fiddle with Python
|
||||
|
@ -306,7 +315,8 @@ namespace mamba
|
|||
}
|
||||
else
|
||||
{
|
||||
current_path.erase(std::unique(current_path.begin(), current_path.end()), current_path.end());
|
||||
current_path.erase(std::unique(current_path.begin(), current_path.end()),
|
||||
current_path.end());
|
||||
std::string result = join(env::pathsep(), current_path);
|
||||
return result;
|
||||
}
|
||||
|
@ -317,8 +327,9 @@ namespace mamba
|
|||
return replace_prefix_in_path(prefix, fs::path());
|
||||
}
|
||||
|
||||
void Activator::get_export_unset_vars(EnvironmentTransform& envt,
|
||||
const std::vector<std::pair<std::string, std::string>>& to_export)
|
||||
void Activator::get_export_unset_vars(
|
||||
EnvironmentTransform& envt,
|
||||
const std::vector<std::pair<std::string, std::string>>& to_export)
|
||||
{
|
||||
// conda_exe_vars_export = OrderedDict()
|
||||
// for k, v in context.conda_exe_vars_dict.items():
|
||||
|
@ -335,7 +346,7 @@ namespace mamba
|
|||
}
|
||||
else
|
||||
{
|
||||
envt.export_vars.push_back({to_upper(k), v});
|
||||
envt.export_vars.push_back({ to_upper(k), v });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -360,12 +371,14 @@ namespace mamba
|
|||
return envt;
|
||||
}
|
||||
|
||||
std::string conda_default_env = (m_env.find("CONDA_DEFAULT_ENV") != m_env.end()) ?
|
||||
m_env["CONDA_DEFAULT_ENV"] : get_default_env(conda_prefix);
|
||||
std::string conda_default_env = (m_env.find("CONDA_DEFAULT_ENV") != m_env.end())
|
||||
? m_env["CONDA_DEFAULT_ENV"]
|
||||
: get_default_env(conda_prefix);
|
||||
|
||||
auto new_path = replace_prefix_in_path(conda_prefix, conda_prefix);
|
||||
|
||||
std::string conda_prompt_modifier = get_prompt_modifier(conda_prefix, conda_default_env, conda_shlvl);
|
||||
std::string conda_prompt_modifier
|
||||
= get_prompt_modifier(conda_prefix, conda_default_env, conda_shlvl);
|
||||
if (Context::instance().change_ps1)
|
||||
{
|
||||
auto res = update_prompt(conda_prompt_modifier);
|
||||
|
@ -375,17 +388,17 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> env_vars_to_export = {
|
||||
{"path", new_path},
|
||||
{"conda_shlvl", std::to_string(conda_shlvl)},
|
||||
{"conda_prompt_modifier", conda_prompt_modifier}
|
||||
};
|
||||
std::vector<std::pair<std::string, std::string>> env_vars_to_export
|
||||
= { { "path", new_path },
|
||||
{ "conda_shlvl", std::to_string(conda_shlvl) },
|
||||
{ "conda_prompt_modifier", conda_prompt_modifier } };
|
||||
get_export_unset_vars(envt, env_vars_to_export);
|
||||
|
||||
// TODO figure out if this is all really necessary?
|
||||
// # environment variables are set only to aid transition from conda 4.3 to conda 4.4
|
||||
// conda_environment_env_vars = self._get_environment_env_vars(conda_prefix)
|
||||
// for k, v in conda_environment_env_vars.items():
|
||||
// # environment variables are set only to aid transition from conda 4.3 to
|
||||
// conda 4.4 conda_environment_env_vars =
|
||||
// self._get_environment_env_vars(conda_prefix) for k, v in
|
||||
// conda_environment_env_vars.items():
|
||||
// if v == CONDA_ENV_VARS_UNSET_VAR:
|
||||
// env_vars_to_unset = env_vars_to_unset + (k,)
|
||||
// else:
|
||||
|
@ -401,8 +414,7 @@ namespace mamba
|
|||
{
|
||||
EnvironmentTransform envt;
|
||||
|
||||
if (m_env.find("CONDA_PREFIX") == m_env.end() ||
|
||||
m_env.find("CONDA_SHLVL") == m_env.end())
|
||||
if (m_env.find("CONDA_PREFIX") == m_env.end() || m_env.find("CONDA_SHLVL") == m_env.end())
|
||||
{
|
||||
// nothing to deactivate
|
||||
return envt;
|
||||
|
@ -414,35 +426,36 @@ namespace mamba
|
|||
int new_conda_shlvl = old_conda_shlvl - 1;
|
||||
|
||||
std::string conda_prompt_modifier = "";
|
||||
// set_vars = {};
|
||||
if (old_conda_shlvl == 1)
|
||||
{
|
||||
std::string new_path = remove_prefix_from_path(old_conda_prefix);
|
||||
// You might think that you can remove the CONDA_EXE vars by passing conda_exe_vars=None
|
||||
// here so that "deactivate means deactivate" but you cannot since the conda shell
|
||||
// scripts still refer to them and they only set them once at the top. We could change
|
||||
// that though, the conda() shell function could set them instead of doing it at the
|
||||
// top. This would be *much* cleaner. I personally cannot abide that I have
|
||||
// deactivated conda and anything at all in my env still references it (apart from the
|
||||
// shell script, we need something I suppose!)
|
||||
// You might think that you can remove the CONDA_EXE vars by passing
|
||||
// conda_exe_vars=None here so that "deactivate means deactivate" but you
|
||||
// cannot since the conda shell scripts still refer to them and they only
|
||||
// set them once at the top. We could change that though, the conda() shell
|
||||
// function could set them instead of doing it at the top. This would be
|
||||
// *much* cleaner. I personally cannot abide that I have deactivated conda
|
||||
// and anything at all in my env still references it (apart from the shell
|
||||
// script, we need something I suppose!)
|
||||
envt.export_path = new_path;
|
||||
std::vector<std::pair<std::string, std::string>> env_vars_to_export = {
|
||||
{"conda_prefix", ""},
|
||||
{"conda_shlvl", std::to_string(new_conda_shlvl)},
|
||||
{"conda_default_env", ""},
|
||||
{"conda_prompt_modifier", ""}
|
||||
};
|
||||
std::vector<std::pair<std::string, std::string>> env_vars_to_export
|
||||
= { { "conda_prefix", "" },
|
||||
{ "conda_shlvl", std::to_string(new_conda_shlvl) },
|
||||
{ "conda_default_env", "" },
|
||||
{ "conda_prompt_modifier", "" } };
|
||||
get_export_unset_vars(envt, env_vars_to_export);
|
||||
}
|
||||
else
|
||||
{
|
||||
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 conda_default_env = get_default_env(new_prefix);
|
||||
std::string conda_prompt_modifier = get_prompt_modifier(new_prefix, conda_default_env, old_conda_shlvl);
|
||||
conda_prompt_modifier
|
||||
= get_prompt_modifier(new_prefix, conda_default_env, old_conda_shlvl);
|
||||
auto new_conda_environment_env_vars = get_environment_vars(new_prefix);
|
||||
|
||||
bool old_prefix_stacked = (m_env.find("CONDA_STACKED_" + std::to_string(old_conda_shlvl)) != m_env.end());
|
||||
bool old_prefix_stacked
|
||||
= (m_env.find("CONDA_STACKED_" + std::to_string(old_conda_shlvl)) != m_env.end());
|
||||
std::string new_path;
|
||||
envt.unset_vars.push_back("CONDA_PREFIX_" + std::to_string(new_conda_shlvl));
|
||||
|
||||
|
@ -456,18 +469,17 @@ namespace mamba
|
|||
new_path = replace_prefix_in_path(old_conda_prefix, new_prefix);
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> env_vars_to_export = {
|
||||
{"conda_prefix", "new_prefix"},
|
||||
{"conda_shlvl", std::to_string(new_conda_shlvl)},
|
||||
{"conda_default_env", conda_default_env},
|
||||
{"conda_prompt_modifier", conda_prompt_modifier}
|
||||
};
|
||||
std::vector<std::pair<std::string, std::string>> env_vars_to_export
|
||||
= { { "conda_prefix", "new_prefix" },
|
||||
{ "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);
|
||||
|
||||
for (auto& [k, v] : new_conda_environment_env_vars)
|
||||
{
|
||||
envt.export_vars.push_back({k, v});
|
||||
envt.export_vars.push_back({ k, v });
|
||||
}
|
||||
|
||||
envt.export_path = new_path;
|
||||
|
@ -486,10 +498,11 @@ namespace mamba
|
|||
for (auto& env_var : old_conda_environment_env_vars)
|
||||
{
|
||||
envt.unset_vars.push_back(env_var.first);
|
||||
std::string save_var = std::string("__CONDA_SHLVL_") + std::to_string(new_conda_shlvl) + "_" + env_var.first; // % (new_conda_shlvl, env_var)
|
||||
std::string save_var = std::string("__CONDA_SHLVL_") + std::to_string(new_conda_shlvl)
|
||||
+ "_" + env_var.first; // % (new_conda_shlvl, env_var)
|
||||
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] });
|
||||
}
|
||||
}
|
||||
return envt;
|
||||
|
@ -530,9 +543,9 @@ namespace mamba
|
|||
return build_reactivate();
|
||||
}
|
||||
|
||||
if (old_conda_shlvl &&
|
||||
m_env.find("CONDA_PREFIX_" + std::to_string(old_conda_shlvl - 1)) != m_env.end() &&
|
||||
m_env["CONDA_PREFIX_" + std::to_string(old_conda_shlvl - 1)] == prefix)
|
||||
if (old_conda_shlvl
|
||||
&& m_env.find("CONDA_PREFIX_" + std::to_string(old_conda_shlvl - 1)) != m_env.end()
|
||||
&& m_env["CONDA_PREFIX_" + std::to_string(old_conda_shlvl - 1)] == prefix)
|
||||
{
|
||||
// in this case, user is attempting to activate the previous environment,
|
||||
// i.e. step back down
|
||||
|
@ -541,7 +554,8 @@ namespace mamba
|
|||
|
||||
envt.activate_scripts = get_activate_scripts(prefix);
|
||||
std::string conda_default_env = get_default_env(prefix);
|
||||
std::string conda_prompt_modifier = get_prompt_modifier(prefix, conda_default_env, old_conda_shlvl);
|
||||
std::string conda_prompt_modifier
|
||||
= get_prompt_modifier(prefix, conda_default_env, old_conda_shlvl);
|
||||
|
||||
auto conda_environment_env_vars = get_environment_vars(prefix);
|
||||
|
||||
|
@ -553,7 +567,8 @@ namespace mamba
|
|||
std::vector<std::string> clobbering_env_vars;
|
||||
for (auto& env_var : conda_environment_env_vars)
|
||||
{
|
||||
if (m_env.find(env_var.first) != m_env.end()) clobbering_env_vars.push_back(env_var.first);
|
||||
if (m_env.find(env_var.first) != m_env.end())
|
||||
clobbering_env_vars.push_back(env_var.first);
|
||||
}
|
||||
|
||||
for (const auto& v : clobbering_env_vars)
|
||||
|
@ -561,7 +576,7 @@ namespace mamba
|
|||
// TODO use concat
|
||||
std::stringstream tmp;
|
||||
tmp << "__CONDA_SHLVL_" << old_conda_shlvl << "_" << v;
|
||||
conda_environment_env_vars.push_back({tmp.str(), m_env[v]});
|
||||
conda_environment_env_vars.push_back({ tmp.str(), m_env[v] });
|
||||
}
|
||||
|
||||
if (clobbering_env_vars.size())
|
||||
|
@ -575,17 +590,15 @@ namespace mamba
|
|||
|
||||
std::string new_path = add_prefix_to_path(prefix, old_conda_shlvl);
|
||||
|
||||
env_vars_to_export = {
|
||||
{"path", std::string(new_path)},
|
||||
{"conda_prefix", std::string(prefix)},
|
||||
{"conda_shlvl", std::to_string(new_conda_shlvl)},
|
||||
{"conda_default_env", conda_default_env},
|
||||
{"conda_prompt_modifier", conda_prompt_modifier}
|
||||
};
|
||||
env_vars_to_export = { { "path", std::string(new_path) },
|
||||
{ "conda_prefix", std::string(prefix) },
|
||||
{ "conda_shlvl", std::to_string(new_conda_shlvl) },
|
||||
{ "conda_default_env", conda_default_env },
|
||||
{ "conda_prompt_modifier", conda_prompt_modifier } };
|
||||
|
||||
for (auto& [k, v] : conda_environment_env_vars)
|
||||
{
|
||||
envt.export_vars.push_back({k, v});
|
||||
envt.export_vars.push_back({ k, v });
|
||||
}
|
||||
|
||||
if (old_conda_shlvl == 0)
|
||||
|
@ -597,16 +610,19 @@ namespace mamba
|
|||
if (m_stack)
|
||||
{
|
||||
get_export_unset_vars(envt, env_vars_to_export);
|
||||
envt.export_vars.push_back({"CONDA_PREFIX_" + std::to_string(old_conda_shlvl), old_conda_prefix});
|
||||
envt.export_vars.push_back({"CONDA_STACKED_" + std::to_string(new_conda_shlvl), "true"});
|
||||
envt.export_vars.push_back(
|
||||
{ "CONDA_PREFIX_" + std::to_string(old_conda_shlvl), old_conda_prefix });
|
||||
envt.export_vars.push_back(
|
||||
{ "CONDA_STACKED_" + std::to_string(new_conda_shlvl), "true" });
|
||||
}
|
||||
else
|
||||
{
|
||||
new_path = replace_prefix_in_path(old_conda_prefix, prefix);
|
||||
envt.deactivate_scripts = get_deactivate_scripts(old_conda_prefix);
|
||||
env_vars_to_export[0] = {"PATH", new_path};
|
||||
get_export_unset_vars(envt, env_vars_to_export);
|
||||
envt.export_vars.push_back({"CONDA_PREFIX_" + std::to_string(old_conda_shlvl), old_conda_prefix});
|
||||
env_vars_to_export[0] = { "PATH", new_path };
|
||||
get_export_unset_vars(envt, env_vars_to_export);
|
||||
envt.export_vars.push_back(
|
||||
{ "CONDA_PREFIX_" + std::to_string(old_conda_shlvl), old_conda_prefix });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -698,25 +714,26 @@ namespace mamba
|
|||
return out.str();
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string>
|
||||
PosixActivator::update_prompt(const std::string& conda_prompt_modifier)
|
||||
std::pair<std::string, std::string> PosixActivator::update_prompt(
|
||||
const std::string& conda_prompt_modifier)
|
||||
{
|
||||
std::string ps1 = (m_env.find("PS1") != m_env.end()) ? m_env["PS1"] : "";
|
||||
if (ps1.find("POWERLINE_COMMAND") != ps1.npos)
|
||||
{
|
||||
// Defer to powerline (https://github.com/powerline/powerline) if it's in use.
|
||||
return {"", ""};
|
||||
// Defer to powerline (https://github.com/powerline/powerline) if it's in
|
||||
// use.
|
||||
return { "", "" };
|
||||
}
|
||||
std::string current_prompt_modifier = env::get("CONDA_PROMPT_MODIFIER");
|
||||
if (!current_prompt_modifier.empty())
|
||||
{
|
||||
replace_all(ps1, current_prompt_modifier, "");
|
||||
}
|
||||
// Because we're using single-quotes to set shell variables, we need to handle the
|
||||
// proper escaping of single quotes that are already part of the string.
|
||||
// Because we're using single-quotes to set shell variables, we need to handle
|
||||
// the proper escaping of single quotes that are already part of the string.
|
||||
// Best solution appears to be https://stackoverflow.com/a/1250279
|
||||
replace_all(ps1, "'", "'\"'\"'");
|
||||
return {"PS1", conda_prompt_modifier + ps1};
|
||||
return { "PS1", conda_prompt_modifier + ps1 };
|
||||
}
|
||||
|
||||
std::string PosixActivator::shell_extension()
|
||||
|
@ -774,9 +791,10 @@ namespace mamba
|
|||
return "";
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> CmdExeActivator::update_prompt(const std::string& conda_prompt_modifier)
|
||||
std::pair<std::string, std::string> CmdExeActivator::update_prompt(
|
||||
const std::string& conda_prompt_modifier)
|
||||
{
|
||||
return {"", ""};
|
||||
return { "", "" };
|
||||
}
|
||||
|
||||
std::string CmdExeActivator::script(const EnvironmentTransform& env_transform)
|
||||
|
@ -816,7 +834,8 @@ namespace mamba
|
|||
|
||||
std::ofstream out_file(tempfile_ptr->path());
|
||||
out_file << out.str();
|
||||
// note: we do not delete the tempfile ptr intentionally, so that the temp file stays
|
||||
// note: we do not delete the tempfile ptr intentionally, so that the temp
|
||||
// file stays
|
||||
return tempfile_ptr->path().string();
|
||||
}
|
||||
|
||||
|
@ -844,9 +863,10 @@ namespace mamba
|
|||
return Context::instance().root_prefix / "condabin" / "mamba_hook.ps1";
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> PowerShellActivator::update_prompt(const std::string& conda_prompt_modifier)
|
||||
std::pair<std::string, std::string> PowerShellActivator::update_prompt(
|
||||
const std::string& conda_prompt_modifier)
|
||||
{
|
||||
return {"", ""};
|
||||
return { "", "" };
|
||||
}
|
||||
|
||||
std::string PowerShellActivator::script(const EnvironmentTransform& env_transform)
|
||||
|
@ -906,9 +926,10 @@ namespace mamba
|
|||
return Context::instance().root_prefix / "etc" / "profile.d" / "mamba.xsh";
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> XonshActivator::update_prompt(const std::string& conda_prompt_modifier)
|
||||
std::pair<std::string, std::string> XonshActivator::update_prompt(
|
||||
const std::string& conda_prompt_modifier)
|
||||
{
|
||||
return {"", ""};
|
||||
return { "", "" };
|
||||
}
|
||||
|
||||
std::string XonshActivator::script(const EnvironmentTransform& env_transform)
|
||||
|
@ -947,4 +968,4 @@ namespace mamba
|
|||
|
||||
return out.str();
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
192
src/channel.cpp
192
src/channel.cpp
|
@ -4,6 +4,8 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "channel.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
|
@ -11,7 +13,6 @@
|
|||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "context.hpp"
|
||||
#include "package_handling.hpp"
|
||||
#include "url.hpp"
|
||||
|
@ -22,50 +23,32 @@ namespace mamba
|
|||
// Constants used by Channel and ChannelContext
|
||||
namespace
|
||||
{
|
||||
const std::string DEFAULT_CHANNEL_ALIAS = "https://conda.anaconda.org";
|
||||
const std::map<std::string, std::string> DEFAULT_CUSTOM_CHANNELS = {{"pkgs/pro", "https://repo.anaconda.com"}};
|
||||
const std::string UNKNOWN_CHANNEL = "<unknown>";
|
||||
const char DEFAULT_CHANNEL_ALIAS[] = "https://conda.anaconda.org";
|
||||
const std::map<std::string, std::string> DEFAULT_CUSTOM_CHANNELS
|
||||
= { { "pkgs/pro", "https://repo.anaconda.com" } };
|
||||
const char UNKNOWN_CHANNEL[] = "<unknown>";
|
||||
|
||||
const std::set<std::string> INVALID_CHANNELS =
|
||||
{
|
||||
"<unknown>",
|
||||
"None:///<unknown>",
|
||||
"None",
|
||||
"",
|
||||
":///<unknown>"
|
||||
};
|
||||
const std::set<std::string> INVALID_CHANNELS
|
||||
= { "<unknown>", "None:///<unknown>", "None", "", ":///<unknown>" };
|
||||
|
||||
const std::string LOCAL_CHANNELS_NAME = "local";
|
||||
const std::string DEFAULT_CHANNELS_NAME = "defaults";
|
||||
const char LOCAL_CHANNELS_NAME[] = "local";
|
||||
const char DEFAULT_CHANNELS_NAME[] = "defaults";
|
||||
|
||||
const std::vector<std::string> DEFAULT_CHANNELS =
|
||||
{
|
||||
const std::vector<std::string> DEFAULT_CHANNELS = {
|
||||
#ifdef _WIN32
|
||||
"https://repo.anaconda.com/pkgs/main",
|
||||
"https://repo.anaconda.com/pkgs/r",
|
||||
"https://repo.anaconda.com/pkgs/msys2"
|
||||
#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
|
||||
};
|
||||
|
||||
const std::vector<std::string> KNOWN_PLATFORMS =
|
||||
{
|
||||
"noarch",
|
||||
"linux-32",
|
||||
"linux-64",
|
||||
"linux-aarch64",
|
||||
"linux-armv6l",
|
||||
"linux-armv7l",
|
||||
"linux-ppc64",
|
||||
"linux-ppc64le",
|
||||
"osx-64",
|
||||
"win-32",
|
||||
"win-64",
|
||||
"zos-z"
|
||||
};
|
||||
}
|
||||
const std::vector<std::string> KNOWN_PLATFORMS
|
||||
= { "noarch", "linux-32", "linux-64", "linux-aarch64",
|
||||
"linux-armv6l", "linux-armv7l", "linux-ppc64", "linux-ppc64le",
|
||||
"osx-64", "win-32", "win-64", "zos-z" };
|
||||
} // namespace
|
||||
|
||||
/**************************
|
||||
* Channel implementation *
|
||||
|
@ -162,9 +145,7 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
std::string Channel::build_url(const std::string& base,
|
||||
bool with_credential) const
|
||||
|
||||
std::string Channel::build_url(const std::string& base, bool with_credential) const
|
||||
{
|
||||
if (with_credential && auth() != "")
|
||||
{
|
||||
|
@ -209,13 +190,12 @@ namespace mamba
|
|||
std::vector<std::string> Channel::urls(const std::vector<std::string>& platforms,
|
||||
bool with_credential) const
|
||||
{
|
||||
|
||||
if (canonical_name() == UNKNOWN_CHANNEL)
|
||||
return make_channel(DEFAULT_CHANNELS_NAME).urls(platforms, with_credential);
|
||||
|
||||
std::string base = with_credential && token() != ""
|
||||
? join_url(location(), "t", token(), name())
|
||||
: join_url(location(), name());
|
||||
? join_url(location(), "t", token(), name())
|
||||
: join_url(location(), name());
|
||||
|
||||
size_t size = platform() != "" ? (platform() != "noarch" ? 2u : 1u) : platforms.size();
|
||||
std::vector<std::string> res(size);
|
||||
|
@ -229,15 +209,14 @@ namespace mamba
|
|||
}
|
||||
else
|
||||
{
|
||||
std::transform(platforms.cbegin(), platforms.cend(), res.begin(),
|
||||
[this, &base, with_credential](const std::string& p)
|
||||
{
|
||||
return this->build_url(join_url(base, p), with_credential);
|
||||
}
|
||||
);
|
||||
std::transform(platforms.cbegin(),
|
||||
platforms.cend(),
|
||||
res.begin(),
|
||||
[this, &base, with_credential](const std::string& p) {
|
||||
return this->build_url(join_url(base, p), with_credential);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -248,11 +227,7 @@ namespace mamba
|
|||
{
|
||||
std::string name(channel_name);
|
||||
std::string location, scheme, auth, token;
|
||||
split_scheme_auth_token(channel_url,
|
||||
location,
|
||||
scheme,
|
||||
auth,
|
||||
token);
|
||||
split_scheme_auth_token(channel_url, location, scheme, auth, token);
|
||||
if (scheme == "")
|
||||
{
|
||||
location = channel_alias.location();
|
||||
|
@ -260,7 +235,7 @@ namespace mamba
|
|||
auth = channel_alias.auth();
|
||||
token = channel_alias.token();
|
||||
}
|
||||
else if(name == "")
|
||||
else if (name == "")
|
||||
{
|
||||
if (channel_alias.location() != "" && starts_with(location, channel_alias.location()))
|
||||
{
|
||||
|
@ -272,7 +247,8 @@ namespace mamba
|
|||
{
|
||||
std::string full_url = scheme + "://" + location;
|
||||
URLHandler parser(full_url);
|
||||
location = rstrip(URLHandler().set_host(parser.host()).set_port(parser.port()).url(), "/");
|
||||
location = rstrip(
|
||||
URLHandler().set_host(parser.host()).set_port(parser.port()).url(), "/");
|
||||
name = lstrip(parser.path(), "/");
|
||||
}
|
||||
}
|
||||
|
@ -363,14 +339,17 @@ namespace mamba
|
|||
const std::string& path)
|
||||
{
|
||||
std::string spath = std::string(rstrip(path, "/"));
|
||||
std::string url = URLHandler().set_scheme(scheme).set_host(host).set_port(port).set_path(spath).url(true);
|
||||
std::string url
|
||||
= URLHandler().set_scheme(scheme).set_host(host).set_port(port).set_path(spath).url(
|
||||
true);
|
||||
|
||||
// Case 1: No path given, channel name is ""
|
||||
if (spath == "")
|
||||
{
|
||||
URLHandler handler;
|
||||
handler.set_host(host).set_port(port);
|
||||
return channel_configuration(std::string(rstrip(handler.url(), "/")), "", scheme, "", "");
|
||||
return channel_configuration(
|
||||
std::string(rstrip(handler.url(), "/")), "", scheme, "", "");
|
||||
}
|
||||
|
||||
// Case 2: migrated_custom_channels not implemented yet
|
||||
|
@ -378,11 +357,13 @@ namespace mamba
|
|||
|
||||
// Case 4: custom_channels matches
|
||||
const auto& custom_channels = ChannelContext::instance().get_custom_channels();
|
||||
for (const auto& ca: custom_channels)
|
||||
for (const auto& ca : custom_channels)
|
||||
{
|
||||
const Channel& channel = ca.second;
|
||||
std::string test_url = join_url(channel.location(), channel.name());
|
||||
if (starts_with(url, test_url)) // original code splits with '/' and compares tokens
|
||||
|
||||
// original code splits with '/' and compares tokens
|
||||
if (starts_with(url, test_url))
|
||||
{
|
||||
auto subname = std::string(strip(url.replace(0u, test_url.size(), ""), "/"));
|
||||
return channel_configuration(channel.location(),
|
||||
|
@ -405,16 +386,12 @@ namespace mamba
|
|||
if (host == "")
|
||||
{
|
||||
auto sp = rsplit(url, "/", 1);
|
||||
return channel_configuration(sp[0].size() ? sp[0] : "/",
|
||||
sp[1],
|
||||
"file",
|
||||
"",
|
||||
"");
|
||||
return channel_configuration(sp[0].size() ? sp[0] : "/", sp[1], "file", "", "");
|
||||
}
|
||||
|
||||
// Case 7: fallback, channel_location = host:port and channel_name = path,
|
||||
// bumps the first token of paths starting with /conda for compatibiliy
|
||||
// with Anaconda Enterprise Repository software
|
||||
// bumps the first token of paths starting with /conda for
|
||||
// compatibiliy with Anaconda Enterprise Repository software
|
||||
spath = lstrip(spath, "/");
|
||||
std::string bump = "";
|
||||
if (starts_with(spath, "conda"))
|
||||
|
@ -423,11 +400,7 @@ namespace mamba
|
|||
spath = spath.replace(0, 6, "");
|
||||
}
|
||||
std::string location = URLHandler().set_host(host).set_port(port).set_path(bump).url();
|
||||
return channel_configuration(std::string(strip(location, "/")),
|
||||
spath,
|
||||
scheme,
|
||||
"",
|
||||
"");
|
||||
return channel_configuration(std::string(strip(location, "/")), spath, scheme, "", "");
|
||||
}
|
||||
|
||||
Channel Channel::from_url(const std::string& url)
|
||||
|
@ -435,10 +408,7 @@ namespace mamba
|
|||
std::string scheme, host, port, path, auth, token, platform, package_name;
|
||||
split_conda_url(url, scheme, host, port, path, auth, token, platform, package_name);
|
||||
|
||||
auto config = read_channel_configuration(scheme,
|
||||
host,
|
||||
port,
|
||||
path);
|
||||
auto config = read_channel_configuration(scheme, host, port, path);
|
||||
|
||||
return Channel(config.m_scheme.size() ? config.m_scheme : "https",
|
||||
auth.size() ? auth : config.m_auth,
|
||||
|
@ -485,12 +455,8 @@ namespace mamba
|
|||
else
|
||||
{
|
||||
const Channel& alias = ChannelContext::instance().get_channel_alias();
|
||||
return Channel(alias.scheme(),
|
||||
alias.auth(),
|
||||
alias.location(),
|
||||
alias.token(),
|
||||
stripped,
|
||||
platform);
|
||||
return Channel(
|
||||
alias.scheme(), alias.auth(), alias.location(), alias.token(), stripped, platform);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -568,12 +534,12 @@ namespace mamba
|
|||
std::set<std::string> control;
|
||||
std::vector<std::string> result;
|
||||
result.reserve(channel_names.size() * platforms.size());
|
||||
for (const auto& name: channel_names)
|
||||
for (const auto& name : channel_names)
|
||||
{
|
||||
auto multi_iter = ChannelContext::instance().get_custom_multichannels().find(name);
|
||||
if (multi_iter != ChannelContext::instance().get_custom_multichannels().end())
|
||||
{
|
||||
for (const auto& n: multi_iter->second)
|
||||
for (const auto& n : multi_iter->second)
|
||||
{
|
||||
append_channel_urls(n, platforms, with_credential, result, control);
|
||||
}
|
||||
|
@ -593,8 +559,8 @@ namespace mamba
|
|||
{
|
||||
// TODO that doesn't seem very logical
|
||||
std::vector<std::string> platforms = platform.size()
|
||||
? std::vector<std::string>({ platform, "noarch" })
|
||||
: Context::instance().platforms();
|
||||
? std::vector<std::string>({ platform, "noarch" })
|
||||
: Context::instance().platforms();
|
||||
|
||||
if (append_context_channels || use_local)
|
||||
{
|
||||
|
@ -624,21 +590,20 @@ namespace mamba
|
|||
if (whitelist.size())
|
||||
{
|
||||
std::vector<std::string> accepted_urls(whitelist.size());
|
||||
std::transform(whitelist.begin(), whitelist.end(), accepted_urls.begin(),
|
||||
[](const std::string& url) { return make_channel(url).base_url(); });
|
||||
std::for_each(urls.begin(), urls.end(), [&accepted_urls](const std::string& s)
|
||||
std::transform(whitelist.begin(),
|
||||
whitelist.end(),
|
||||
accepted_urls.begin(),
|
||||
[](const std::string& url) { return make_channel(url).base_url(); });
|
||||
std::for_each(urls.begin(), urls.end(), [&accepted_urls](const std::string& s) {
|
||||
auto it = std::find(
|
||||
accepted_urls.begin(), accepted_urls.end(), make_channel(s).base_url());
|
||||
if (it == accepted_urls.end())
|
||||
{
|
||||
auto it = std::find(accepted_urls.begin(),
|
||||
accepted_urls.end(),
|
||||
make_channel(s).base_url());
|
||||
if (it == accepted_urls.end())
|
||||
{
|
||||
std::ostringstream str;
|
||||
str << "Channel " << s << " not allowed";
|
||||
throw std::runtime_error(str.str().c_str());
|
||||
}
|
||||
std::ostringstream str;
|
||||
str << "Channel " << s << " not allowed";
|
||||
throw std::runtime_error(str.str().c_str());
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -684,11 +649,7 @@ namespace mamba
|
|||
Channel ChannelContext::build_channel_alias()
|
||||
{
|
||||
std::string location, scheme, auth, token;
|
||||
split_scheme_auth_token(DEFAULT_CHANNEL_ALIAS,
|
||||
location,
|
||||
scheme,
|
||||
auth,
|
||||
token);
|
||||
split_scheme_auth_token(DEFAULT_CHANNEL_ALIAS, location, scheme, auth, token);
|
||||
return Channel(scheme, auth, location, token);
|
||||
}
|
||||
|
||||
|
@ -701,9 +662,10 @@ namespace mamba
|
|||
// Default channels
|
||||
std::vector<std::string> default_names(DEFAULT_CHANNELS.size());
|
||||
auto name_iter = default_names.begin();
|
||||
for(auto& url: DEFAULT_CHANNELS)
|
||||
for (auto& url : DEFAULT_CHANNELS)
|
||||
{
|
||||
auto channel = Channel::make_simple_channel(m_channel_alias, url, "", DEFAULT_CHANNELS_NAME);
|
||||
auto channel
|
||||
= Channel::make_simple_channel(m_channel_alias, url, "", DEFAULT_CHANNELS_NAME);
|
||||
std::string name = channel.name();
|
||||
auto res = m_custom_channels.emplace(std::move(name), std::move(channel));
|
||||
*name_iter++ = res.first->first;
|
||||
|
@ -711,21 +673,20 @@ namespace mamba
|
|||
m_custom_multichannels.emplace(DEFAULT_CHANNELS_NAME, std::move(default_names));
|
||||
|
||||
// Local channels
|
||||
std::vector<std::string> local_channels =
|
||||
{
|
||||
Context::instance().target_prefix.string() + "/conda-bld",
|
||||
Context::instance().root_prefix.string() + "/conda-bld",
|
||||
"~/conda-bld"
|
||||
};
|
||||
std::vector<std::string> local_channels
|
||||
= { Context::instance().target_prefix.string() + "/conda-bld",
|
||||
Context::instance().root_prefix.string() + "/conda-bld",
|
||||
"~/conda-bld" };
|
||||
|
||||
std::vector<std::string> local_names;
|
||||
local_names.reserve(local_channels.size());
|
||||
for(const auto& p: local_channels)
|
||||
for (const auto& p : local_channels)
|
||||
{
|
||||
if (fs::is_directory(p))
|
||||
{
|
||||
std::string url = path_to_url(p);
|
||||
auto channel = Channel::make_simple_channel(m_channel_alias, url, "", LOCAL_CHANNELS_NAME);
|
||||
auto channel
|
||||
= Channel::make_simple_channel(m_channel_alias, url, "", LOCAL_CHANNELS_NAME);
|
||||
std::string name = channel.name();
|
||||
auto res = m_custom_channels.emplace(std::move(name), std::move(channel));
|
||||
local_names.push_back(res.first->first);
|
||||
|
@ -738,9 +699,10 @@ namespace mamba
|
|||
*******************/
|
||||
|
||||
// Default local channel
|
||||
for(auto& ch: DEFAULT_CUSTOM_CHANNELS)
|
||||
for (auto& ch : DEFAULT_CUSTOM_CHANNELS)
|
||||
{
|
||||
m_custom_channels.emplace(ch.first, Channel::make_simple_channel(m_channel_alias, ch.second, ch.first));
|
||||
m_custom_channels.emplace(
|
||||
ch.first, Channel::make_simple_channel(m_channel_alias, ch.second, ch.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#include "output.hpp"
|
||||
#include "util.hpp"
|
||||
#include "context.hpp"
|
||||
#include "thirdparty/termcolor.hpp"
|
||||
#include "thread_utils.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -18,45 +19,45 @@ namespace mamba
|
|||
{
|
||||
// armv6l and armv7l
|
||||
#if defined(__arm__) || defined(__thumb__)
|
||||
#ifdef ___ARM_ARCH_6__
|
||||
const std::string MAMBA_PLATFORM = "armv6l";
|
||||
#elif __ARM_ARCH_7__
|
||||
const std::string MAMBA_PLATFORM = "armv7l";
|
||||
#else
|
||||
#error "Unknown platform"
|
||||
#endif
|
||||
#elif _M_ARM==6
|
||||
const std::string MAMBA_PLATFORM = "armv6l";
|
||||
#elif _M_ARM==7
|
||||
const std::string MAMBA_PLATFORM = "armv7l";
|
||||
#ifdef ___ARM_ARCH_6__
|
||||
static const char MAMBA_PLATFORM[] = "armv6l";
|
||||
#elif __ARM_ARCH_7__
|
||||
static const char MAMBA_PLATFORM[] = "armv7l";
|
||||
#else
|
||||
#error "Unknown platform"
|
||||
#endif
|
||||
#elif _M_ARM == 6
|
||||
static const char MAMBA_PLATFORM[] = "armv6l";
|
||||
#elif _M_ARM == 7
|
||||
static const char MAMBA_PLATFORM[] = "armv7l";
|
||||
// aarch64
|
||||
#elif defined(__aarch64__)
|
||||
const std::string MAMBA_PLATFORM = "aarch64";
|
||||
static const char MAMBA_PLATFORM[] = "aarch64";
|
||||
#elif defined(__ppc64__) || defined(__powerpc64__)
|
||||
#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
const std::string MAMBA_PLATFORM = "ppc64";
|
||||
#else
|
||||
const std::string MAMBA_PLATFORM = "ppc64le";
|
||||
#endif
|
||||
#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
static const char MAMBA_PLATFORM[] = "ppc64";
|
||||
#else
|
||||
static const char MAMBA_PLATFORM[] = "ppc64le";
|
||||
#endif
|
||||
// Linux
|
||||
#elif defined(__linux__)
|
||||
#if __x86_64__
|
||||
const std::string MAMBA_PLATFORM = "linux-64";
|
||||
#else
|
||||
const std::string MAMBA_PLATFORM = "linux-32";
|
||||
#endif
|
||||
#if __x86_64__
|
||||
static const char MAMBA_PLATFORM[] = "linux-64";
|
||||
#else
|
||||
static const char MAMBA_PLATFORM[] = "linux-32";
|
||||
#endif
|
||||
// OSX
|
||||
#elif defined(__APPLE__) || defined(__MACH__)
|
||||
const std::string MAMBA_PLATFORM = "osx-64";
|
||||
static const char MAMBA_PLATFORM[] = "osx-64";
|
||||
// Windows
|
||||
#elif defined(_WIN64)
|
||||
const std::string MAMBA_PLATFORM = "win-64";
|
||||
#elif defined (_WIN32)
|
||||
const std::string MAMBA_PLATFORM = "win-32";
|
||||
static const char MAMBA_PLATFORM[] = "win-64";
|
||||
#elif defined(_WIN32)
|
||||
static const char MAMBA_PLATFORM[] = "win-32";
|
||||
#else
|
||||
#error "Unknown platform"
|
||||
#error "Unknown platform"
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
Context::Context()
|
||||
{
|
||||
set_verbosity(0);
|
||||
|
@ -144,4 +145,4 @@ namespace mamba
|
|||
|
||||
throw std::runtime_error("Environment name not found " + name);
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "fetch.hpp"
|
||||
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
|
||||
#include "context.hpp"
|
||||
#include "fetch.hpp"
|
||||
#include "util.hpp"
|
||||
#include "thread_utils.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -18,7 +19,9 @@ namespace mamba
|
|||
* DownloadTarget implementation *
|
||||
*********************************/
|
||||
|
||||
DownloadTarget::DownloadTarget(const std::string& name, const std::string& url, const std::string& filename)
|
||||
DownloadTarget::DownloadTarget(const std::string& name,
|
||||
const std::string& url,
|
||||
const std::string& filename)
|
||||
: m_name(name)
|
||||
, m_filename(filename)
|
||||
, m_url(url)
|
||||
|
@ -43,7 +46,8 @@ namespace mamba
|
|||
m_headers = nullptr;
|
||||
if (ends_with(url, ".json"))
|
||||
{
|
||||
curl_easy_setopt(m_handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate, compress, identity");
|
||||
curl_easy_setopt(
|
||||
m_handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate, compress, identity");
|
||||
m_headers = curl_slist_append(m_headers, "Content-Type: application/json");
|
||||
}
|
||||
curl_easy_setopt(m_handle, CURLOPT_HTTPHEADER, m_headers);
|
||||
|
@ -51,11 +55,12 @@ namespace mamba
|
|||
|
||||
curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
|
||||
// DO NOT SET TIMEOUT as it will also take into account multi-start time and it's just wrong
|
||||
// curl_easy_setopt(m_handle, CURLOPT_TIMEOUT, Context::instance().read_timeout_secs);
|
||||
// DO NOT SET TIMEOUT as it will also take into account multi-start time and
|
||||
// it's just wrong curl_easy_setopt(m_handle, CURLOPT_TIMEOUT,
|
||||
// Context::instance().read_timeout_secs);
|
||||
|
||||
// TODO while libcurl in conda now _has_ http2 support we need to fix mamba to work properly with it
|
||||
// this includes:
|
||||
// TODO while libcurl in conda now _has_ http2 support we need to fix mamba to
|
||||
// work properly with it this includes:
|
||||
// - setting the cache stuff correctly
|
||||
// - fixing how the progress bar works
|
||||
curl_easy_setopt(m_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||
|
@ -64,7 +69,8 @@ namespace mamba
|
|||
curl_easy_setopt(m_handle, CURLOPT_LOW_SPEED_TIME, 60L);
|
||||
curl_easy_setopt(m_handle, CURLOPT_LOW_SPEED_LIMIT, 30L);
|
||||
|
||||
curl_easy_setopt(m_handle, CURLOPT_CONNECTTIMEOUT, Context::instance().connect_timeout_secs);
|
||||
curl_easy_setopt(
|
||||
m_handle, CURLOPT_CONNECTTIMEOUT, Context::instance().connect_timeout_secs);
|
||||
|
||||
std::string& ssl_verify = Context::instance().ssl_verify;
|
||||
|
||||
|
@ -96,9 +102,8 @@ namespace mamba
|
|||
|
||||
bool DownloadTarget::can_retry()
|
||||
{
|
||||
return m_retries < size_t(Context::instance().max_retries) &&
|
||||
http_status >= 500 &&
|
||||
!starts_with(m_url, "file://");
|
||||
return m_retries < size_t(Context::instance().max_retries) && http_status >= 500
|
||||
&& !starts_with(m_url, "file://");
|
||||
}
|
||||
|
||||
CURL* DownloadTarget::retry()
|
||||
|
@ -115,7 +120,8 @@ namespace mamba
|
|||
init_curl_target(m_url);
|
||||
if (m_has_progress_bar)
|
||||
{
|
||||
curl_easy_setopt(m_handle, CURLOPT_XFERINFOFUNCTION, &DownloadTarget::progress_callback);
|
||||
curl_easy_setopt(
|
||||
m_handle, CURLOPT_XFERINFOFUNCTION, &DownloadTarget::progress_callback);
|
||||
curl_easy_setopt(m_handle, CURLOPT_XFERINFODATA, this);
|
||||
}
|
||||
m_retry_wait_seconds = m_retry_wait_seconds * Context::instance().retry_backoff;
|
||||
|
@ -135,16 +141,16 @@ namespace mamba
|
|||
curl_slist_free_all(m_headers);
|
||||
}
|
||||
|
||||
size_t DownloadTarget::write_callback(char *ptr, size_t size, size_t nmemb, void *self)
|
||||
size_t DownloadTarget::write_callback(char* ptr, size_t size, size_t nmemb, void* self)
|
||||
{
|
||||
auto* s = (DownloadTarget*)self;
|
||||
auto* s = reinterpret_cast<DownloadTarget*>(self);
|
||||
s->m_file.write(ptr, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
size_t DownloadTarget::header_callback(char *buffer, size_t size, size_t nitems, void *self)
|
||||
size_t DownloadTarget::header_callback(char* buffer, size_t size, size_t nitems, void* self)
|
||||
{
|
||||
auto* s = (DownloadTarget*)self;
|
||||
auto* s = reinterpret_cast<DownloadTarget*>(self);
|
||||
|
||||
std::string_view header(buffer, size * nitems);
|
||||
auto colon_idx = header.find(':');
|
||||
|
@ -177,7 +183,8 @@ namespace mamba
|
|||
return nitems * size;
|
||||
}
|
||||
|
||||
int DownloadTarget::progress_callback(void*, curl_off_t total_to_download, curl_off_t now_downloaded, curl_off_t, curl_off_t)
|
||||
int DownloadTarget::progress_callback(
|
||||
void*, curl_off_t total_to_download, curl_off_t now_downloaded, curl_off_t, curl_off_t)
|
||||
{
|
||||
if (Context::instance().quiet || Context::instance().json)
|
||||
{
|
||||
|
@ -199,7 +206,8 @@ namespace mamba
|
|||
|
||||
if ((total_to_download != 0 || m_expected_size != 0) && now_downloaded != 0)
|
||||
{
|
||||
double perc = double(now_downloaded) / double(total_to_download);
|
||||
double perc
|
||||
= static_cast<double>(now_downloaded) / static_cast<double>(total_to_download);
|
||||
std::stringstream postfix;
|
||||
postfix << std::setw(6);
|
||||
to_human_readable_filesize(postfix, now_downloaded);
|
||||
|
@ -234,11 +242,13 @@ namespace mamba
|
|||
|
||||
if (mod_etag.find("_etag") != mod_etag.end())
|
||||
{
|
||||
m_headers = curl_slist_append(m_headers, to_header("If-None-Match", mod_etag["_etag"]).c_str());
|
||||
m_headers = curl_slist_append(m_headers,
|
||||
to_header("If-None-Match", mod_etag["_etag"]).c_str());
|
||||
}
|
||||
if (mod_etag.find("_mod") != mod_etag.end())
|
||||
{
|
||||
m_headers = curl_slist_append(m_headers, to_header("If-Modified-Since", mod_etag["_mod"]).c_str());
|
||||
m_headers = curl_slist_append(m_headers,
|
||||
to_header("If-Modified-Since", mod_etag["_mod"]).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,11 +299,12 @@ namespace mamba
|
|||
curl_easy_getinfo(m_handle, CURLINFO_EFFECTIVE_URL, &effective_url);
|
||||
|
||||
std::stringstream err;
|
||||
err << "Download error (" << result << ") " <<
|
||||
curl_easy_strerror(result) << " [" << effective_url << "]";
|
||||
err << "Download error (" << result << ") " << curl_easy_strerror(result) << " ["
|
||||
<< effective_url << "]";
|
||||
LOG_WARNING << err.str();
|
||||
|
||||
m_next_retry = std::chrono::steady_clock::now() + std::chrono::seconds(m_retry_wait_seconds);
|
||||
m_next_retry
|
||||
= std::chrono::steady_clock::now() + std::chrono::seconds(m_retry_wait_seconds);
|
||||
m_progress_bar.set_progress(0);
|
||||
m_progress_bar.set_postfix(curl_easy_strerror(result));
|
||||
if (m_ignore_failure == false && can_retry() == false)
|
||||
|
@ -317,12 +328,14 @@ namespace mamba
|
|||
curl_easy_getinfo(m_handle, CURLINFO_EFFECTIVE_URL, &effective_url);
|
||||
curl_easy_getinfo(m_handle, CURLINFO_SIZE_DOWNLOAD_T, &downloaded_size);
|
||||
|
||||
LOG_INFO << "Transfer finalized, status: " << http_status << " [" << effective_url << "] " << downloaded_size << " bytes";
|
||||
LOG_INFO << "Transfer finalized, status: " << http_status << " [" << effective_url << "] "
|
||||
<< downloaded_size << " bytes";
|
||||
|
||||
if (http_status >= 500 && can_retry())
|
||||
{
|
||||
// this request didn't work!
|
||||
m_next_retry = std::chrono::steady_clock::now() + std::chrono::seconds(m_retry_wait_seconds);
|
||||
m_next_retry
|
||||
= std::chrono::steady_clock::now() + std::chrono::seconds(m_retry_wait_seconds);
|
||||
std::stringstream msg;
|
||||
msg << "Failed (" << http_status << "), retry in " << m_retry_wait_seconds << "s";
|
||||
m_progress_bar.set_progress(0);
|
||||
|
@ -354,8 +367,8 @@ namespace mamba
|
|||
MultiDownloadTarget::MultiDownloadTarget()
|
||||
{
|
||||
m_handle = curl_multi_init();
|
||||
curl_multi_setopt(m_handle, CURLMOPT_MAX_TOTAL_CONNECTIONS,
|
||||
Context::instance().max_parallel_downloads);
|
||||
curl_multi_setopt(
|
||||
m_handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, Context::instance().max_parallel_downloads);
|
||||
}
|
||||
|
||||
MultiDownloadTarget::~MultiDownloadTarget()
|
||||
|
@ -365,7 +378,8 @@ namespace mamba
|
|||
|
||||
void MultiDownloadTarget::add(DownloadTarget* target)
|
||||
{
|
||||
if (!target) return;
|
||||
if (!target)
|
||||
return;
|
||||
CURLMcode code = curl_multi_add_handle(m_handle, target->handle());
|
||||
if (code != CURLM_CALL_MULTI_PERFORM)
|
||||
{
|
||||
|
@ -380,7 +394,7 @@ namespace mamba
|
|||
bool MultiDownloadTarget::check_msgs(bool failfast)
|
||||
{
|
||||
int msgs_in_queue;
|
||||
CURLMsg *msg;
|
||||
CURLMsg* msg;
|
||||
|
||||
while ((msg = curl_multi_info_read(m_handle, &msgs_in_queue)))
|
||||
{
|
||||
|
@ -449,7 +463,7 @@ namespace mamba
|
|||
{
|
||||
CURLMcode code = curl_multi_perform(m_handle, &still_running);
|
||||
|
||||
if(code != CURLM_OK)
|
||||
if (code != CURLM_OK)
|
||||
{
|
||||
throw std::runtime_error(curl_multi_strerror(code));
|
||||
}
|
||||
|
@ -474,17 +488,17 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
long curl_timeout = -1;
|
||||
long curl_timeout = -1; // NOLINT(runtime/int)
|
||||
code = curl_multi_timeout(m_handle, &curl_timeout);
|
||||
if (code != CURLM_OK)
|
||||
{
|
||||
throw std::runtime_error(curl_multi_strerror(code));
|
||||
}
|
||||
|
||||
if (curl_timeout == 0) // No wait
|
||||
if (curl_timeout == 0) // No wait
|
||||
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;
|
||||
|
||||
int numfds;
|
||||
|
@ -494,10 +508,10 @@ namespace mamba
|
|||
throw std::runtime_error(curl_multi_strerror(code));
|
||||
}
|
||||
|
||||
if(!numfds)
|
||||
if (!numfds)
|
||||
{
|
||||
repeats++; // count number of repeated zero numfds
|
||||
if(repeats > 1)
|
||||
repeats++; // count number of repeated zero numfds
|
||||
if (repeats > 1)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
|
@ -506,8 +520,7 @@ namespace mamba
|
|||
{
|
||||
repeats = 0;
|
||||
}
|
||||
}
|
||||
while ((still_running || !m_retry_targets.empty()) && !is_sig_interrupted());
|
||||
} while ((still_running || !m_retry_targets.empty()) && !is_sig_interrupted());
|
||||
|
||||
if (is_sig_interrupted())
|
||||
{
|
||||
|
@ -517,4 +530,4 @@ namespace mamba
|
|||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "history.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "history.hpp"
|
||||
#include "fsutil.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
History::History(const std::string& prefix)
|
||||
: m_prefix(prefix),
|
||||
m_history_file_path(fs::path(m_prefix) / "conda-meta" / "history")
|
||||
: m_prefix(prefix)
|
||||
, m_history_file_path(fs::path(m_prefix) / "conda-meta" / "history")
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,8 @@ namespace mamba
|
|||
while (getline(in_file, line))
|
||||
{
|
||||
// line.strip()
|
||||
if (line.size() == 0) continue;
|
||||
if (line.size() == 0)
|
||||
continue;
|
||||
std::smatch base_match;
|
||||
if (std::regex_match(line, base_match, head_re))
|
||||
{
|
||||
|
@ -67,7 +68,6 @@ namespace mamba
|
|||
{
|
||||
req.cmd = rmatch[1].str();
|
||||
}
|
||||
|
||||
else if (std::regex_match(line, rmatch, conda_v_pat))
|
||||
{
|
||||
req.conda_version = rmatch[1].str();
|
||||
|
@ -234,8 +234,10 @@ namespace mamba
|
|||
out << "+" << link_dist << std::endl;
|
||||
}
|
||||
|
||||
auto specs_output = [](const std::string& action, const std::vector<std::string>& specs) -> std::string {
|
||||
if (specs.empty()) return "";
|
||||
auto specs_output = [](const std::string& action,
|
||||
const std::vector<std::string>& specs) -> std::string {
|
||||
if (specs.empty())
|
||||
return "";
|
||||
std::stringstream spec_ss;
|
||||
spec_ss << "# " << action << " specs: [";
|
||||
for (auto spec : specs)
|
||||
|
@ -253,4 +255,4 @@ namespace mamba
|
|||
out << specs_output("neutered", entry.neutered);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
281
src/link.cpp
281
src/link.cpp
|
@ -4,22 +4,24 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "link.hpp"
|
||||
#include "output.hpp"
|
||||
#include "validate.hpp"
|
||||
#include "environment.hpp"
|
||||
#include "util.hpp"
|
||||
#include "match_spec.hpp"
|
||||
#include "transaction_context.hpp"
|
||||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "environment.hpp"
|
||||
#include "match_spec.hpp"
|
||||
#include "output.hpp"
|
||||
#include "thirdparty/subprocess.hpp"
|
||||
#include "transaction_context.hpp"
|
||||
#include "util.hpp"
|
||||
#include "validate.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
void python_entry_point_template(std::ostream& out,
|
||||
const python_entry_point_parsed& p)
|
||||
void python_entry_point_template(std::ostream& out, const python_entry_point_parsed& p)
|
||||
{
|
||||
auto import_name = split(p.func, ".")[0];
|
||||
out << "# -*- coding: utf-8 -*-\n";
|
||||
|
@ -29,11 +31,13 @@ namespace mamba
|
|||
out << "from " << p.module << " import " << import_name << "\n\n";
|
||||
|
||||
out << "if __name__ == '__main__':\n";
|
||||
out << " sys.argv[0] = re.sub(r'(-script\\.pyw?|\\.exe)?$', '', sys.argv[0])\n";
|
||||
out << " sys.argv[0] = re.sub(r'(-script\\.pyw?|\\.exe)?$', '', "
|
||||
"sys.argv[0])\n";
|
||||
out << " sys.exit(" << p.func << "())\n";
|
||||
}
|
||||
|
||||
void application_entry_point_template(std::ostream& out, const std::string_view& source_full_path)
|
||||
void application_entry_point_template(std::ostream& out,
|
||||
const std::string_view& source_full_path)
|
||||
{
|
||||
out << "# -*- coding: utf-8 -*-\n";
|
||||
out << "if __name__ == '__main__':\n";
|
||||
|
@ -64,7 +68,8 @@ namespace mamba
|
|||
auto py_file_stem = py_path.stem();
|
||||
std::string py_ver_nodot = py_ver;
|
||||
replace_all(py_ver_nodot, ".", "");
|
||||
return directory / fs::path("__pycache__") / concat(py_file_stem.c_str(), ".cpython-", py_ver_nodot, ".pyc");
|
||||
return directory / fs::path("__pycache__")
|
||||
/ concat(py_file_stem.c_str(), ".cpython-", py_ver_nodot, ".pyc");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,12 +97,16 @@ namespace mamba
|
|||
auto path_begin = shebang.find_first_not_of(WHITESPACES);
|
||||
auto path_end = shebang.substr(path_begin).find_first_not_of(WHITESPACES);
|
||||
fs::path shebang_path = shebang.substr(path_begin, path_end);
|
||||
return concat("#!/usr/bin/env ", std::string(shebang_path.filename()), " ", shebang.substr(path_end));
|
||||
return concat("#!/usr/bin/env ",
|
||||
std::string(shebang_path.filename()),
|
||||
" ",
|
||||
shebang.substr(path_end));
|
||||
}
|
||||
}
|
||||
|
||||
// for noarch python packages that have entry points
|
||||
auto LinkPackage::create_python_entry_point(const fs::path& path, const python_entry_point_parsed& entry_point)
|
||||
auto LinkPackage::create_python_entry_point(const fs::path& path,
|
||||
const python_entry_point_parsed& entry_point)
|
||||
{
|
||||
fs::path target = m_context->target_prefix / path;
|
||||
if (fs::exists(target))
|
||||
|
@ -105,15 +114,15 @@ namespace mamba
|
|||
throw std::runtime_error("clobber warning");
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// We add -script.py to WIN32, and link the conda.exe launcher which will automatically find
|
||||
// the correct script to launch
|
||||
#ifdef _WIN32
|
||||
// We add -script.py to WIN32, and link the conda.exe launcher which will
|
||||
// automatically find the correct script to launch
|
||||
std::string win_script = path;
|
||||
win_script += "-script.py";
|
||||
std::ofstream out_file(m_context->target_prefix / win_script);
|
||||
#else
|
||||
#else
|
||||
std::ofstream out_file(target);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
fs::path python_path;
|
||||
if (m_context->has_python)
|
||||
|
@ -137,11 +146,13 @@ namespace mamba
|
|||
python_entry_point_template(out_file, entry_point);
|
||||
out_file.close();
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
fs::path conda_exe = Context::instance().conda_prefix / "Scripts" / "conda.exe";
|
||||
if (!fs::exists(conda_exe))
|
||||
{
|
||||
throw std::runtime_error("Cannot link noarch package entrypoint conda.exe because conda.exe is not installed.");
|
||||
throw std::runtime_error(
|
||||
"Cannot link noarch package entrypoint conda.exe because conda.exe is "
|
||||
"not installed.");
|
||||
}
|
||||
fs::path script_exe = path;
|
||||
script_exe.replace_extension("exe");
|
||||
|
@ -154,14 +165,14 @@ namespace mamba
|
|||
LOG_INFO << "Linking exe " << conda_exe << " --> " << script_exe;
|
||||
fs::create_hard_link(conda_exe, m_context->target_prefix / script_exe);
|
||||
make_executable(m_context->target_prefix / script_exe);
|
||||
return std::array<std::string, 2>{win_script, script_exe};
|
||||
#else
|
||||
return std::array<std::string, 2>{ win_script, script_exe };
|
||||
#else
|
||||
if (!python_path.empty())
|
||||
{
|
||||
make_executable(target);
|
||||
}
|
||||
return path;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string ensure_pad(const std::string& str, char pad = '_')
|
||||
|
@ -189,16 +200,18 @@ namespace mamba
|
|||
|
||||
std::string win_path_double_escape(const std::string& path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
std::string path_copy = path;
|
||||
replace_all(path_copy, "\\", "\\\\");
|
||||
return path_copy;
|
||||
#else
|
||||
#else
|
||||
return path;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void create_application_entry_point(const fs::path& source_full_path, const fs::path& target_full_path, const fs::path& python_full_path)
|
||||
void create_application_entry_point(const fs::path& source_full_path,
|
||||
const fs::path& target_full_path,
|
||||
const fs::path& python_full_path)
|
||||
{
|
||||
// source_full_path: where the entry point file points to
|
||||
// target_full_path: the location of the new entry point file being created
|
||||
|
@ -220,10 +233,11 @@ namespace mamba
|
|||
make_executable(target_full_path);
|
||||
}
|
||||
|
||||
// def create_application_entry_point(source_full_path, target_full_path, python_full_path):
|
||||
// def create_application_entry_point(source_full_path, target_full_path,
|
||||
// python_full_path):
|
||||
// # source_full_path: where the entry point file points to
|
||||
// # target_full_path: the location of the new entry point file being created
|
||||
// if lexists(target_full_path):
|
||||
// # target_full_path: the location of the new entry point file being
|
||||
// created if lexists(target_full_path):
|
||||
// maybe_raise(BasicClobberError(
|
||||
// source_path=None,
|
||||
// target_path=target_full_path,
|
||||
|
@ -277,7 +291,8 @@ namespace mamba
|
|||
}
|
||||
if (!fs::is_regular_file(cmd_exe))
|
||||
{
|
||||
LOG_WARNING << "cmd.exe could not be found. Looked in SystemRoot and windir env vars.";
|
||||
LOG_WARNING << "cmd.exe could not be found. Looked in SystemRoot and "
|
||||
"windir env vars.";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -288,15 +303,15 @@ namespace mamba
|
|||
}
|
||||
|
||||
std::unique_ptr<TemporaryFile> wrap_call(const fs::path& root_prefix,
|
||||
const fs::path& prefix,
|
||||
bool dev_mode,
|
||||
bool debug_wrapper_scripts,
|
||||
const std::vector<std::string>& arguments)
|
||||
const fs::path& prefix,
|
||||
bool dev_mode,
|
||||
bool debug_wrapper_scripts,
|
||||
const std::vector<std::string>& arguments)
|
||||
{
|
||||
// todo add abspath here
|
||||
fs::path tmp_prefix = prefix / ".tmp";
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
ensure_comspec_set();
|
||||
std::string comspec = env::get("COMSPEC");
|
||||
std::string conda_bat;
|
||||
|
@ -322,12 +337,15 @@ namespace mamba
|
|||
std::ofstream out(tf->path());
|
||||
|
||||
std::string silencer;
|
||||
if (!debug_wrapper_scripts) silencer = "@";
|
||||
if (!debug_wrapper_scripts)
|
||||
silencer = "@";
|
||||
|
||||
out << silencer << "ECHO OFF\n";
|
||||
out << silencer << "SET PYTHONIOENCODING=utf-8\n";
|
||||
out << silencer << "SET PYTHONUTF8=1\n";
|
||||
out << silencer << "FOR /F \"tokens=2 delims=:.\" %%A in (\'chcp\') do for %%B in (%%A) do set \"_CONDA_OLD_CHCP=%%B\"\n";
|
||||
out << silencer
|
||||
<< "FOR /F \"tokens=2 delims=:.\" %%A in (\'chcp\') do for %%B in (%%A) "
|
||||
"do set \"_CONDA_OLD_CHCP=%%B\"\n";
|
||||
out << silencer << "chcp 65001 > NUL\n";
|
||||
|
||||
if (dev_mode)
|
||||
|
@ -338,7 +356,9 @@ namespace mamba
|
|||
// 'python -m conda'
|
||||
// *with* PYTHONPATH set.
|
||||
out << silencer << "SET PYTHONPATH=" << CONDA_PACKAGE_ROOT << "\n";
|
||||
out << silencer << "SET CONDA_EXE=" << "python.exe" << "\n"; // TODO this should be `sys.executable`
|
||||
out << silencer << "SET CONDA_EXE="
|
||||
<< "python.exe"
|
||||
<< "\n"; // TODO this should be `sys.executable`
|
||||
out << silencer << "SET _CE_M=-m\n";
|
||||
out << silencer << "SET _CE_CONDA=conda\n";
|
||||
}
|
||||
|
@ -357,11 +377,11 @@ namespace mamba
|
|||
out << "SET 1>&2\n";
|
||||
}
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
// During tests, we sometimes like to have a temp env with e.g. an old python in it
|
||||
// and have it run tests against the very latest development sources. For that to
|
||||
// work we need extra smarts here, we want it to be instead:
|
||||
// During tests, we sometimes like to have a temp env with e.g. an old python
|
||||
// in it and have it run tests against the very latest development sources.
|
||||
// For that to work we need extra smarts here, we want it to be instead:
|
||||
std::string shebang;
|
||||
std::string dev_arg;
|
||||
if (dev_mode)
|
||||
|
@ -409,9 +429,8 @@ namespace mamba
|
|||
<< ">&2 env\n";
|
||||
}
|
||||
|
||||
out << "\n"
|
||||
<< join(" ", arguments);
|
||||
#endif
|
||||
out << "\n" << join(" ", arguments);
|
||||
#endif
|
||||
|
||||
out.close();
|
||||
|
||||
|
@ -419,27 +438,32 @@ namespace mamba
|
|||
}
|
||||
|
||||
/*
|
||||
call the post-link or pre-unlink script and return true / false on success / failure
|
||||
call the post-link or pre-unlink script and return true / false on success /
|
||||
failure
|
||||
*/
|
||||
bool run_script(const fs::path& prefix, const PackageInfo& pkg_info,
|
||||
bool run_script(const fs::path& prefix,
|
||||
const PackageInfo& pkg_info,
|
||||
const std::string& action = "post-link",
|
||||
const std::string& env_prefix = "",
|
||||
bool activate = false)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
auto path = prefix / get_bin_directory_short_path() / concat(".", pkg_info.name, "-", action, ".bat");
|
||||
#else
|
||||
auto path = prefix / get_bin_directory_short_path() / concat(".", pkg_info.name, "-", action, ".sh");
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
auto path = prefix / get_bin_directory_short_path()
|
||||
/ concat(".", pkg_info.name, "-", action, ".bat");
|
||||
#else
|
||||
auto path = prefix / get_bin_directory_short_path()
|
||||
/ concat(".", pkg_info.name, "-", action, ".sh");
|
||||
#endif
|
||||
|
||||
if (!fs::exists(path))
|
||||
{
|
||||
LOG_INFO << action << " script for " << pkg_info.name << " does not exist (" << path << ")";
|
||||
LOG_INFO << action << " script for " << pkg_info.name << " does not exist (" << path
|
||||
<< ")";
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO impl.
|
||||
std::map<std::string, std::string> envmap; // = env::copy();
|
||||
std::map<std::string, std::string> envmap; // = env::copy();
|
||||
|
||||
if (action == "pre-link")
|
||||
{
|
||||
|
@ -450,27 +474,31 @@ namespace mamba
|
|||
std::vector<std::string> command_args;
|
||||
std::unique_ptr<TemporaryFile> script_file;
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
ensure_comspec_set();
|
||||
std::string comspec = env::get("COMSPEC");
|
||||
if (comspec.size() == 0)
|
||||
{
|
||||
LOG_ERROR << "Failed to run " << action << " for " << pkg_info.name << " due to COMSPEC not set in env vars.";
|
||||
LOG_ERROR << "Failed to run " << action << " for " << pkg_info.name
|
||||
<< " due to COMSPEC not set in env vars.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (activate)
|
||||
{
|
||||
script_file = wrap_call(Context::instance().root_prefix, prefix,
|
||||
Context::instance().dev, false, {"@CALL", path});
|
||||
script_file = wrap_call(Context::instance().root_prefix,
|
||||
prefix,
|
||||
Context::instance().dev,
|
||||
false,
|
||||
{ "@CALL", path });
|
||||
|
||||
command_args = {comspec, "/d", "/c", script_file->path()};
|
||||
command_args = { comspec, "/d", "/c", script_file->path() };
|
||||
}
|
||||
else
|
||||
{
|
||||
command_args = {comspec, "/d", "/c", path};
|
||||
command_args = { comspec, "/d", "/c", path };
|
||||
}
|
||||
#else
|
||||
#else
|
||||
// shell_path = 'sh' if 'bsd' in sys.platform else 'bash'
|
||||
fs::path shell_path = env::which("bash");
|
||||
if (shell_path.empty())
|
||||
|
@ -481,13 +509,11 @@ namespace mamba
|
|||
if (activate)
|
||||
{
|
||||
// std::string caller
|
||||
script_file = wrap_call(
|
||||
Context::instance().root_prefix,
|
||||
prefix,
|
||||
Context::instance().dev,
|
||||
false,
|
||||
{".", path}
|
||||
);
|
||||
script_file = wrap_call(Context::instance().root_prefix,
|
||||
prefix,
|
||||
Context::instance().dev,
|
||||
false,
|
||||
{ ".", path });
|
||||
command_args.push_back(shell_path);
|
||||
command_args.push_back(script_file->path());
|
||||
}
|
||||
|
@ -497,7 +523,7 @@ namespace mamba
|
|||
command_args.push_back("-x");
|
||||
command_args.push_back(path);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
envmap["ROOT_PREFIX"] = Context::instance().root_prefix;
|
||||
envmap["PREFIX"] = env_prefix.size() ? env_prefix : std::string(prefix);
|
||||
|
@ -509,10 +535,12 @@ namespace mamba
|
|||
|
||||
std::string cargs = join(" ", command_args);
|
||||
envmap["PATH"] = concat(path.parent_path().c_str(), env::pathsep(), PATH);
|
||||
LOG_DEBUG << "For " << pkg_info.name << " at " << envmap["PREFIX"] << ", executing script: $ " << cargs;
|
||||
LOG_DEBUG << "For " << pkg_info.name << " at " << envmap["PREFIX"]
|
||||
<< ", executing script: $ " << cargs;
|
||||
LOG_WARNING << "Calling " << cargs;
|
||||
|
||||
int response = subprocess::call(cargs, subprocess::environment{envmap}, subprocess::cwd{path.parent_path()});
|
||||
int response = subprocess::call(
|
||||
cargs, subprocess::environment{ envmap }, subprocess::cwd{ path.parent_path() });
|
||||
auto msg = get_prefix_messages(envmap["PREFIX"]);
|
||||
if (Context::instance().json)
|
||||
{
|
||||
|
@ -536,7 +564,9 @@ namespace mamba
|
|||
return true;
|
||||
}
|
||||
|
||||
UnlinkPackage::UnlinkPackage(const PackageInfo& pkg_info, const fs::path& cache_path, TransactionContext* context)
|
||||
UnlinkPackage::UnlinkPackage(const PackageInfo& pkg_info,
|
||||
const fs::path& cache_path,
|
||||
TransactionContext* context)
|
||||
: m_pkg_info(pkg_info)
|
||||
, m_cache_path(cache_path)
|
||||
, m_specifier(m_pkg_info.str())
|
||||
|
@ -588,7 +618,9 @@ namespace mamba
|
|||
return lp.execute();
|
||||
}
|
||||
|
||||
LinkPackage::LinkPackage(const PackageInfo& pkg_info, const fs::path& cache_path, TransactionContext* context)
|
||||
LinkPackage::LinkPackage(const PackageInfo& pkg_info,
|
||||
const fs::path& cache_path,
|
||||
TransactionContext* context)
|
||||
: m_pkg_info(pkg_info)
|
||||
, m_cache_path(cache_path)
|
||||
, m_source(cache_path / m_pkg_info.str())
|
||||
|
@ -596,7 +628,8 @@ namespace mamba
|
|||
{
|
||||
}
|
||||
|
||||
std::tuple<std::string, std::string> LinkPackage::link_path(const PathData& path_data, bool noarch_python)
|
||||
std::tuple<std::string, std::string> LinkPackage::link_path(const PathData& path_data,
|
||||
bool noarch_python)
|
||||
{
|
||||
std::string subtarget = path_data.path;
|
||||
LOG_INFO << "linking path " << subtarget;
|
||||
|
@ -650,10 +683,11 @@ namespace mamba
|
|||
|
||||
std::string padding(path_data.prefix_placeholder.size() - new_prefix.size(), '\0');
|
||||
|
||||
auto binary_replace = [&](std::size_t pos, std::size_t end, const std::string& suffix) {
|
||||
std::string replacement = concat(new_prefix, suffix, padding);
|
||||
buffer.replace(pos, end - pos, replacement);
|
||||
};
|
||||
auto binary_replace
|
||||
= [&](std::size_t pos, std::size_t end, const std::string& suffix) {
|
||||
std::string replacement = concat(new_prefix, suffix, padding);
|
||||
buffer.replace(pos, end - pos, replacement);
|
||||
};
|
||||
|
||||
std::size_t pos = buffer.find(path_data.prefix_placeholder);
|
||||
while (pos != std::string::npos)
|
||||
|
@ -672,7 +706,9 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
auto open_mode = (path_data.file_mode == FileMode::BINARY) ? std::ios::out | std::ios::binary : std::ios::out;
|
||||
auto open_mode = (path_data.file_mode == FileMode::BINARY)
|
||||
? std::ios::out | std::ios::binary
|
||||
: std::ios::out;
|
||||
std::ofstream fo(dst, open_mode);
|
||||
fo << buffer;
|
||||
fo.close();
|
||||
|
@ -694,7 +730,8 @@ namespace mamba
|
|||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error(std::string("Path type not implemented: ") + std::to_string((int)path_data.path_type));
|
||||
throw std::runtime_error(std::string("Path type not implemented: ")
|
||||
+ std::to_string(static_cast<int>(path_data.path_type)));
|
||||
}
|
||||
// TODO we could also use the SHA256 sum of the paths json
|
||||
return std::make_tuple(validate::sha256sum(dst), rel_dst);
|
||||
|
@ -719,21 +756,26 @@ namespace mamba
|
|||
}
|
||||
all_py_files_f.close();
|
||||
// TODO use the real python file here?!
|
||||
std::vector<std::string> command = {
|
||||
m_context->target_prefix / m_context->python_path,
|
||||
"-Wi", "-m", "compileall", "-q", "-l", "-i",
|
||||
all_py_files.path()
|
||||
};
|
||||
std::vector<std::string> command = { m_context->target_prefix / m_context->python_path,
|
||||
"-Wi",
|
||||
"-m",
|
||||
"compileall",
|
||||
"-q",
|
||||
"-l",
|
||||
"-i",
|
||||
all_py_files.path() };
|
||||
|
||||
auto py_ver_split = split(m_context->python_version, ".");
|
||||
|
||||
if (std::stoi(std::string(py_ver_split[0])) >= 3 && std::stoi(std::string(py_ver_split[1])) > 5)
|
||||
if (std::stoi(std::string(py_ver_split[0])) >= 3
|
||||
&& std::stoi(std::string(py_ver_split[1])) > 5)
|
||||
{
|
||||
// activate parallel pyc compilation
|
||||
command.push_back("-j0");
|
||||
}
|
||||
|
||||
auto out = subprocess::check_output(command, subprocess::cwd{std::string(m_context->target_prefix)});
|
||||
auto out = subprocess::check_output(
|
||||
command, subprocess::cwd{ std::string(m_context->target_prefix) });
|
||||
|
||||
return pyc_files;
|
||||
}
|
||||
|
@ -790,13 +832,12 @@ namespace mamba
|
|||
paths_json["paths_version"] = 1;
|
||||
for (auto& path : paths_data)
|
||||
{
|
||||
auto [sha256_in_prefix, final_path] = link_path(path, noarch_type == NoarchType::PYTHON);
|
||||
auto [sha256_in_prefix, final_path]
|
||||
= link_path(path, noarch_type == NoarchType::PYTHON);
|
||||
files_record.push_back(final_path);
|
||||
|
||||
nlohmann::json json_record = {
|
||||
{"_path", final_path},
|
||||
{"sha256_in_prefix", sha256_in_prefix}
|
||||
};
|
||||
nlohmann::json json_record
|
||||
= { { "_path", final_path }, { "sha256_in_prefix", sha256_in_prefix } };
|
||||
|
||||
if (!path.sha256.empty())
|
||||
{
|
||||
|
@ -829,9 +870,9 @@ namespace mamba
|
|||
paths_json["paths"].push_back(json_record);
|
||||
}
|
||||
|
||||
std::string f_name = index_json["name"].get<std::string>() + "-" +
|
||||
index_json["version"].get<std::string>() + "-" +
|
||||
index_json["build"].get<std::string>();
|
||||
std::string f_name = index_json["name"].get<std::string>() + "-"
|
||||
+ index_json["version"].get<std::string>() + "-"
|
||||
+ index_json["build"].get<std::string>();
|
||||
|
||||
out_json = index_json;
|
||||
out_json["paths_data"] = paths_json;
|
||||
|
@ -841,10 +882,7 @@ namespace mamba
|
|||
out_json["extracted_package_dir"] = m_source;
|
||||
|
||||
// TODO find out what `1` means
|
||||
out_json["link"] = {
|
||||
{"source", std::string(m_source)},
|
||||
{"type", 1}
|
||||
};
|
||||
out_json["link"] = { { "source", std::string(m_source) }, { "type", 1 } };
|
||||
|
||||
if (noarch_type == NoarchType::PYTHON)
|
||||
{
|
||||
|
@ -862,7 +900,8 @@ namespace mamba
|
|||
{
|
||||
if (std::regex_match(sub_path_json.path, py_file_re))
|
||||
{
|
||||
for_compilation.push_back(get_python_noarch_target_path(sub_path_json.path, m_context->site_packages_path));
|
||||
for_compilation.push_back(get_python_noarch_target_path(
|
||||
sub_path_json.path, m_context->site_packages_path));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -871,46 +910,36 @@ namespace mamba
|
|||
for (const fs::path& pyc_path : pyc_files)
|
||||
{
|
||||
out_json["paths_data"]["paths"].push_back(
|
||||
{
|
||||
{"_path", std::string(pyc_path)},
|
||||
{"path_type", "pyc_file"}
|
||||
});
|
||||
{ { "_path", std::string(pyc_path) }, { "path_type", "pyc_file" } });
|
||||
|
||||
out_json["files"].push_back(pyc_path);
|
||||
}
|
||||
|
||||
if (link_json.find("noarch") != link_json.end() &&
|
||||
link_json["noarch"].find("entry_points") != link_json["noarch"].end())
|
||||
if (link_json.find("noarch") != link_json.end()
|
||||
&& link_json["noarch"].find("entry_points") != link_json["noarch"].end())
|
||||
{
|
||||
for (auto& ep : link_json["noarch"]["entry_points"])
|
||||
{
|
||||
// install entry points
|
||||
auto entry_point_parsed = parse_entry_point(ep.get<std::string>());
|
||||
auto entry_point_path = get_bin_directory_short_path() / entry_point_parsed.command;
|
||||
auto entry_point_path
|
||||
= get_bin_directory_short_path() / entry_point_parsed.command;
|
||||
LOG_INFO << "entry point path: " << entry_point_path << std::endl;
|
||||
auto files = create_python_entry_point(entry_point_path, entry_point_parsed);
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
out_json["paths_data"]["paths"].push_back(
|
||||
{
|
||||
{"_path", files[0]},
|
||||
{"path_type", "win_python_entry_point"}
|
||||
});
|
||||
{ { "_path", files[0] }, { "path_type", "win_python_entry_point" } });
|
||||
out_json["paths_data"]["paths"].push_back(
|
||||
{
|
||||
{"_path", files[1]},
|
||||
{"path_type", "windows_python_entry_point_exe"}
|
||||
});
|
||||
{ { "_path", files[1] },
|
||||
{ "path_type", "windows_python_entry_point_exe" } });
|
||||
out_json["files"].push_back(files[0]);
|
||||
out_json["files"].push_back(files[1]);
|
||||
#else
|
||||
#else
|
||||
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);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -935,4 +964,4 @@ namespace mamba
|
|||
UnlinkPackage ulp(m_pkg_info, m_cache_path, m_context);
|
||||
return ulp.execute();
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
148
src/main.cpp
148
src/main.cpp
|
@ -10,12 +10,12 @@
|
|||
#include "activation.hpp"
|
||||
#include "channel.hpp"
|
||||
#include "context.hpp"
|
||||
#include "repo.hpp"
|
||||
#include "transaction.hpp"
|
||||
#include "prefix_data.hpp"
|
||||
#include "subdirdata.hpp"
|
||||
#include "solver.hpp"
|
||||
#include "repo.hpp"
|
||||
#include "shell_init.hpp"
|
||||
#include "solver.hpp"
|
||||
#include "subdirdata.hpp"
|
||||
#include "transaction.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
const char banner[] = R"MAMBARAW(
|
||||
|
@ -27,9 +27,10 @@ const char banner[] = R"MAMBARAW(
|
|||
/_/
|
||||
)MAMBARAW";
|
||||
|
||||
using namespace mamba;
|
||||
using namespace mamba; // NOLINT(build/namespaces)
|
||||
|
||||
static struct {
|
||||
static struct
|
||||
{
|
||||
bool hook;
|
||||
std::string shell_type;
|
||||
std::string action;
|
||||
|
@ -37,19 +38,22 @@ static struct {
|
|||
bool stack;
|
||||
} shell_options;
|
||||
|
||||
static struct {
|
||||
static struct
|
||||
{
|
||||
std::vector<std::string> specs;
|
||||
std::string prefix;
|
||||
std::string name;
|
||||
std::vector<std::string> channels;
|
||||
} create_options;
|
||||
|
||||
static struct {
|
||||
static struct
|
||||
{
|
||||
bool ssl_verify = true;
|
||||
std::string cacert_path;
|
||||
} network_options;
|
||||
|
||||
static struct {
|
||||
static struct
|
||||
{
|
||||
int verbosity = 0;
|
||||
bool always_yes = false;
|
||||
bool quiet = false;
|
||||
|
@ -58,32 +62,38 @@ static struct {
|
|||
bool dry_run = false;
|
||||
} global_options;
|
||||
|
||||
|
||||
void init_network_parser(CLI::App* subcom)
|
||||
void
|
||||
init_network_parser(CLI::App* subcom)
|
||||
{
|
||||
subcom->add_option("--ssl_verify", network_options.ssl_verify, "Enable or disable SSL verification");
|
||||
subcom->add_option(
|
||||
"--ssl_verify", network_options.ssl_verify, "Enable or disable SSL verification");
|
||||
subcom->add_option("--cacert_path", network_options.cacert_path, "Path for CA Certificate");
|
||||
}
|
||||
|
||||
void init_global_parser(CLI::App* subcom)
|
||||
void
|
||||
init_global_parser(CLI::App* subcom)
|
||||
{
|
||||
subcom->add_flag("-v,--verbose", global_options.verbosity, "Enbable verbose mode (higher verbosity with multiple -v, e.g. -vvv)");
|
||||
subcom->add_flag("-v,--verbose",
|
||||
global_options.verbosity,
|
||||
"Enbable verbose mode (higher verbosity with multiple -v, e.g. -vvv)");
|
||||
subcom->add_flag("-q,--quiet", global_options.quiet, "Quiet mode (print less output)");
|
||||
subcom->add_flag("-y,--yes", global_options.always_yes, "Automatically answer yes on all questions");
|
||||
subcom->add_flag(
|
||||
"-y,--yes", global_options.always_yes, "Automatically answer yes on all questions");
|
||||
subcom->add_flag("--json", global_options.json, "Report all output as json");
|
||||
subcom->add_flag("--offline", global_options.offline, "Force use cached repodata");
|
||||
subcom->add_flag("--dry-run", global_options.dry_run, "Only display what would have been done");
|
||||
}
|
||||
|
||||
void set_network_options(Context& ctx)
|
||||
void
|
||||
set_network_options(Context& ctx)
|
||||
{
|
||||
std::array<std::string, 6> cert_locations {
|
||||
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
|
||||
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
|
||||
"/etc/ssl/ca-bundle.pem", // OpenSUSE
|
||||
"/etc/pki/tls/cacert.pem", // OpenELEC
|
||||
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
|
||||
"/etc/ssl/cert.pem", // Alpine Linux
|
||||
std::array<std::string, 6> cert_locations{
|
||||
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
|
||||
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
|
||||
"/etc/ssl/ca-bundle.pem", // OpenSUSE
|
||||
"/etc/pki/tls/cacert.pem", // OpenELEC
|
||||
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
|
||||
"/etc/ssl/cert.pem", // Alpine Linux
|
||||
};
|
||||
|
||||
// ssl verify can be either an empty string (regular SSL verification),
|
||||
|
@ -114,7 +124,8 @@ void set_network_options(Context& ctx)
|
|||
}
|
||||
}
|
||||
|
||||
void set_global_options(Context& ctx)
|
||||
void
|
||||
set_global_options(Context& ctx)
|
||||
{
|
||||
ctx.set_verbosity(global_options.verbosity);
|
||||
ctx.quiet = global_options.quiet;
|
||||
|
@ -124,31 +135,40 @@ void set_global_options(Context& ctx)
|
|||
ctx.dry_run = global_options.dry_run;
|
||||
}
|
||||
|
||||
void init_channel_parser(CLI::App* subcom)
|
||||
void
|
||||
init_channel_parser(CLI::App* subcom)
|
||||
{
|
||||
subcom->add_option("-c,--channel", create_options.channels) \
|
||||
->type_size(1, 1) \
|
||||
->allow_extra_args(false);
|
||||
subcom->add_option("-c,--channel", create_options.channels)
|
||||
->type_size(1, 1)
|
||||
->allow_extra_args(false);
|
||||
}
|
||||
|
||||
void set_channels(Context& ctx)
|
||||
void
|
||||
set_channels(Context& ctx)
|
||||
{
|
||||
ctx.channels = create_options.channels;
|
||||
}
|
||||
|
||||
void init_shell_parser(CLI::App* subcom)
|
||||
void
|
||||
init_shell_parser(CLI::App* subcom)
|
||||
{
|
||||
subcom->add_option("-s,--shell", shell_options.shell_type, "A shell type (bash, fish, posix, powershell, xonsh)");
|
||||
subcom->add_option("--stack", shell_options.stack,
|
||||
"Stack the environment being activated on top of the previous active environment, "
|
||||
"rather replacing the current active environment with a new one. Currently, "
|
||||
"only the PATH environment variable is stacked. "
|
||||
"This may be enabled implicitly by the 'auto_stack' configuration variable."
|
||||
);
|
||||
subcom->add_option("-s,--shell",
|
||||
shell_options.shell_type,
|
||||
"A shell type (bash, fish, posix, powershell, xonsh)");
|
||||
subcom->add_option("--stack",
|
||||
shell_options.stack,
|
||||
"Stack the environment being activated on top of the "
|
||||
"previous active environment, "
|
||||
"rather replacing the current active environment with a "
|
||||
"new one. Currently, "
|
||||
"only the PATH environment variable is stacked. "
|
||||
"This may be enabled implicitly by the 'auto_stack' "
|
||||
"configuration variable.");
|
||||
|
||||
subcom->add_option("action", shell_options.action, "activate, deactivate or hook");
|
||||
// TODO add custom validator here!
|
||||
subcom->add_option("-p,--prefix", shell_options.prefix,
|
||||
subcom->add_option("-p,--prefix",
|
||||
shell_options.prefix,
|
||||
"The root prefix to configure (for init and hook), and the prefix "
|
||||
"to activate for activate, either by name or by path");
|
||||
|
||||
|
@ -172,7 +192,8 @@ void init_shell_parser(CLI::App* subcom)
|
|||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Currently allowed values are: bash, zsh, cmd.exe & powershell" << std::endl;
|
||||
std::cout << "Currently allowed values are: bash, zsh, cmd.exe & powershell"
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
if (shell_options.action == "init")
|
||||
|
@ -208,24 +229,28 @@ void init_shell_parser(CLI::App* subcom)
|
|||
});
|
||||
}
|
||||
|
||||
void install_specs(const std::vector<std::string>& specs, bool create_env = false)
|
||||
void
|
||||
install_specs(const std::vector<std::string>& specs, bool create_env = false)
|
||||
{
|
||||
auto& ctx = Context::instance();
|
||||
|
||||
|
||||
set_global_options(ctx);
|
||||
|
||||
Console::print(banner);
|
||||
|
||||
if (ctx.root_prefix.empty())
|
||||
{
|
||||
std::cout << "You have not set a $MAMBA_ROOT_PREFIX.\nEither set the MAMBA_ROOT_PREFIX environment variable, or use\n micromamba shell init ... \nto initialize your shell, then restart or source the contents of the shell init script.\n";
|
||||
std::cout << "You have not set a $MAMBA_ROOT_PREFIX.\nEither set the "
|
||||
"MAMBA_ROOT_PREFIX environment variable, or use\n micromamba "
|
||||
"shell init ... \nto initialize your shell, then restart or "
|
||||
"source the contents of the shell init script.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ctx.target_prefix.empty())
|
||||
{
|
||||
std::cout << "No active target prefix.\n\nRun $ micromamba activate <PATH_TO_MY_ENV>\nto activate an environment.\n";
|
||||
std::cout << "No active target prefix.\n\nRun $ micromamba activate "
|
||||
"<PATH_TO_MY_ENV>\nto activate an environment.\n";
|
||||
exit(1);
|
||||
}
|
||||
if (!fs::exists(ctx.target_prefix) && create_env == false)
|
||||
|
@ -255,11 +280,9 @@ void install_specs(const std::vector<std::string>& specs, bool create_env = fals
|
|||
auto& channel = make_channel(url);
|
||||
std::string full_url = concat(channel.url(true), "/repodata.json");
|
||||
|
||||
auto sdir = std::make_shared<MSubdirData>(
|
||||
concat(channel.name(), "/", channel.platform()),
|
||||
full_url,
|
||||
cache_dir / cache_fn_url(full_url)
|
||||
);
|
||||
auto sdir = std::make_shared<MSubdirData>(concat(channel.name(), "/", channel.platform()),
|
||||
full_url,
|
||||
cache_dir / cache_fn_url(full_url));
|
||||
|
||||
sdir->load();
|
||||
multi_dl.add(sdir->target());
|
||||
|
@ -282,11 +305,11 @@ void install_specs(const std::vector<std::string>& specs, bool create_env = fals
|
|||
repos.push_back(repo);
|
||||
}
|
||||
|
||||
MSolver solver(pool, {{SOLVER_FLAG_ALLOW_DOWNGRADE, 1}});
|
||||
MSolver solver(pool, { { SOLVER_FLAG_ALLOW_DOWNGRADE, 1 } });
|
||||
solver.add_jobs(create_options.specs, SOLVER_INSTALL);
|
||||
solver.solve();
|
||||
|
||||
mamba::MultiPackageCache package_caches({ctx.root_prefix / "pkgs"});
|
||||
mamba::MultiPackageCache package_caches({ ctx.root_prefix / "pkgs" });
|
||||
mamba::MTransaction trans(solver, package_caches);
|
||||
|
||||
if (ctx.json)
|
||||
|
@ -295,11 +318,15 @@ void install_specs(const std::vector<std::string>& specs, bool create_env = fals
|
|||
}
|
||||
// TODO this is not so great
|
||||
std::vector<MRepo*> repo_ptrs;
|
||||
for (auto& r : repos) { repo_ptrs.push_back(&r); }
|
||||
for (auto& r : repos)
|
||||
{
|
||||
repo_ptrs.push_back(&r);
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
bool yes = trans.prompt(ctx.root_prefix / "pkgs", repo_ptrs);
|
||||
if (!yes) exit(0);
|
||||
if (!yes)
|
||||
exit(0);
|
||||
|
||||
if (create_env && !Context::instance().dry_run)
|
||||
{
|
||||
|
@ -311,7 +338,8 @@ void install_specs(const std::vector<std::string>& specs, bool create_env = fals
|
|||
trans.execute(prefix_data, ctx.root_prefix / "pkgs");
|
||||
}
|
||||
|
||||
void init_install_parser(CLI::App* subcom)
|
||||
void
|
||||
init_install_parser(CLI::App* subcom)
|
||||
{
|
||||
subcom->add_option("specs", create_options.specs, "Specs to install into the new environment");
|
||||
init_network_parser(subcom);
|
||||
|
@ -325,7 +353,8 @@ void init_install_parser(CLI::App* subcom)
|
|||
});
|
||||
}
|
||||
|
||||
void init_create_parser(CLI::App* subcom)
|
||||
void
|
||||
init_create_parser(CLI::App* subcom)
|
||||
{
|
||||
subcom->add_option("specs", create_options.specs, "Specs to install into the new environment");
|
||||
subcom->add_option("-p,--prefix", create_options.prefix, "Path to the Prefix");
|
||||
|
@ -352,14 +381,16 @@ void init_create_parser(CLI::App* subcom)
|
|||
});
|
||||
}
|
||||
|
||||
std::string version()
|
||||
std::string
|
||||
version()
|
||||
{
|
||||
return mamba_version;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
CLI::App app{std::string(banner) + "\nVersion: " + version() + "\n"};
|
||||
CLI::App app{ std::string(banner) + "\nVersion: " + version() + "\n" };
|
||||
|
||||
auto print_version = [](int count) {
|
||||
std::cout << version() << std::endl;
|
||||
|
@ -373,7 +404,8 @@ int main(int argc, char** argv)
|
|||
CLI::App* create_subcom = app.add_subcommand("create", "Create new environment");
|
||||
init_create_parser(create_subcom);
|
||||
|
||||
CLI::App* install_subcom = app.add_subcommand("install", "Install packages in active environment");
|
||||
CLI::App* install_subcom
|
||||
= app.add_subcommand("install", "Install packages in active environment");
|
||||
init_install_parser(install_subcom);
|
||||
|
||||
// just for the help text
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "match_spec.hpp"
|
||||
|
||||
#include "output.hpp"
|
||||
#include "url.hpp"
|
||||
#include "util.hpp"
|
||||
|
@ -33,24 +34,22 @@ namespace mamba
|
|||
{
|
||||
std::size_t pm1 = pos - 1;
|
||||
char d = s[pm1];
|
||||
if (d == '=' || d == '!' || d == '|' ||
|
||||
d == ',' || d == '<' || d == '>' || d == '~')
|
||||
if (d == '=' || d == '!' || d == '|' || d == ',' || d == '<' || d == '>'
|
||||
|| d == '~')
|
||||
{
|
||||
std::string tmp = s;
|
||||
replace_all(tmp, " ", "");
|
||||
return { tmp , "" };
|
||||
return { tmp, "" };
|
||||
}
|
||||
}
|
||||
// c is either ' ' or pm1 is none of the forbidden chars
|
||||
|
||||
std::string v = s.substr(0, pos),
|
||||
b = s.substr(pos + 1);
|
||||
std::string v = s.substr(0, pos), b = s.substr(pos + 1);
|
||||
replace_all(v, " ", "");
|
||||
replace_all(b, " ", "");
|
||||
return { v, b };
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void MatchSpec::parse()
|
||||
{
|
||||
|
@ -74,8 +73,7 @@ namespace mamba
|
|||
LOG_INFO << "Got a package file: " << spec_str << std::endl;
|
||||
}
|
||||
|
||||
auto extract_kv = [&spec_str](const std::string& kv_string, auto& map)
|
||||
{
|
||||
auto extract_kv = [&spec_str](const std::string& kv_string, auto& map) {
|
||||
static std::regex kv_re("([a-zA-Z0-9_-]+?)=([\"\']?)([^\'\"]*?)(\\2)(?:[\'\", ]|$)");
|
||||
std::cmatch kv_match;
|
||||
const char* text_iter = kv_string.c_str();
|
||||
|
@ -153,7 +151,8 @@ namespace mamba
|
|||
// if 'subdir' in brackets:
|
||||
// subdir = brackets.pop('subdir')
|
||||
|
||||
// support faulty conda matchspecs such as `libblas=[build=*mkl]`, which is the repr of `libblas=*=*mkl`
|
||||
// support faulty conda matchspecs such as `libblas=[build=*mkl]`, which is
|
||||
// the repr of `libblas=*=*mkl`
|
||||
if (spec_str.back() == '=')
|
||||
{
|
||||
spec_str.push_back('*');
|
||||
|
@ -181,7 +180,8 @@ namespace mamba
|
|||
{
|
||||
if (version.find("[") != version.npos)
|
||||
{
|
||||
throw std::runtime_error("Invalid match spec: multiple bracket sections not allowed " + spec);
|
||||
throw std::runtime_error(
|
||||
"Invalid match spec: multiple bracket sections not allowed " + spec);
|
||||
}
|
||||
|
||||
version = std::string(strip(version));
|
||||
|
@ -309,10 +309,8 @@ namespace mamba
|
|||
std::vector<std::string> brackets;
|
||||
bool version_exact = false;
|
||||
|
||||
auto is_complex_relation = [](const std::string& s)
|
||||
{
|
||||
return s.find_first_of("><$^|,") != s.npos;
|
||||
};
|
||||
auto is_complex_relation
|
||||
= [](const std::string& s) { return s.find_first_of("><$^|,") != s.npos; };
|
||||
|
||||
if (!version.empty())
|
||||
{
|
||||
|
@ -398,4 +396,4 @@ namespace mamba
|
|||
}
|
||||
return res.str();
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
160
src/output.cpp
160
src/output.cpp
|
@ -13,18 +13,21 @@
|
|||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "thirdparty/termcolor.hpp"
|
||||
|
||||
#include "output.hpp"
|
||||
#include "util.hpp"
|
||||
#include "url.hpp"
|
||||
#include "thirdparty/termcolor.hpp"
|
||||
#include "thread_utils.hpp"
|
||||
#include "url.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
std::ostream& write_duration(std::ostream &os, std::chrono::nanoseconds ns)
|
||||
std::ostream& write_duration(std::ostream& os, std::chrono::nanoseconds ns)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
using std::chrono::duration;
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::hours;
|
||||
using std::chrono::minutes;
|
||||
using std::chrono::seconds;
|
||||
|
||||
using days = duration<int, std::ratio<86400>>;
|
||||
char fill = os.fill();
|
||||
|
@ -51,16 +54,16 @@ namespace mamba
|
|||
|
||||
int get_console_width()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
#ifndef _WIN32
|
||||
struct winsize w;
|
||||
ioctl(0, TIOCGWINSZ, &w);
|
||||
return w.ws_col;
|
||||
#else
|
||||
#else
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO coninfo;
|
||||
auto res = GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
|
||||
return coninfo.dwSize.X;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -82,7 +85,7 @@ namespace mamba
|
|||
|
||||
std::ostream& ProgressScaleWriter::write(std::ostream& os, std::size_t progress) const
|
||||
{
|
||||
int pos = int(progress * m_bar_width / 100.0);
|
||||
int pos = static_cast<int>(progress * m_bar_width / 100.0);
|
||||
for (int i = 0; i < m_bar_width; ++i)
|
||||
{
|
||||
if (i < pos)
|
||||
|
@ -106,7 +109,8 @@ namespace mamba
|
|||
***************/
|
||||
|
||||
ProgressBar::ProgressBar(const std::string& prefix)
|
||||
: m_prefix(prefix), m_start_time_saved(false)
|
||||
: m_prefix(prefix)
|
||||
, m_start_time_saved(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -171,16 +175,18 @@ namespace mamba
|
|||
pf << m_postfix;
|
||||
auto fpf = pf.str();
|
||||
int width = get_console_width();
|
||||
width = (width == -1) ? 20 : (std::min)(int(width - (m_prefix.size() + 4) - fpf.size()), 20);
|
||||
width = (width == -1)
|
||||
? 20
|
||||
: (std::min)(static_cast<int>(width - (m_prefix.size() + 4) - fpf.size()), 20);
|
||||
|
||||
if (!m_activate_bob)
|
||||
{
|
||||
ProgressScaleWriter w{width, "=", ">", " "};
|
||||
ProgressScaleWriter w{ width, "=", ">", " " };
|
||||
w.write(std::cout, m_progress);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pos = int(m_progress * width / 100.0);
|
||||
auto pos = static_cast<int>(m_progress * width / 100.0);
|
||||
for (int i = 0; i < width; ++i)
|
||||
{
|
||||
if (i == pos - 1)
|
||||
|
@ -274,7 +280,7 @@ namespace mamba
|
|||
namespace printers
|
||||
{
|
||||
constexpr const char* green = "\033[32m";
|
||||
constexpr const char* red = "\033[31m";
|
||||
constexpr const char* red = "\033[31m";
|
||||
constexpr const char* reset = "\033[00m";
|
||||
|
||||
Table::Table(const std::vector<FormattedString>& header)
|
||||
|
@ -297,7 +303,8 @@ namespace mamba
|
|||
m_table.push_back(r);
|
||||
}
|
||||
|
||||
void Table::add_rows(const std::string& header, const std::vector<std::vector<FormattedString>>& rs)
|
||||
void Table::add_rows(const std::string& header,
|
||||
const std::vector<std::vector<FormattedString>>& rs)
|
||||
{
|
||||
m_table.push_back({ header });
|
||||
|
||||
|
@ -307,10 +314,12 @@ namespace mamba
|
|||
|
||||
std::ostream& Table::print(std::ostream& out)
|
||||
{
|
||||
if (m_table.size() == 0) return out;
|
||||
if (m_table.size() == 0)
|
||||
return out;
|
||||
std::size_t n_col = m_header.size();
|
||||
|
||||
if (m_align.size() == 0) m_align = std::vector<alignment>(n_col, alignment::left);
|
||||
if (m_align.size() == 0)
|
||||
m_align = std::vector<alignment>(n_col, alignment::left);
|
||||
|
||||
std::vector<std::size_t> cell_sizes(n_col);
|
||||
for (size_t i = 0; i < n_col; ++i)
|
||||
|
@ -318,14 +327,16 @@ namespace mamba
|
|||
|
||||
for (size_t i = 0; i < m_table.size(); ++i)
|
||||
{
|
||||
if (m_table[i].size() == 1) continue;
|
||||
if (m_table[i].size() == 1)
|
||||
continue;
|
||||
for (size_t j = 0; j < m_table[i].size(); ++j)
|
||||
cell_sizes[j] = std::max(cell_sizes[j], m_table[i][j].size());
|
||||
}
|
||||
|
||||
if (m_padding.size())
|
||||
{
|
||||
for (std::size_t i = 0; i < n_col; ++i) cell_sizes[i];
|
||||
for (std::size_t i = 0; i < n_col; ++i)
|
||||
cell_sizes[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -335,16 +346,20 @@ namespace mamba
|
|||
std::size_t total_length = std::accumulate(cell_sizes.begin(), cell_sizes.end(), 0);
|
||||
total_length = std::accumulate(m_padding.begin(), m_padding.end(), total_length);
|
||||
|
||||
auto print_row = [this, &cell_sizes, &out](const std::vector<FormattedString>& row)
|
||||
{
|
||||
auto print_row = [this, &cell_sizes, &out](const std::vector<FormattedString>& row) {
|
||||
for (size_t j = 0; j < row.size(); ++j)
|
||||
{
|
||||
if (row[j].flag != format::none)
|
||||
{
|
||||
if (static_cast<std::size_t>(row[j].flag) & static_cast<std::size_t>(format::red)) out << termcolor::red;
|
||||
if (static_cast<std::size_t>(row[j].flag) & static_cast<std::size_t>(format::green)) out << termcolor::green;
|
||||
if (static_cast<std::size_t>(row[j].flag) & static_cast<std::size_t>(format::yellow)) out << termcolor::yellow;
|
||||
|
||||
if (static_cast<std::size_t>(row[j].flag)
|
||||
& static_cast<std::size_t>(format::red))
|
||||
out << termcolor::red;
|
||||
if (static_cast<std::size_t>(row[j].flag)
|
||||
& static_cast<std::size_t>(format::green))
|
||||
out << termcolor::green;
|
||||
if (static_cast<std::size_t>(row[j].flag)
|
||||
& static_cast<std::size_t>(format::yellow))
|
||||
out << termcolor::yellow;
|
||||
}
|
||||
if (this->m_align[j] == alignment::left)
|
||||
{
|
||||
|
@ -366,11 +381,11 @@ namespace mamba
|
|||
|
||||
print_row(m_header);
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MAMBA_TABLE_DELIM "-"
|
||||
#else
|
||||
#define MAMBA_TABLE_DELIM "─"
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#define MAMBA_TABLE_DELIM "-"
|
||||
#else
|
||||
#define MAMBA_TABLE_DELIM "─"
|
||||
#endif
|
||||
|
||||
out << "\n";
|
||||
for (size_t i = 0; i < total_length + m_padding[0]; ++i)
|
||||
|
@ -384,11 +399,12 @@ namespace mamba
|
|||
if (m_table[i].size() == 1)
|
||||
{
|
||||
// print header
|
||||
if (i != 0) std::cout << "\n";
|
||||
if (i != 0)
|
||||
std::cout << "\n";
|
||||
|
||||
for (int x = 0; x < m_padding[0]; ++x)
|
||||
{
|
||||
out << ' ';
|
||||
out << ' ';
|
||||
}
|
||||
out << m_table[i][0].s;
|
||||
|
||||
|
@ -407,7 +423,7 @@ namespace mamba
|
|||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
} // namespace printers
|
||||
|
||||
/*****************
|
||||
* ConsoleStream *
|
||||
|
@ -447,13 +463,13 @@ namespace mamba
|
|||
if (!(Context::instance().quiet || Context::instance().json) || force_print)
|
||||
{
|
||||
// print above the progress bars
|
||||
if (Console::instance().m_progress_started && Console::instance().m_active_progress_bars.size())
|
||||
if (Console::instance().m_progress_started
|
||||
&& Console::instance().m_active_progress_bars.size())
|
||||
{
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(instance().m_mutex);
|
||||
const auto& ps = instance().m_active_progress_bars.size();
|
||||
std::cout << cursor::up(ps) << cursor::erase_line()
|
||||
<< str << std::endl;
|
||||
std::cout << cursor::up(ps) << cursor::erase_line() << str << std::endl;
|
||||
|
||||
if (!Console::instance().skip_progress_bars())
|
||||
{
|
||||
|
@ -532,15 +548,20 @@ namespace mamba
|
|||
{
|
||||
std::lock_guard<std::mutex> lock(instance().m_mutex);
|
||||
|
||||
if (Context::instance().no_progress_bars && !(Context::instance().quiet || Context::instance().json))
|
||||
if (Context::instance().no_progress_bars
|
||||
&& !(Context::instance().quiet || Context::instance().json))
|
||||
{
|
||||
std::cout << m_progress_bars[idx]->prefix() << " " << msg << "\n";
|
||||
}
|
||||
|
||||
auto it = std::find(m_active_progress_bars.begin(), m_active_progress_bars.end(), m_progress_bars[idx].get());
|
||||
if (it == m_active_progress_bars.end() || Context::instance().quiet || Context::instance().json)
|
||||
auto it = std::find(m_active_progress_bars.begin(),
|
||||
m_active_progress_bars.end(),
|
||||
m_progress_bars[idx].get());
|
||||
if (it == m_active_progress_bars.end() || Context::instance().quiet
|
||||
|| Context::instance().json)
|
||||
{
|
||||
// if no_progress_bars is true, should return here as no progress bars are active
|
||||
// if no_progress_bars is true, should return here as no progress bars are
|
||||
// active
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -574,7 +595,9 @@ namespace mamba
|
|||
std::cout << cursor::up(cursor_up);
|
||||
}
|
||||
|
||||
auto it = std::find(m_active_progress_bars.begin(), m_active_progress_bars.end(), m_progress_bars[idx].get());
|
||||
auto it = std::find(m_active_progress_bars.begin(),
|
||||
m_active_progress_bars.end(),
|
||||
m_progress_bars[idx].get());
|
||||
if (it == m_active_progress_bars.end())
|
||||
{
|
||||
m_active_progress_bars.push_back(m_progress_bars[idx].get());
|
||||
|
@ -609,7 +632,8 @@ namespace mamba
|
|||
|
||||
bool Console::skip_progress_bars() const
|
||||
{
|
||||
return Context::instance().quiet || Context::instance().json || Context::instance().no_progress_bars;
|
||||
return Context::instance().quiet || Context::instance().json
|
||||
|| Context::instance().no_progress_bars;
|
||||
}
|
||||
|
||||
/*****************
|
||||
|
@ -624,9 +648,7 @@ namespace mamba
|
|||
char sep = '/';
|
||||
#endif
|
||||
size_t pos = file.rfind(sep);
|
||||
return pos != std::string::npos ?
|
||||
file.substr(pos + 1, std::string::npos) :
|
||||
file;
|
||||
return pos != std::string::npos ? file.substr(pos + 1, std::string::npos) : file;
|
||||
}
|
||||
|
||||
MessageLogger::MessageLogger(const char* file, int line, LogSeverity severity)
|
||||
|
@ -645,26 +667,29 @@ namespace mamba
|
|||
return;
|
||||
}
|
||||
|
||||
switch(m_severity)
|
||||
switch (m_severity)
|
||||
{
|
||||
case LogSeverity::fatal:
|
||||
Console::stream() << "\033[1;35m" << "FATAL " << m_stream.str() << "\033[0m";
|
||||
break;
|
||||
case LogSeverity::error:
|
||||
Console::stream() << "\033[1;31m" << "ERROR " << m_stream.str() << "\033[0m";
|
||||
break;
|
||||
case LogSeverity::warning:
|
||||
Console::stream() << "\033[1;33m" << "WARNING " << m_stream.str() << "\033[0m";
|
||||
break;
|
||||
case LogSeverity::info:
|
||||
Console::stream() << "INFO " << m_stream.str();
|
||||
break;
|
||||
case LogSeverity::debug:
|
||||
Console::stream() << "DEBUG " << m_stream.str();
|
||||
break;
|
||||
default:
|
||||
Console::stream() << "UNKOWN " << m_stream.str();
|
||||
break;
|
||||
case LogSeverity::fatal:
|
||||
Console::stream() << "\033[1;35m"
|
||||
<< "FATAL " << m_stream.str() << "\033[0m";
|
||||
break;
|
||||
case LogSeverity::error:
|
||||
Console::stream() << "\033[1;31m"
|
||||
<< "ERROR " << m_stream.str() << "\033[0m";
|
||||
break;
|
||||
case LogSeverity::warning:
|
||||
Console::stream() << "\033[1;33m"
|
||||
<< "WARNING " << m_stream.str() << "\033[0m";
|
||||
break;
|
||||
case LogSeverity::info:
|
||||
Console::stream() << "INFO " << m_stream.str();
|
||||
break;
|
||||
case LogSeverity::debug:
|
||||
Console::stream() << "DEBUG " << m_stream.str();
|
||||
break;
|
||||
default:
|
||||
Console::stream() << "UNKOWN " << m_stream.str();
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_severity == LogSeverity::fatal)
|
||||
|
@ -698,7 +723,8 @@ namespace mamba
|
|||
return j;
|
||||
}
|
||||
|
||||
// write all the key/value pairs of a JSON object into the current entry, which is then a JSON object
|
||||
// write all the key/value pairs of a JSON object into the current entry, which
|
||||
// is then a JSON object
|
||||
void JsonLogger::json_write(const nlohmann::json& j)
|
||||
{
|
||||
if (Context::instance().json)
|
||||
|
@ -747,4 +773,4 @@ namespace mamba
|
|||
if (Context::instance().json)
|
||||
json_hier.erase(json_hier.rfind('/'));
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include "validate.hpp"
|
||||
#include "package_cache.hpp"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "package_handling.hpp"
|
||||
#include "validate.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -23,12 +23,14 @@ namespace mamba
|
|||
{
|
||||
LOG_INFO << "Attempt to create package cache directory " << m_pkgs_dir;
|
||||
bool sudo_safe = path::starts_with_home(m_pkgs_dir);
|
||||
path::touch(m_pkgs_dir / PACKAGE_CACHE_MAGIC_FILE, sudo_safe, /*mkdir*/true);
|
||||
path::touch(m_pkgs_dir / PACKAGE_CACHE_MAGIC_FILE,
|
||||
sudo_safe,
|
||||
/*mkdir*/ true);
|
||||
// TODO why magic string "urls" here? is it necessary?
|
||||
path::touch(m_pkgs_dir / "urls", sudo_safe);
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
catch (...)
|
||||
{
|
||||
// TODO better error handling
|
||||
LOG_ERROR << "cannot create package cache directory " << m_pkgs_dir;
|
||||
|
@ -55,8 +57,7 @@ namespace mamba
|
|||
return m_pkgs_dir;
|
||||
}
|
||||
|
||||
PackageCacheData
|
||||
PackageCacheData::first_writable(const std::vector<fs::path>* pkgs_dirs)
|
||||
PackageCacheData PackageCacheData::first_writable(const std::vector<fs::path>* pkgs_dirs)
|
||||
{
|
||||
const std::vector<fs::path>* dirs = pkgs_dirs ? pkgs_dirs : &Context::instance().pkgs_dirs;
|
||||
for (const auto& dir : (*dirs))
|
||||
|
@ -115,7 +116,7 @@ namespace mamba
|
|||
return m_valid_cache[pkg];
|
||||
}
|
||||
|
||||
assert (!s.fn.empty());
|
||||
assert(!s.fn.empty());
|
||||
// TODO move entire cache checking logic here (including md5 sum check)
|
||||
bool valid = false;
|
||||
if (fs::exists(m_pkgs_dir / s.fn))
|
||||
|
@ -129,7 +130,8 @@ namespace mamba
|
|||
}
|
||||
else if (fs::exists(m_pkgs_dir / strip_package_extension(s.fn)))
|
||||
{
|
||||
auto repodata_record_path = m_pkgs_dir / strip_package_extension(s.fn) / "info" / "repodata_record.json";
|
||||
auto repodata_record_path
|
||||
= m_pkgs_dir / strip_package_extension(s.fn) / "info" / "repodata_record.json";
|
||||
if (fs::exists(repodata_record_path))
|
||||
{
|
||||
try
|
||||
|
@ -143,7 +145,9 @@ namespace mamba
|
|||
valid = valid && repodata_record["url"].get<std::string>() == s.url;
|
||||
if (!valid)
|
||||
{
|
||||
LOG_WARNING << "Found directory with same name, but different size, channel, url or checksum " << repodata_record_path;
|
||||
LOG_WARNING << "Found directory with same name, but different size, "
|
||||
"channel, url or checksum "
|
||||
<< repodata_record_path;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
|
@ -193,8 +197,9 @@ namespace mamba
|
|||
{
|
||||
for (auto& c : m_caches)
|
||||
{
|
||||
if (c.query(s)) return true;
|
||||
if (c.query(s))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -4,24 +4,23 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <sstream>
|
||||
#include "package_handling.hpp"
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
#include "util.hpp"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include <sstream>
|
||||
|
||||
#include "package_handling.hpp"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "output.hpp"
|
||||
#include "thread_utils.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
class extraction_guard
|
||||
{
|
||||
public:
|
||||
|
||||
explicit extraction_guard(const fs::path& file)
|
||||
: m_file(file)
|
||||
{
|
||||
|
@ -42,14 +41,13 @@ namespace mamba
|
|||
extraction_guard& operator=(extraction_guard&&) = delete;
|
||||
|
||||
private:
|
||||
|
||||
const fs::path& m_file;
|
||||
};
|
||||
|
||||
static int copy_data(archive *ar, archive *aw)
|
||||
static int copy_data(archive* ar, archive* aw)
|
||||
{
|
||||
int r;
|
||||
const void *buff;
|
||||
const void* buff;
|
||||
size_t size;
|
||||
la_int64_t offset;
|
||||
|
||||
|
@ -86,9 +84,9 @@ namespace mamba
|
|||
}
|
||||
fs::current_path(destination);
|
||||
|
||||
struct archive *a;
|
||||
struct archive *ext;
|
||||
struct archive_entry *entry;
|
||||
struct archive* a;
|
||||
struct archive* ext;
|
||||
struct archive_entry* entry;
|
||||
int flags;
|
||||
int r;
|
||||
|
||||
|
@ -164,7 +162,9 @@ namespace mamba
|
|||
fs::current_path(prev_path);
|
||||
}
|
||||
|
||||
void extract_conda(const fs::path& file, const fs::path& dest_dir, const std::vector<std::string>& parts)
|
||||
void extract_conda(const fs::path& file,
|
||||
const fs::path& dest_dir,
|
||||
const std::vector<std::string>& parts)
|
||||
{
|
||||
TemporaryDirectory tdir;
|
||||
extract_archive(file, tdir);
|
||||
|
@ -252,4 +252,4 @@ namespace mamba
|
|||
throw std::runtime_error("Unknown file format (" + std::string(file) + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -4,20 +4,20 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "package_info.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
#include "package_info.hpp"
|
||||
#include "util.hpp"
|
||||
#include "output.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template <class T>
|
||||
std::string get_package_info_field(const PackageInfo&,
|
||||
T PackageInfo::*field);
|
||||
std::string get_package_info_field(const PackageInfo&, T PackageInfo::*field);
|
||||
|
||||
template <>
|
||||
std::string get_package_info_field<std::string>(const PackageInfo& pkg,
|
||||
|
@ -36,8 +36,7 @@ namespace mamba
|
|||
template <class T>
|
||||
PackageInfo::field_getter build_field_getter(T PackageInfo::*field)
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
return std::bind(get_package_info_field<T>, _1, field);
|
||||
return std::bind(get_package_info_field<T>, std::placeholders::_1, field);
|
||||
}
|
||||
|
||||
using field_getter_map = std::map<std::string, PackageInfo::field_getter>;
|
||||
|
@ -64,7 +63,7 @@ namespace mamba
|
|||
static field_getter_map m = build_field_getter_map();
|
||||
return m;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
PackageInfo::field_getter PackageInfo::get_field_getter(const std::string& name)
|
||||
{
|
||||
|
@ -79,15 +78,17 @@ namespace mamba
|
|||
PackageInfo::compare_fun PackageInfo::less(const std::string& member)
|
||||
{
|
||||
auto getter = get_field_getter(member);
|
||||
return [getter](const PackageInfo& lhs, const PackageInfo& rhs)
|
||||
{ return getter(lhs) < getter(rhs); };
|
||||
return [getter](const PackageInfo& lhs, const PackageInfo& rhs) {
|
||||
return getter(lhs) < getter(rhs);
|
||||
};
|
||||
}
|
||||
|
||||
PackageInfo::compare_fun PackageInfo::equal(const std::string& member)
|
||||
{
|
||||
auto getter = get_field_getter(member);
|
||||
return [getter](const PackageInfo& lhs, const PackageInfo& rhs)
|
||||
{ return getter(lhs) == getter(rhs); };
|
||||
return [getter](const PackageInfo& lhs, const PackageInfo& rhs) {
|
||||
return getter(lhs) == getter(rhs);
|
||||
};
|
||||
}
|
||||
|
||||
PackageInfo::PackageInfo(Solvable* s)
|
||||
|
@ -118,7 +119,8 @@ namespace mamba
|
|||
}
|
||||
else
|
||||
{
|
||||
channel = s->repo->name; // note this can and should be <unknown> when e.g. installing from a tarball
|
||||
channel = s->repo->name; // note this can and should be <unknown> when e.g.
|
||||
// installing from a tarball
|
||||
}
|
||||
|
||||
url = channel + "/" + check_char(solvable_lookup_str(s, SOLVABLE_MEDIAFILE));
|
||||
|
@ -155,7 +157,7 @@ namespace mamba
|
|||
|
||||
PackageInfo::PackageInfo(nlohmann::json&& j)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
using namespace std::string_literals; // NOLINT(build/namespaces)
|
||||
assign_or(j, "name", name, ""s);
|
||||
assign_or(j, "version", version, ""s);
|
||||
assign_or(j, "channel", channel, ""s);
|
||||
|
@ -182,9 +184,14 @@ namespace mamba
|
|||
{
|
||||
}
|
||||
|
||||
PackageInfo::PackageInfo(const std::string& n, const std::string& v,
|
||||
const std::string b, std::size_t bn)
|
||||
: name(n), version(v), build_string(b), build_number(bn)
|
||||
PackageInfo::PackageInfo(const std::string& n,
|
||||
const std::string& v,
|
||||
const std::string b,
|
||||
std::size_t bn)
|
||||
: name(n)
|
||||
, version(v)
|
||||
, build_string(b)
|
||||
, build_number(bn)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -222,4 +229,4 @@ namespace mamba
|
|||
// TODO channel contains subdir right now?!
|
||||
return concat(channel, "::", name, "-", version, "-", build_string);
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -6,17 +6,18 @@
|
|||
|
||||
#include "package_paths.hpp"
|
||||
|
||||
#include "util.hpp"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
std::map<std::string, PrefixFileParse> read_has_prefix(const fs::path& path)
|
||||
{
|
||||
// reads `has_prefix` file and return dict mapping filepaths to tuples(placeholder, FileMode)
|
||||
// A line in `has_prefix` contains one of
|
||||
// reads `has_prefix` file and return dict mapping filepaths to
|
||||
// tuples(placeholder, FileMode) A line in `has_prefix` contains one of
|
||||
// * filepath
|
||||
// * placeholder mode filepath
|
||||
// mode values are one of
|
||||
|
@ -31,17 +32,18 @@ namespace mamba
|
|||
}
|
||||
for (auto& l : read_lines(path))
|
||||
{
|
||||
|
||||
// TODO: make sure that strings that are quoted are still split correctly
|
||||
// e.g. when a file path contains a space...
|
||||
auto s = split(l, " ");
|
||||
if (s.size() == 1)
|
||||
{
|
||||
res[s[0]] = PrefixFileParse{concat(PREFIX_PLACEHOLDER_1, PREFIX_PLACEHOLDER_2), "text", s[0]};
|
||||
res[s[0]] = PrefixFileParse{ concat(PREFIX_PLACEHOLDER_1, PREFIX_PLACEHOLDER_2),
|
||||
"text",
|
||||
s[0] };
|
||||
}
|
||||
else if (s.size() == 3)
|
||||
{
|
||||
res[s[2]] = PrefixFileParse{s[0], s[1], s[2]};
|
||||
res[s[2]] = PrefixFileParse{ s[0], s[1], s[2] };
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -75,8 +77,7 @@ namespace mamba
|
|||
auto info_dir = directory / "info";
|
||||
auto paths_json_path = info_dir / "paths.json";
|
||||
|
||||
auto parse_file_mode = [](nlohmann::json& j) -> FileMode
|
||||
{
|
||||
auto parse_file_mode = [](nlohmann::json& j) -> FileMode {
|
||||
if (j.find("file_mode") != j.end())
|
||||
{
|
||||
// check if "text" or "binary"
|
||||
|
@ -92,8 +93,7 @@ namespace mamba
|
|||
return FileMode::UNDEFINED;
|
||||
};
|
||||
|
||||
auto parse_path_type = [](nlohmann::json& j) -> PathType
|
||||
{
|
||||
auto parse_path_type = [](nlohmann::json& j) -> PathType {
|
||||
if (j.find("path_type") != j.end())
|
||||
{
|
||||
// TODO find a DIRECTORY path type
|
||||
|
@ -164,7 +164,8 @@ namespace mamba
|
|||
if (has_prefix_files.find(f) != has_prefix_files.end())
|
||||
{
|
||||
p.prefix_placeholder = has_prefix_files[f].placeholder;
|
||||
p.file_mode = has_prefix_files[f].file_mode[0] == 't' ? FileMode::TEXT : FileMode::BINARY;
|
||||
p.file_mode = has_prefix_files[f].file_mode[0] == 't' ? FileMode::TEXT
|
||||
: FileMode::BINARY;
|
||||
}
|
||||
if (no_link.find(f) != no_link.end())
|
||||
{
|
||||
|
@ -183,4 +184,4 @@ namespace mamba
|
|||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "pool.hpp"
|
||||
|
||||
#include "output.hpp"
|
||||
|
||||
namespace mamba
|
||||
|
@ -39,4 +40,4 @@ namespace mamba
|
|||
{
|
||||
return m_pool;
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "prefix_data.hpp"
|
||||
|
||||
#include "output.hpp"
|
||||
|
||||
namespace mamba
|
||||
|
@ -20,7 +21,7 @@ namespace mamba
|
|||
auto conda_meta_dir = m_prefix_path / "conda-meta";
|
||||
if (lexists(conda_meta_dir))
|
||||
{
|
||||
for(auto& p: fs::directory_iterator(conda_meta_dir))
|
||||
for (auto& p : fs::directory_iterator(conda_meta_dir))
|
||||
{
|
||||
if (ends_with(p.path().c_str(), ".json"))
|
||||
{
|
||||
|
@ -52,6 +53,6 @@ namespace mamba
|
|||
nlohmann::json j;
|
||||
infile >> j;
|
||||
auto prec = PackageInfo(std::move(j));
|
||||
m_package_records.insert({prec.name, std::move(prec)});
|
||||
m_package_records.insert({ prec.name, std::move(prec) });
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -7,29 +7,29 @@
|
|||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
#include "util.hpp"
|
||||
#include "solver.hpp"
|
||||
#include "channel.hpp"
|
||||
#include "context.hpp"
|
||||
#include "pool.hpp"
|
||||
#include "transaction.hpp"
|
||||
#include "repo.hpp"
|
||||
#include "prefix_data.hpp"
|
||||
#include "query.hpp"
|
||||
#include "repo.hpp"
|
||||
#include "solver.hpp"
|
||||
#include "subdirdata.hpp"
|
||||
#include "context.hpp"
|
||||
#include "channel.hpp"
|
||||
#include "transaction.hpp"
|
||||
#include "url.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
PYBIND11_MODULE(mamba_api, m) {
|
||||
PYBIND11_MODULE(mamba_api, m)
|
||||
{
|
||||
using namespace mamba;
|
||||
|
||||
py::class_<ghc::filesystem::path>(m, "Path")
|
||||
.def(py::init<std::string>())
|
||||
.def("__repr__", [](ghc::filesystem::path& self) -> std::string {
|
||||
return std::string("ghc::filesystem::path[") + std::string(self) + "]";
|
||||
})
|
||||
;
|
||||
});
|
||||
py::implicitly_convertible<std::string, ghc::filesystem::path>();
|
||||
|
||||
py::register_exception<mamba_error>(m, "MambaNativeException");
|
||||
|
@ -37,13 +37,11 @@ PYBIND11_MODULE(mamba_api, m) {
|
|||
py::class_<MPool>(m, "Pool")
|
||||
.def(py::init<>())
|
||||
.def("set_debuglevel", &MPool::set_debuglevel)
|
||||
.def("create_whatprovides", &MPool::create_whatprovides)
|
||||
;
|
||||
.def("create_whatprovides", &MPool::create_whatprovides);
|
||||
|
||||
py::class_<MultiPackageCache>(m, "MultiPackageCache")
|
||||
.def(py::init<std::vector<fs::path>>())
|
||||
.def("query", &MultiPackageCache::query)
|
||||
;
|
||||
.def("query", &MultiPackageCache::query);
|
||||
|
||||
py::class_<MRepo>(m, "Repo")
|
||||
.def(py::init<MPool&, const std::string&, const std::string&, const std::string&>())
|
||||
|
@ -53,8 +51,7 @@ PYBIND11_MODULE(mamba_api, m) {
|
|||
.def("name", &MRepo::name)
|
||||
.def("priority", &MRepo::priority)
|
||||
.def("size", &MRepo::size)
|
||||
.def("clear", &MRepo::clear)
|
||||
;
|
||||
.def("clear", &MRepo::clear);
|
||||
|
||||
py::class_<MTransaction>(m, "Transaction")
|
||||
.def(py::init<MSolver&, MultiPackageCache&>())
|
||||
|
@ -63,10 +60,9 @@ PYBIND11_MODULE(mamba_api, m) {
|
|||
.def("print", &MTransaction::print)
|
||||
.def("fetch_extract_packages", &MTransaction::fetch_extract_packages)
|
||||
.def("prompt", &MTransaction::prompt)
|
||||
.def("execute", [](MTransaction& self, PrefixData& target_prefix, const std::string& cache_dir) -> bool {
|
||||
return self.execute(target_prefix, cache_dir);
|
||||
})
|
||||
;
|
||||
.def("execute",
|
||||
[](MTransaction& self, PrefixData& target_prefix, const std::string& cache_dir)
|
||||
-> bool { return self.execute(target_prefix, cache_dir); });
|
||||
|
||||
py::class_<MSolver>(m, "Solver")
|
||||
.def(py::init<MPool&, std::vector<std::pair<int, int>>>())
|
||||
|
@ -78,8 +74,7 @@ PYBIND11_MODULE(mamba_api, m) {
|
|||
.def("set_postsolve_flags", &MSolver::set_postsolve_flags)
|
||||
.def("is_solved", &MSolver::is_solved)
|
||||
.def("problems_to_str", &MSolver::problems_to_str)
|
||||
.def("solve", &MSolver::solve)
|
||||
;
|
||||
.def("solve", &MSolver::solve);
|
||||
|
||||
/*py::class_<Query>(m, "Query")
|
||||
.def(py::init<MPool&>())
|
||||
|
@ -90,58 +85,53 @@ PYBIND11_MODULE(mamba_api, m) {
|
|||
|
||||
py::class_<Query>(m, "Query")
|
||||
.def(py::init<MPool&>())
|
||||
.def("find", [](const Query& q, const std::string& query)
|
||||
{
|
||||
if (Context::instance().json)
|
||||
std::cout << q.find(query).groupby("name").json().dump(4);
|
||||
else
|
||||
q.find(query).groupby("name").table(std::cout);
|
||||
})
|
||||
.def("whoneeds", [](const Query& q, const std::string& query, bool tree)
|
||||
{
|
||||
//QueryResult res = q.whoneeds(query, tree);
|
||||
query_result res = q.whoneeds(query, tree);
|
||||
if (tree)
|
||||
res.tree(std::cout);
|
||||
else if (Context::instance().json)
|
||||
std::cout << res.json().dump(4);
|
||||
else
|
||||
res.table(std::cout);
|
||||
})
|
||||
.def("depends", [](const Query& q, const std::string& query, bool tree)
|
||||
{
|
||||
query_result res = q.depends(query, tree);
|
||||
if (Context::instance().json)
|
||||
std::cout << res.json().dump(4);
|
||||
else if (tree)
|
||||
res.tree(std::cout);
|
||||
else
|
||||
res.table(std::cout);
|
||||
});
|
||||
.def("find",
|
||||
[](const Query& q, const std::string& query) {
|
||||
if (Context::instance().json)
|
||||
std::cout << q.find(query).groupby("name").json().dump(4);
|
||||
else
|
||||
q.find(query).groupby("name").table(std::cout);
|
||||
})
|
||||
.def("whoneeds",
|
||||
[](const Query& q, const std::string& query, bool tree) {
|
||||
// QueryResult res = q.whoneeds(query, tree);
|
||||
query_result res = q.whoneeds(query, tree);
|
||||
if (tree)
|
||||
res.tree(std::cout);
|
||||
else if (Context::instance().json)
|
||||
std::cout << res.json().dump(4);
|
||||
else
|
||||
res.table(std::cout);
|
||||
})
|
||||
.def("depends", [](const Query& q, const std::string& query, bool tree) {
|
||||
query_result res = q.depends(query, tree);
|
||||
if (Context::instance().json)
|
||||
std::cout << res.json().dump(4);
|
||||
else if (tree)
|
||||
res.tree(std::cout);
|
||||
else
|
||||
res.table(std::cout);
|
||||
});
|
||||
|
||||
py::class_<MSubdirData>(m, "SubdirData")
|
||||
.def(py::init<const std::string&, const std::string&, const std::string&>())
|
||||
.def("create_repo", &MSubdirData::create_repo)
|
||||
.def("load", &MSubdirData::load)
|
||||
.def("loaded", &MSubdirData::loaded)
|
||||
.def("cache_path", &MSubdirData::cache_path)
|
||||
;
|
||||
.def("cache_path", &MSubdirData::cache_path);
|
||||
|
||||
m.def("cache_fn_url", &cache_fn_url);
|
||||
m.def("create_cache_dir", &create_cache_dir);
|
||||
|
||||
py::class_<MultiDownloadTarget>(m, "DownloadTargetList")
|
||||
.def(py::init<>())
|
||||
.def("add", [](MultiDownloadTarget& self, MSubdirData& sub) -> void {
|
||||
self.add(sub.target());
|
||||
})
|
||||
.def("download", &MultiDownloadTarget::download)
|
||||
;
|
||||
.def("add",
|
||||
[](MultiDownloadTarget& self, MSubdirData& sub) -> void { self.add(sub.target()); })
|
||||
.def("download", &MultiDownloadTarget::download);
|
||||
|
||||
py::class_<Context, std::unique_ptr<Context, py::nodelete>>(m, "Context")
|
||||
.def(py::init([]() {
|
||||
return std::unique_ptr<Context, py::nodelete>(&Context::instance());
|
||||
}))
|
||||
.def(
|
||||
py::init([]() { return std::unique_ptr<Context, py::nodelete>(&Context::instance()); }))
|
||||
.def_readwrite("verbosity", &Context::verbosity)
|
||||
.def_readwrite("quiet", &Context::quiet)
|
||||
.def_readwrite("json", &Context::json)
|
||||
|
@ -164,13 +154,11 @@ PYBIND11_MODULE(mamba_api, m) {
|
|||
.def_readwrite("envs_dirs", &Context::envs_dirs)
|
||||
.def_readwrite("pkgs_dirs", &Context::pkgs_dirs)
|
||||
.def("set_verbosity", &Context::set_verbosity)
|
||||
.def_readwrite("channels", &Context::channels)
|
||||
;
|
||||
.def_readwrite("channels", &Context::channels);
|
||||
|
||||
py::class_<PrefixData>(m, "PrefixData")
|
||||
.def(py::init<const std::string&>())
|
||||
.def("load", &PrefixData::load)
|
||||
;
|
||||
.def("load", &PrefixData::load);
|
||||
|
||||
py::class_<Channel>(m, "Channel")
|
||||
.def(py::init([](const std::string& value) { return &(make_channel(value)); }))
|
||||
|
@ -181,8 +169,7 @@ PYBIND11_MODULE(mamba_api, m) {
|
|||
.def_property_readonly("subdir", &Channel::platform)
|
||||
.def_property_readonly("canonical_name", &Channel::canonical_name)
|
||||
.def("url", &Channel::url, py::arg("with_credentials") = true)
|
||||
.def("__repr__", [](const Channel& c) { return join_url(c.name(), c.platform()); })
|
||||
;
|
||||
.def("__repr__", [](const Channel& c) { return join_url(c.name(), c.platform()); });
|
||||
|
||||
m.def("get_channel_urls", &get_channel_urls);
|
||||
m.def("calculate_channel_urls", &calculate_channel_urls);
|
||||
|
|
146
src/query.cpp
146
src/query.cpp
|
@ -4,22 +4,24 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <sstream>
|
||||
#include "query.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <solv/evr.h>
|
||||
}
|
||||
|
||||
#include <iomanip>
|
||||
#include <numeric>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
|
||||
#include "query.hpp"
|
||||
#include "match_spec.hpp"
|
||||
#include "package_info.hpp"
|
||||
#include "output.hpp"
|
||||
#include "package_info.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <solv/evr.h>
|
||||
}
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
void walk_graph(query_result::dependency_graph& dep_graph,
|
||||
|
@ -42,7 +44,7 @@ namespace mamba
|
|||
Id* reqp = s->repo->idarraydata + s->requires;
|
||||
Id req = *reqp;
|
||||
|
||||
while(req != 0)
|
||||
while (req != 0)
|
||||
{
|
||||
Queue job, rec_solvables;
|
||||
queue_init(&rec_solvables);
|
||||
|
@ -81,7 +83,8 @@ namespace mamba
|
|||
auto it = not_found.find(name);
|
||||
if (it == not_found.end())
|
||||
{
|
||||
auto dep_id = dep_graph.add_node(PackageInfo(concat(name, " >>> NOT FOUND <<<")));
|
||||
auto dep_id
|
||||
= dep_graph.add_node(PackageInfo(concat(name, " >>> NOT FOUND <<<")));
|
||||
dep_graph.add_edge(parent, dep_id);
|
||||
not_found.insert(std::make_pair(name, dep_id));
|
||||
}
|
||||
|
@ -166,7 +169,8 @@ namespace mamba
|
|||
|
||||
Pool* pool = m_pool.get();
|
||||
std::sort(solvables.elements, solvables.elements + solvables.count, [pool](Id a, Id b) {
|
||||
Solvable* sa; Solvable* sb;
|
||||
Solvable* sa;
|
||||
Solvable* sb;
|
||||
sa = pool_id2solvable(pool, a);
|
||||
sb = pool_id2solvable(pool, b);
|
||||
return (pool_evrcmp(pool, sa->evr, sb->evr, EVRCMP_COMPARE) > 0);
|
||||
|
@ -209,7 +213,7 @@ namespace mamba
|
|||
{
|
||||
Solvable* latest = pool_id2solvable(m_pool.get(), solvables.elements[0]);
|
||||
auto id = g.add_node(PackageInfo(latest));
|
||||
std::map<Solvable*, size_t> visited = {{latest, id}};
|
||||
std::map<Solvable*, size_t> visited = { { latest, id } };
|
||||
reverse_walk_graph(g, id, latest, visited);
|
||||
}
|
||||
}
|
||||
|
@ -253,13 +257,15 @@ namespace mamba
|
|||
Solvable* s = pool_id2solvable(m_pool.get(), solvables.elements[i]);
|
||||
if (pool_evrcmp_str(m_pool.get(),
|
||||
pool_id2evr(m_pool.get(), s->evr),
|
||||
pool_id2evr(m_pool.get(), latest->evr), 0) > 0)
|
||||
pool_id2evr(m_pool.get(), latest->evr),
|
||||
0)
|
||||
> 0)
|
||||
{
|
||||
latest = s;
|
||||
}
|
||||
}
|
||||
auto id = g.add_node(PackageInfo(latest));
|
||||
std::map<Solvable*, size_t> visited = {{latest, id}};
|
||||
std::map<Solvable*, size_t> visited = { { latest, id } };
|
||||
std::map<std::string, size_t> not_found;
|
||||
walk_graph(g, id, latest, visited, not_found, depth);
|
||||
}
|
||||
|
@ -294,39 +300,23 @@ namespace mamba
|
|||
, m_ordered_pkg_list()
|
||||
{
|
||||
using std::swap;
|
||||
auto offset_lbd = [&rhs, this](auto iter)
|
||||
{
|
||||
return m_dep_graph.get_node_list().begin() + (iter - rhs.m_dep_graph.get_node_list().begin());
|
||||
auto offset_lbd = [&rhs, this](auto iter) {
|
||||
return m_dep_graph.get_node_list().begin()
|
||||
+ (iter - rhs.m_dep_graph.get_node_list().begin());
|
||||
};
|
||||
|
||||
package_view_list tmp(rhs.m_pkg_view_list.size());
|
||||
std::transform
|
||||
(
|
||||
rhs.m_pkg_view_list.begin(),
|
||||
rhs.m_pkg_view_list.end(),
|
||||
tmp.begin(),
|
||||
offset_lbd
|
||||
);
|
||||
std::transform(
|
||||
rhs.m_pkg_view_list.begin(), rhs.m_pkg_view_list.end(), tmp.begin(), offset_lbd);
|
||||
swap(tmp, m_pkg_view_list);
|
||||
|
||||
if (!rhs.m_ordered_pkg_list.empty())
|
||||
{
|
||||
auto tmp(rhs.m_ordered_pkg_list);
|
||||
std::for_each
|
||||
(
|
||||
tmp.begin(),
|
||||
tmp.end(),
|
||||
[offset_lbd](auto& entry)
|
||||
{
|
||||
std::transform
|
||||
(
|
||||
entry.second.begin(),
|
||||
entry.second.end(),
|
||||
entry.second.begin(),
|
||||
offset_lbd
|
||||
);
|
||||
}
|
||||
);
|
||||
std::for_each(tmp.begin(), tmp.end(), [offset_lbd](auto& entry) {
|
||||
std::transform(
|
||||
entry.second.begin(), entry.second.end(), entry.second.begin(), offset_lbd);
|
||||
});
|
||||
swap(m_ordered_pkg_list, tmp);
|
||||
}
|
||||
}
|
||||
|
@ -358,16 +348,18 @@ namespace mamba
|
|||
|
||||
if (!m_ordered_pkg_list.empty())
|
||||
{
|
||||
for (auto& entry: m_ordered_pkg_list)
|
||||
for (auto& entry : m_ordered_pkg_list)
|
||||
{
|
||||
std::sort(entry.second.begin(), entry.second.end(),
|
||||
[fun](const auto& lhs, const auto& rhs) { return fun(*lhs, *rhs); });
|
||||
std::sort(entry.second.begin(),
|
||||
entry.second.end(),
|
||||
[fun](const auto& lhs, const auto& rhs) { return fun(*lhs, *rhs); });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::sort(m_pkg_view_list.begin(), m_pkg_view_list.end(),
|
||||
[fun](const auto& lhs, const auto& rhs) { return fun(*lhs, *rhs); });
|
||||
std::sort(m_pkg_view_list.begin(),
|
||||
m_pkg_view_list.end(),
|
||||
[fun](const auto& lhs, const auto& rhs) { return fun(*lhs, *rhs); });
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
@ -378,7 +370,7 @@ namespace mamba
|
|||
auto fun = PackageInfo::get_field_getter(field);
|
||||
if (m_ordered_pkg_list.empty())
|
||||
{
|
||||
for (auto& pkg: m_pkg_view_list)
|
||||
for (auto& pkg : m_pkg_view_list)
|
||||
{
|
||||
m_ordered_pkg_list[fun(*pkg)].push_back(pkg);
|
||||
}
|
||||
|
@ -386,9 +378,9 @@ namespace mamba
|
|||
else
|
||||
{
|
||||
ordered_package_list tmp;
|
||||
for (auto& entry: m_ordered_pkg_list)
|
||||
for (auto& entry : m_ordered_pkg_list)
|
||||
{
|
||||
for (auto& pkg: entry.second)
|
||||
for (auto& pkg : entry.second)
|
||||
{
|
||||
std::string key = entry.first + '/' + fun(*pkg);
|
||||
tmp[key].push_back(pkg);
|
||||
|
@ -413,23 +405,26 @@ namespace mamba
|
|||
out << "No entries matching \"" << m_query << "\" found";
|
||||
}
|
||||
|
||||
printers::Table printer({"Name", "Version", "Build", "Channel"});
|
||||
printers::Table printer({ "Name", "Version", "Build", "Channel" });
|
||||
|
||||
if (!m_ordered_pkg_list.empty())
|
||||
{
|
||||
for (auto& entry: m_ordered_pkg_list)
|
||||
for (auto& entry : m_ordered_pkg_list)
|
||||
{
|
||||
for (auto& pkg: entry.second)
|
||||
for (auto& pkg : entry.second)
|
||||
{
|
||||
printer.add_row({pkg->name, pkg->version, pkg->build_string, cut_repo_name(pkg->channel)});
|
||||
printer.add_row({ pkg->name,
|
||||
pkg->version,
|
||||
pkg->build_string,
|
||||
cut_repo_name(pkg->channel) });
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& pkg: m_pkg_view_list)
|
||||
for (const auto& pkg : m_pkg_view_list)
|
||||
{
|
||||
printer.add_row({pkg->name, pkg->version, pkg->build_string, pkg->channel});
|
||||
printer.add_row({ pkg->name, pkg->version, pkg->build_string, pkg->channel });
|
||||
}
|
||||
}
|
||||
return printer.print(out);
|
||||
|
@ -438,7 +433,6 @@ namespace mamba
|
|||
class graph_printer
|
||||
{
|
||||
public:
|
||||
|
||||
using graph_type = query_result::dependency_graph;
|
||||
using node_id = graph_type::node_id;
|
||||
|
||||
|
@ -480,12 +474,17 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
void tree_edge(node_id, node_id, const graph_type&) {}
|
||||
void back_edge(node_id, node_id, const graph_type&) {}
|
||||
void tree_edge(node_id, node_id, const graph_type&)
|
||||
{
|
||||
}
|
||||
void back_edge(node_id, node_id, const graph_type&)
|
||||
{
|
||||
}
|
||||
void forward_or_cross_edge(node_id, node_id to, const graph_type& g)
|
||||
{
|
||||
print_prefix(to);
|
||||
m_out << concat("\033[2m", g.get_node_list()[to].name, " already visited", "\033[00m") << '\n';
|
||||
m_out << concat("\033[2m", g.get_node_list()[to].name, " already visited", "\033[00m")
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
void finish_edge(node_id from, node_id to, const graph_type& g)
|
||||
|
@ -497,7 +496,6 @@ namespace mamba
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
bool is_on_last_stack(node_id node) const
|
||||
{
|
||||
return !m_last_stack.empty() && m_last_stack.top() == node;
|
||||
|
@ -505,7 +503,7 @@ namespace mamba
|
|||
|
||||
void print_prefix(node_id node)
|
||||
{
|
||||
for (const auto& token: m_prefix_stack)
|
||||
for (const auto& token : m_prefix_stack)
|
||||
{
|
||||
m_out << token;
|
||||
}
|
||||
|
@ -528,7 +526,8 @@ namespace mamba
|
|||
|
||||
std::ostream& query_result::tree(std::ostream& out) const
|
||||
{
|
||||
bool use_graph = !m_dep_graph.get_node_list().empty() && !m_dep_graph.get_edge_list(0).empty();
|
||||
bool use_graph
|
||||
= !m_dep_graph.get_node_list().empty() && !m_dep_graph.get_edge_list(0).empty();
|
||||
if (use_graph)
|
||||
{
|
||||
graph_printer printer(out);
|
||||
|
@ -551,20 +550,13 @@ namespace mamba
|
|||
{
|
||||
nl::json j;
|
||||
std::string query_type = m_type == QueryType::Search
|
||||
? "search"
|
||||
: (m_type == QueryType::Depends
|
||||
? "depends"
|
||||
: "whoneeds");
|
||||
j["query"] = {
|
||||
{"query", MatchSpec(m_query).conda_build_form()},
|
||||
{"type", query_type}
|
||||
};
|
||||
? "search"
|
||||
: (m_type == QueryType::Depends ? "depends" : "whoneeds");
|
||||
j["query"] = { { "query", MatchSpec(m_query).conda_build_form() }, { "type", query_type } };
|
||||
|
||||
std::string msg = m_pkg_view_list.empty() ? "No entries matching \"" + m_query + "\" found" : "";
|
||||
j["result"] = {
|
||||
{"msg", msg},
|
||||
{"status", "OK"}
|
||||
};
|
||||
std::string msg
|
||||
= m_pkg_view_list.empty() ? "No entries matching \"" + m_query + "\" found" : "";
|
||||
j["result"] = { { "msg", msg }, { "status", "OK" } };
|
||||
|
||||
j["result"]["pkgs"] = nlohmann::json::array();
|
||||
for (size_t i = 0; i < m_pkg_view_list.size(); ++i)
|
||||
|
@ -576,7 +568,8 @@ namespace mamba
|
|||
{
|
||||
bool has_root = !m_dep_graph.get_edge_list(0).empty();
|
||||
j["result"]["graph_roots"] = nlohmann::json::array();
|
||||
j["result"]["graph_roots"].push_back(has_root ? m_dep_graph.get_node_list()[0].json() : nl::json(m_query));
|
||||
j["result"]["graph_roots"].push_back(has_root ? m_dep_graph.get_node_list()[0].json()
|
||||
: nl::json(m_query));
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
@ -584,14 +577,11 @@ namespace mamba
|
|||
void query_result::reset_pkg_view_list()
|
||||
{
|
||||
auto it = m_dep_graph.get_node_list().begin();
|
||||
std::generate(m_pkg_view_list.begin(),
|
||||
m_pkg_view_list.end(),
|
||||
[&it]() { return it++; });
|
||||
|
||||
std::generate(m_pkg_view_list.begin(), m_pkg_view_list.end(), [&it]() { return it++; });
|
||||
}
|
||||
|
||||
std::string query_result::get_package_repr(const PackageInfo& pkg) const
|
||||
{
|
||||
return pkg.version.empty() ? pkg.name : pkg.name + '[' + pkg.version + ']';
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
65
src/repo.cpp
65
src/repo.cpp
|
@ -5,12 +5,13 @@
|
|||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "repo.hpp"
|
||||
#include "package_info.hpp"
|
||||
|
||||
#include "output.hpp"
|
||||
#include "package_info.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "solv/repo_write.h"
|
||||
#include "solv/repo_write.h"
|
||||
}
|
||||
|
||||
#define MAMBA_TOOL_VERSION "1.1"
|
||||
|
@ -21,11 +22,10 @@ namespace mamba
|
|||
{
|
||||
const char* mamba_tool_version()
|
||||
{
|
||||
static char MTV[30];
|
||||
const size_t bufferSize = 30;
|
||||
static char MTV[bufferSize];
|
||||
MTV[0] = '\0';
|
||||
strcat(MTV, MAMBA_TOOL_VERSION);
|
||||
strcat(MTV, "_");
|
||||
strcat(MTV, solv_version);
|
||||
snprintf(MTV, bufferSize, MAMBA_TOOL_VERSION, "_", solv_version);
|
||||
return MTV;
|
||||
}
|
||||
|
||||
|
@ -54,17 +54,19 @@ namespace mamba
|
|||
{
|
||||
m_repo = repo_create(pool, "installed");
|
||||
int flags = 0;
|
||||
Repodata *data;
|
||||
Repodata* data;
|
||||
data = repo_add_repodata(m_repo, flags);
|
||||
|
||||
for (auto& [name, record] : prefix_data.records())
|
||||
{
|
||||
LOG_INFO << "Adding package record to repo " << name;
|
||||
Id handle = repo_add_solvable(m_repo);
|
||||
Solvable *s;
|
||||
Solvable* s;
|
||||
s = pool_id2solvable(pool, handle);
|
||||
repodata_set_str(data, handle, SOLVABLE_BUILDVERSION, std::to_string(record.build_number).c_str());
|
||||
repodata_add_poolstr_array(data, handle, SOLVABLE_BUILDFLAVOR, record.build_string.c_str());
|
||||
repodata_set_str(
|
||||
data, handle, SOLVABLE_BUILDVERSION, std::to_string(record.build_number).c_str());
|
||||
repodata_add_poolstr_array(
|
||||
data, handle, SOLVABLE_BUILDFLAVOR, record.build_string.c_str());
|
||||
s->name = pool_str2id(pool, record.name.c_str(), 1);
|
||||
s->evr = pool_str2id(pool, record.version.c_str(), 1);
|
||||
|
||||
|
@ -95,7 +97,8 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
s->provides = repo_addid_dep(m_repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
|
||||
s->provides = repo_addid_dep(
|
||||
m_repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
|
||||
}
|
||||
LOG_INFO << "Internalizing";
|
||||
repodata_internalize(data);
|
||||
|
@ -107,9 +110,9 @@ namespace mamba
|
|||
// not sure if reuse_ids is useful here
|
||||
// repo will be freed with pool as well though
|
||||
// maybe explicitly free pool for faster repo deletion as well
|
||||
// TODO this is actually freed with the pool, and calling it here will cause segfaults.
|
||||
// need to find a more clever way to do this.
|
||||
// repo_free(m_repo, /*reuse_ids*/1);
|
||||
// TODO this is actually freed with the pool, and calling it here will cause
|
||||
// segfaults. need to find a more clever way to do this. repo_free(m_repo,
|
||||
// /*reuse_ids*/1);
|
||||
}
|
||||
|
||||
void MRepo::set_installed()
|
||||
|
@ -178,7 +181,8 @@ namespace mamba
|
|||
int ret = repo_add_solv(m_repo, fp, 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOG_ERROR << "Could not load .solv file, falling back to JSON" << pool_errstr(m_repo->pool);
|
||||
LOG_ERROR << "Could not load .solv file, falling back to JSON"
|
||||
<< pool_errstr(m_repo->pool);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -198,23 +202,27 @@ namespace mamba
|
|||
int pip_added = repodata_lookup_num(repodata, SOLVID_META, pip_added_id, -1);
|
||||
const char* etag = repodata_lookup_str(repodata, SOLVID_META, etag_id);
|
||||
const char* mod = repodata_lookup_str(repodata, SOLVID_META, mod_id);
|
||||
const char* tool_version = repodata_lookup_str(repodata, SOLVID_META, REPOSITORY_TOOLVERSION);
|
||||
bool metadata_valid = !(!url || !etag || !mod || !tool_version || pip_added == -1);
|
||||
const char* tool_version
|
||||
= repodata_lookup_str(repodata, SOLVID_META, REPOSITORY_TOOLVERSION);
|
||||
bool metadata_valid
|
||||
= !(!url || !etag || !mod || !tool_version || pip_added == -1);
|
||||
|
||||
if (metadata_valid)
|
||||
{
|
||||
RepoMetadata read_metadata {
|
||||
url, pip_added == 1, etag, mod
|
||||
};
|
||||
metadata_valid = (read_metadata == m_metadata) && (std::strcmp(tool_version, mamba_tool_version()) == 0);
|
||||
RepoMetadata read_metadata{ url, pip_added == 1, etag, mod };
|
||||
metadata_valid = (read_metadata == m_metadata)
|
||||
&& (std::strcmp(tool_version, mamba_tool_version()) == 0);
|
||||
}
|
||||
|
||||
LOG_INFO << "Metadata from .solv is " << (metadata_valid ? "valid" : "NOT valid");
|
||||
LOG_INFO << "Metadata from .solv is "
|
||||
<< (metadata_valid ? "valid" : "NOT valid");
|
||||
|
||||
if (!metadata_valid)
|
||||
{
|
||||
LOG_INFO << "solv file was written with a previous version of libsolv or mamba " <<
|
||||
(tool_version != nullptr ? tool_version : "<NULL>") << ", updating it now!";
|
||||
LOG_INFO << "solv file was written with a previous version of "
|
||||
"libsolv or mamba "
|
||||
<< (tool_version != nullptr ? tool_version : "<NULL>")
|
||||
<< ", updating it now!";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -241,7 +249,8 @@ namespace mamba
|
|||
int ret = repo_add_conda(m_repo, fp, 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
throw std::runtime_error("Could not read JSON repodata file (" + m_json_file + ") " + std::string(pool_errstr(m_repo->pool)));
|
||||
throw std::runtime_error("Could not read JSON repodata file (" + m_json_file + ") "
|
||||
+ std::string(pool_errstr(m_repo->pool)));
|
||||
}
|
||||
|
||||
// TODO move this to a more structured approach for repodata patching?
|
||||
|
@ -311,14 +320,14 @@ namespace mamba
|
|||
}
|
||||
|
||||
fclose(solv_f);
|
||||
repodata_free(info); // delete meta info repodata again
|
||||
repodata_free(info); // delete meta info repodata again
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MRepo::clear(bool reuse_ids = 1)
|
||||
{
|
||||
repo_free(m_repo, (int)reuse_ids);
|
||||
repo_free(m_repo, static_cast<int>(reuse_ids));
|
||||
m_repo = nullptr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -5,14 +5,17 @@
|
|||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "solver.hpp"
|
||||
#include "output.hpp"
|
||||
#include "util.hpp"
|
||||
#include "package_info.hpp"
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "output.hpp"
|
||||
#include "package_info.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
MSolver::MSolver(MPool& pool, const std::vector<std::pair<int, int>>& flags, const PrefixData* prefix_data)
|
||||
MSolver::MSolver(MPool& pool,
|
||||
const std::vector<std::pair<int, int>>& flags,
|
||||
const PrefixData* prefix_data)
|
||||
: m_flags(flags)
|
||||
, m_is_solved(false)
|
||||
, m_solver(nullptr)
|
||||
|
@ -35,9 +38,10 @@ namespace mamba
|
|||
inline bool channel_match(Solvable* s, const std::string& channel)
|
||||
{
|
||||
// TODO this could should be a lot better.
|
||||
// TODO this might match too much (e.g. bioconda would also match bioconda-experimental etc)
|
||||
// Note: s->repo->name is the URL of the repo
|
||||
// TODO maybe better to check all repos, select pointers, and compare the pointer (s->repo == ptr?)
|
||||
// TODO this might match too much (e.g. bioconda would also match
|
||||
// bioconda-experimental etc) Note: s->repo->name is the URL of the repo
|
||||
// TODO maybe better to check all repos, select pointers, and compare the
|
||||
// pointer (s->repo == ptr?)
|
||||
Channel& chan = make_channel(s->repo->name);
|
||||
return chan.url(false).find(channel) != std::string::npos;
|
||||
}
|
||||
|
@ -60,7 +64,8 @@ namespace mamba
|
|||
}
|
||||
if (selected_pkgs.count == 0)
|
||||
{
|
||||
LOG_ERROR << "Selected channel specific (or force-reinstall) job, but package is not available from channel. Solve job will fail.";
|
||||
LOG_ERROR << "Selected channel specific (or force-reinstall) job, but "
|
||||
"package is not available from channel. Solve job will fail.";
|
||||
}
|
||||
Id d = pool_queuetowhatprovides(pool, &selected_pkgs);
|
||||
queue_push2(&m_jobs, job_flag | SOLVER_SOLVABLE_ONE_OF, d);
|
||||
|
@ -102,7 +107,9 @@ namespace mamba
|
|||
MatchSpec modified_spec(ms);
|
||||
if (!ms.channel.empty() || !ms.version.empty() || !ms.build.empty())
|
||||
{
|
||||
Console::stream() << ms.conda_build_form() << ": overriding channel, version and build from installed packages due to --force-reinstall.";
|
||||
Console::stream() << ms.conda_build_form()
|
||||
<< ": overriding channel, version and build from "
|
||||
"installed packages due to --force-reinstall.";
|
||||
ms.channel = "";
|
||||
ms.version = "";
|
||||
ms.build = "";
|
||||
|
@ -111,12 +118,14 @@ namespace mamba
|
|||
modified_spec.channel = selected_channel;
|
||||
modified_spec.version = check_char(pool_id2str(pool, s->evr));
|
||||
modified_spec.build = check_char(solvable_lookup_str(s, SOLVABLE_BUILDFLAVOR));
|
||||
LOG_INFO << "Reinstall " << modified_spec.conda_build_form() << " from channel " << selected_channel;
|
||||
LOG_INFO << "Reinstall " << modified_spec.conda_build_form() << " from channel "
|
||||
<< selected_channel;
|
||||
return add_channel_specific_job(modified_spec, job_flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
Id inst_id = pool_conda_matchspec((Pool*) m_pool, ms.conda_build_form().c_str());
|
||||
Id inst_id
|
||||
= pool_conda_matchspec(reinterpret_cast<Pool*>(m_pool), ms.conda_build_form().c_str());
|
||||
queue_push2(&m_jobs, job_flag | SOLVER_SOLVABLE_PROVIDES, inst_id);
|
||||
}
|
||||
|
||||
|
@ -143,7 +152,8 @@ namespace mamba
|
|||
{
|
||||
if (job_flag & SOLVER_ERASE)
|
||||
{
|
||||
throw std::runtime_error("Cannot erase a channel-specific package. (" + job + ")");
|
||||
throw std::runtime_error("Cannot erase a channel-specific package. (" + job
|
||||
+ ")");
|
||||
}
|
||||
add_channel_specific_job(ms, job_flag);
|
||||
}
|
||||
|
@ -155,7 +165,8 @@ namespace mamba
|
|||
{
|
||||
// Todo remove double parsing?
|
||||
LOG_INFO << "Adding job: " << ms.conda_build_form() << std::endl;
|
||||
Id inst_id = pool_conda_matchspec((Pool*) m_pool, ms.conda_build_form().c_str());
|
||||
Id inst_id = pool_conda_matchspec(reinterpret_cast<Pool*>(m_pool),
|
||||
ms.conda_build_form().c_str());
|
||||
queue_push2(&m_jobs, job_flag | SOLVER_SOLVABLE_PROVIDES, inst_id);
|
||||
}
|
||||
}
|
||||
|
@ -164,19 +175,23 @@ namespace mamba
|
|||
void MSolver::add_constraint(const std::string& job)
|
||||
{
|
||||
MatchSpec ms(job);
|
||||
Id inst_id = pool_conda_matchspec((Pool*) m_pool, ms.conda_build_form().c_str());
|
||||
Id inst_id
|
||||
= pool_conda_matchspec(reinterpret_cast<Pool*>(m_pool), ms.conda_build_form().c_str());
|
||||
queue_push2(&m_jobs, SOLVER_INSTALL | SOLVER_SOLVABLE_PROVIDES, inst_id);
|
||||
}
|
||||
|
||||
void MSolver::add_pin(const std::string& job)
|
||||
{
|
||||
// if we pin a package, we need to remove all packages that don't match the pin from being
|
||||
// available for installation!
|
||||
// This is done by adding SOLVER_LOCK to the packages, so that they are prevented from being installed
|
||||
// A lock basically says: keep the state of the package. I.e. uninstalled packages stay uninstalled, installed packages stay installed.
|
||||
// A lock is a hard requirement, we could also use SOLVER_FAVOR for soft requirements
|
||||
// if we pin a package, we need to remove all packages that don't match the
|
||||
// pin from being available for installation! This is done by adding
|
||||
// SOLVER_LOCK to the packages, so that they are prevented from being
|
||||
// installed A lock basically says: keep the state of the package. I.e.
|
||||
// uninstalled packages stay uninstalled, installed packages stay installed.
|
||||
// A lock is a hard requirement, we could also use SOLVER_FAVOR for soft
|
||||
// requirements
|
||||
|
||||
// First we need to check if the pin is OK given the currently installed packages
|
||||
// First we need to check if the pin is OK given the currently installed
|
||||
// packages
|
||||
Pool* pool = m_pool;
|
||||
MatchSpec ms(job);
|
||||
|
||||
|
@ -188,8 +203,9 @@ namespace mamba
|
|||
// LOG_ERROR << "NAME " << name;
|
||||
// if (name == ms.name)
|
||||
// {
|
||||
// LOG_ERROR << "Found pinned package in installed packages, need to check pin now.";
|
||||
// LOG_ERROR << record.version << " vs " << ms.version;
|
||||
// LOG_ERROR << "Found pinned package in installed packages, need
|
||||
// to check pin now."; LOG_ERROR << record.version << " vs " <<
|
||||
// ms.version;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
@ -225,11 +241,12 @@ namespace mamba
|
|||
Queue selected_pkgs;
|
||||
queue_init(&selected_pkgs);
|
||||
|
||||
for (auto& id: all_solvables)
|
||||
for (auto& id : all_solvables)
|
||||
{
|
||||
if (matching_solvables.find(id) == matching_solvables.end())
|
||||
{
|
||||
// the solvable is _NOT_ matched by our pinning expression! So we have to lock it to make it un-installable
|
||||
// the solvable is _NOT_ matched by our pinning expression! So we have to
|
||||
// lock it to make it un-installable
|
||||
queue_push(&selected_pkgs, id);
|
||||
}
|
||||
}
|
||||
|
@ -291,7 +308,7 @@ namespace mamba
|
|||
m_is_solved = true;
|
||||
LOG_WARNING << "Problem count: " << solver_problem_count(m_solver) << std::endl;
|
||||
success = solver_problem_count(m_solver) == 0;
|
||||
JsonLogger::instance().json_write({{"success", success}});
|
||||
JsonLogger::instance().json_write({ { "success", success } });
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@ -314,4 +331,4 @@ namespace mamba
|
|||
{
|
||||
return m_solver;
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "openssl/md5.h"
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
|
||||
#include "subdirdata.hpp"
|
||||
|
||||
#include "openssl/md5.h"
|
||||
#include "output.hpp"
|
||||
#include "package_cache.hpp"
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
|
||||
namespace fs = ghc::filesystem;
|
||||
|
||||
|
@ -22,22 +22,24 @@ namespace decompress
|
|||
|
||||
LOG_INFO << "Decompressing from " << in << " to " << out;
|
||||
|
||||
struct archive *a = archive_read_new();
|
||||
struct archive* a = archive_read_new();
|
||||
archive_read_support_filter_bzip2(a);
|
||||
archive_read_support_format_raw(a);
|
||||
// TODO figure out good value for this
|
||||
const std::size_t BLOCKSIZE = 16384;
|
||||
r = archive_read_open_filename(a, in.c_str(), BLOCKSIZE);
|
||||
if (r != ARCHIVE_OK) {
|
||||
if (r != ARCHIVE_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
struct archive_entry *entry;
|
||||
struct archive_entry* entry;
|
||||
std::ofstream out_file(out);
|
||||
char buff[BLOCKSIZE];
|
||||
std::size_t buffsize = BLOCKSIZE;
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r != ARCHIVE_OK) {
|
||||
if (r != ARCHIVE_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -46,7 +48,8 @@ namespace decompress
|
|||
size = archive_read_data(a, &buff, buffsize);
|
||||
if (size < ARCHIVE_OK)
|
||||
{
|
||||
throw std::runtime_error(std::string("Could not read archive: ") + archive_error_string(a));
|
||||
throw std::runtime_error(std::string("Could not read archive: ")
|
||||
+ archive_error_string(a));
|
||||
}
|
||||
if (size == 0)
|
||||
{
|
||||
|
@ -58,11 +61,13 @@ namespace decompress
|
|||
archive_read_free(a);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} // namespace decompress
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
MSubdirData::MSubdirData(const std::string& name, const std::string& url, const std::string& repodata_fn)
|
||||
MSubdirData::MSubdirData(const std::string& name,
|
||||
const std::string& url,
|
||||
const std::string& repodata_fn)
|
||||
: m_loaded(false)
|
||||
, m_download_complete(false)
|
||||
, m_url(url)
|
||||
|
@ -72,16 +77,19 @@ namespace mamba
|
|||
{
|
||||
}
|
||||
|
||||
fs::file_time_type::duration MSubdirData::check_cache(const fs::path& cache_file, const fs::file_time_type::clock::time_point& ref)
|
||||
fs::file_time_type::duration MSubdirData::check_cache(
|
||||
const fs::path& cache_file, const fs::file_time_type::clock::time_point& ref)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
auto last_write = fs::last_write_time(cache_file);
|
||||
auto tdiff = ref - last_write;
|
||||
return tdiff;
|
||||
// auto as_seconds = std::chrono::duration_cast<std::chrono::duration<double>>(tdiff);
|
||||
// return as_seconds.count();
|
||||
// auto as_seconds =
|
||||
// std::chrono::duration_cast<std::chrono::duration<double>>(tdiff); return
|
||||
// as_seconds.count();
|
||||
}
|
||||
catch(...)
|
||||
catch (...)
|
||||
{
|
||||
// could not open the file...
|
||||
return fs::file_time_type::duration::max();
|
||||
|
@ -120,11 +128,13 @@ namespace mamba
|
|||
max_age = get_cache_control_max_age(el);
|
||||
}
|
||||
|
||||
auto cache_age_seconds = std::chrono::duration_cast<std::chrono::seconds>(cache_age).count();
|
||||
auto cache_age_seconds
|
||||
= std::chrono::duration_cast<std::chrono::seconds>(cache_age).count();
|
||||
if ((max_age > cache_age_seconds || Context::instance().offline) && !forbid_cache())
|
||||
{
|
||||
// cache valid!
|
||||
LOG_INFO << "Using cache " << m_url << " age in seconds: " << cache_age_seconds << " / " << max_age;
|
||||
LOG_INFO << "Using cache " << m_url << " age in seconds: " << cache_age_seconds
|
||||
<< " / " << max_age;
|
||||
std::string prefix = m_name;
|
||||
prefix.resize(PREFIX_LENGTH - 1, ' ');
|
||||
Console::stream() << prefix << " Using cache";
|
||||
|
@ -134,8 +144,10 @@ namespace mamba
|
|||
|
||||
// check solv cache
|
||||
auto solv_age = check_cache(m_solv_fn, now);
|
||||
LOG_INFO << "Solv cache age in seconds: " << std::chrono::duration_cast<std::chrono::seconds>(solv_age).count();
|
||||
if (solv_age != fs::file_time_type::duration::max() && solv_age.count() <= cache_age.count())
|
||||
LOG_INFO << "Solv cache age in seconds: "
|
||||
<< std::chrono::duration_cast<std::chrono::seconds>(solv_age).count();
|
||||
if (solv_age != fs::file_time_type::duration::max()
|
||||
&& solv_age.count() <= cache_age.count())
|
||||
{
|
||||
LOG_INFO << "Also using .solv cache file";
|
||||
m_solv_cache_valid = true;
|
||||
|
@ -188,7 +200,8 @@ namespace mamba
|
|||
{
|
||||
if (m_target->result != 0 || m_target->http_status >= 400)
|
||||
{
|
||||
LOG_INFO << "Unable to retrieve repodata (response: " << m_target->http_status << ") for " << m_url;
|
||||
LOG_INFO << "Unable to retrieve repodata (response: " << m_target->http_status
|
||||
<< ") for " << m_url;
|
||||
m_progress_bar.set_postfix(std::to_string(m_target->http_status) + " Failed");
|
||||
m_progress_bar.set_progress(100);
|
||||
m_progress_bar.mark_as_completed();
|
||||
|
@ -198,13 +211,15 @@ namespace mamba
|
|||
|
||||
LOG_WARNING << "HTTP response code: " << m_target->http_status;
|
||||
// Note HTTP status == 0 for files
|
||||
if (m_target->http_status == 0 || m_target->http_status == 200 || m_target->http_status == 304)
|
||||
if (m_target->http_status == 0 || m_target->http_status == 200
|
||||
|| m_target->http_status == 304)
|
||||
{
|
||||
m_download_complete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Unhandled HTTP code: " + std::to_string(m_target->http_status));
|
||||
throw std::runtime_error("Unhandled HTTP code: "
|
||||
+ std::to_string(m_target->http_status));
|
||||
}
|
||||
|
||||
if (m_target->http_status == 304)
|
||||
|
@ -215,9 +230,12 @@ namespace mamba
|
|||
auto solv_age = check_cache(m_solv_fn, now);
|
||||
|
||||
fs::last_write_time(m_json_fn, now);
|
||||
LOG_INFO << "Solv age: " << std::chrono::duration_cast<std::chrono::seconds>(solv_age).count()
|
||||
<< ", JSON age: " << std::chrono::duration_cast<std::chrono::seconds>(cache_age).count();
|
||||
if(solv_age != fs::file_time_type::duration::max() && solv_age.count() <= cache_age.count())
|
||||
LOG_INFO << "Solv age: "
|
||||
<< std::chrono::duration_cast<std::chrono::seconds>(solv_age).count()
|
||||
<< ", JSON age: "
|
||||
<< std::chrono::duration_cast<std::chrono::seconds>(cache_age).count();
|
||||
if (solv_age != fs::file_time_type::duration::max()
|
||||
&& solv_age.count() <= cache_age.count())
|
||||
{
|
||||
fs::last_write_time(m_solv_fn, now);
|
||||
m_solv_cache_valid = true;
|
||||
|
@ -262,14 +280,13 @@ namespace mamba
|
|||
temp_json << m_mod_etag.dump();
|
||||
|
||||
// replace `}` with `,`
|
||||
temp_json.seekp(-1, temp_json.cur); temp_json << ',';
|
||||
temp_json.seekp(-1, temp_json.cur);
|
||||
temp_json << ',';
|
||||
final_file << temp_json.str();
|
||||
temp_file.seekg(1);
|
||||
std::copy(
|
||||
std::istreambuf_iterator<char>(temp_file),
|
||||
std::istreambuf_iterator<char>(),
|
||||
std::ostreambuf_iterator<char>(final_file)
|
||||
);
|
||||
std::copy(std::istreambuf_iterator<char>(temp_file),
|
||||
std::istreambuf_iterator<char>(),
|
||||
std::ostreambuf_iterator<char>(final_file));
|
||||
|
||||
m_progress_bar.set_postfix("Done");
|
||||
m_progress_bar.set_progress(100);
|
||||
|
@ -306,7 +323,8 @@ namespace mamba
|
|||
m_progress_bar = Console::instance().add_progress_bar(m_name);
|
||||
m_target = std::make_unique<DownloadTarget>(m_name, m_url, m_temp_file->path());
|
||||
m_target->set_progress_bar(m_progress_bar);
|
||||
// if we get something _other_ than the noarch, we DO NOT throw if the file can't be retrieved
|
||||
// if we get something _other_ than the noarch, we DO NOT throw if the file
|
||||
// can't be retrieved
|
||||
if (!ends_with(m_name, "/noarch"))
|
||||
{
|
||||
m_target->set_ignore_failure(true);
|
||||
|
@ -320,7 +338,8 @@ namespace mamba
|
|||
static std::regex max_age_re("max-age=(\\d+)");
|
||||
std::smatch max_age_match;
|
||||
bool matches = std::regex_search(val, max_age_match, max_age_re);
|
||||
if (!matches) return 0;
|
||||
if (!matches)
|
||||
return 0;
|
||||
return std::stoi(max_age_match[1]);
|
||||
}
|
||||
|
||||
|
@ -332,8 +351,7 @@ namespace mamba
|
|||
// "_mod": "Sat, 04 Apr 2020 03:29:49 GMT",
|
||||
// "_cache_control": "public, max-age=1200"
|
||||
|
||||
auto extract_subjson = [](std::ifstream& s)
|
||||
{
|
||||
auto extract_subjson = [](std::ifstream& s) {
|
||||
char next;
|
||||
std::string result;
|
||||
bool escaped = false;
|
||||
|
@ -373,7 +391,7 @@ namespace mamba
|
|||
result = nlohmann::json::parse(json);
|
||||
return result;
|
||||
}
|
||||
catch(...)
|
||||
catch (...)
|
||||
{
|
||||
LOG_WARNING << "Could not parse mod / etag header!";
|
||||
return nlohmann::json();
|
||||
|
@ -394,7 +412,8 @@ namespace mamba
|
|||
|
||||
std::string create_cache_dir()
|
||||
{
|
||||
std::string cache_dir = PackageCacheData::first_writable().get_pkgs_dir().string() + "/cache";
|
||||
std::string cache_dir
|
||||
= PackageCacheData::first_writable().get_pkgs_dir().string() + "/cache";
|
||||
fs::create_directories(cache_dir);
|
||||
#ifndef _WIN32
|
||||
::chmod(cache_dir.c_str(), 02775);
|
||||
|
@ -404,13 +423,11 @@ namespace mamba
|
|||
|
||||
MRepo MSubdirData::create_repo(MPool& pool)
|
||||
{
|
||||
RepoMetadata meta {
|
||||
m_url,
|
||||
Context::instance().add_pip_as_python_dependency,
|
||||
m_mod_etag["_etag"],
|
||||
m_mod_etag["_mod"]
|
||||
};
|
||||
RepoMetadata meta{ m_url,
|
||||
Context::instance().add_pip_as_python_dependency,
|
||||
m_mod_etag["_etag"],
|
||||
m_mod_etag["_mod"] };
|
||||
|
||||
return MRepo(pool, m_name, cache_path(), meta);
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
// Copyright (c) 2019, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
#include "thread_utils.hpp"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
@ -8,7 +13,6 @@
|
|||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
/***********************
|
||||
* thread interruption *
|
||||
***********************/
|
||||
|
@ -20,10 +24,7 @@ namespace mamba
|
|||
|
||||
void set_default_signal_handler()
|
||||
{
|
||||
std::signal(SIGINT, [](int signum)
|
||||
{
|
||||
set_sig_interrupted();
|
||||
});
|
||||
std::signal(SIGINT, [](int signum) { set_sig_interrupted(); });
|
||||
}
|
||||
|
||||
bool is_sig_interrupted() noexcept
|
||||
|
@ -57,7 +58,7 @@ namespace mamba
|
|||
std::atomic<bool> is_clean = false;
|
||||
std::mutex main_mutex;
|
||||
std::condition_variable main_var;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void increase_thread_count()
|
||||
{
|
||||
|
@ -140,7 +141,7 @@ namespace mamba
|
|||
|
||||
#ifdef _WIN32
|
||||
|
||||
std::function<void ()> interruption_guard::m_cleanup_function;
|
||||
std::function<void()> interruption_guard::m_cleanup_function;
|
||||
|
||||
interruption_guard::~interruption_guard()
|
||||
{
|
||||
|
@ -180,4 +181,4 @@ namespace mamba
|
|||
|
||||
#endif
|
||||
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "transaction.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <stack>
|
||||
#include <thread>
|
||||
|
||||
#include "transaction.hpp"
|
||||
#include "match_spec.hpp"
|
||||
#include "link.hpp"
|
||||
#include "match_spec.hpp"
|
||||
#include "thread_utils.hpp"
|
||||
|
||||
namespace mamba
|
||||
|
@ -26,7 +27,8 @@ namespace mamba
|
|||
|
||||
std::mutex PackageDownloadExtractTarget::extract_mutex;
|
||||
|
||||
PackageDownloadExtractTarget::PackageDownloadExtractTarget(const MRepo& repo, Solvable* solvable)
|
||||
PackageDownloadExtractTarget::PackageDownloadExtractTarget(const MRepo& repo,
|
||||
Solvable* solvable)
|
||||
: m_solv(solvable)
|
||||
, m_finished(false)
|
||||
{
|
||||
|
@ -80,14 +82,16 @@ namespace mamba
|
|||
if (size_t(m_target->downloaded_size) != expected_size)
|
||||
{
|
||||
LOG_ERROR << "File not valid: file size doesn't match expectation " << m_tarball_path;
|
||||
throw std::runtime_error("File not valid: file size doesn't match expectation (" + std::string(m_tarball_path) + ")");
|
||||
throw std::runtime_error("File not valid: file size doesn't match expectation ("
|
||||
+ std::string(m_tarball_path) + ")");
|
||||
}
|
||||
interruption_point();
|
||||
std::string sha256_check = lookup_checksum(m_solv, SOLVABLE_CHECKSUM);
|
||||
if (!sha256_check.empty() && !validate::sha256(m_tarball_path, sha256_check))
|
||||
{
|
||||
LOG_ERROR << "File not valid: SHA256 sum doesn't match expectation " << m_tarball_path;
|
||||
throw std::runtime_error("File not valid: SHA256 sum doesn't match expectation (" + std::string(m_tarball_path) + ")");
|
||||
throw std::runtime_error("File not valid: SHA256 sum doesn't match expectation ("
|
||||
+ std::string(m_tarball_path) + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -95,7 +99,8 @@ namespace mamba
|
|||
if (!md5_check.empty() && !validate::md5(m_tarball_path, md5_check))
|
||||
{
|
||||
LOG_ERROR << "File not valid: MD5 sum doesn't match expectation " << m_tarball_path;
|
||||
throw std::runtime_error("File not valid: MD5 sum doesn't match expectation (" + std::string(m_tarball_path) + ")");
|
||||
throw std::runtime_error("File not valid: MD5 sum doesn't match expectation ("
|
||||
+ std::string(m_tarball_path) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,7 +121,8 @@ namespace mamba
|
|||
|
||||
interruption_point();
|
||||
std::stringstream final_msg;
|
||||
final_msg << "Finished " << std::left << std::setw(30) << m_name << std::right << std::setw(8);
|
||||
final_msg << "Finished " << std::left << std::setw(30) << m_name << std::right
|
||||
<< std::setw(8);
|
||||
m_progress_proxy.elapsed_time_to_stream(final_msg);
|
||||
final_msg << " " << std::setw(12 + 2);
|
||||
to_human_readable_filesize(final_msg, expected_size);
|
||||
|
@ -148,7 +154,8 @@ namespace mamba
|
|||
}
|
||||
|
||||
// todo remove cache from this interface
|
||||
DownloadTarget* PackageDownloadExtractTarget::target(const fs::path& cache_path, MultiPackageCache& cache)
|
||||
DownloadTarget* PackageDownloadExtractTarget::target(const fs::path& cache_path,
|
||||
MultiPackageCache& cache)
|
||||
{
|
||||
m_cache_path = cache_path;
|
||||
m_tarball_path = cache_path / m_filename;
|
||||
|
@ -187,7 +194,8 @@ namespace mamba
|
|||
|
||||
bool MTransaction::filter(Solvable* s)
|
||||
{
|
||||
if (m_filter_type == FilterType::none) return false;
|
||||
if (m_filter_type == FilterType::none)
|
||||
return false;
|
||||
bool spec_in_filter = m_filter_name_ids.count(s->name);
|
||||
|
||||
if (m_filter_type == FilterType::keep_only)
|
||||
|
@ -200,13 +208,13 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
MTransaction::MTransaction(MSolver& solver, MultiPackageCache& cache)
|
||||
: m_multi_cache(cache)
|
||||
{
|
||||
if (!solver.is_solved())
|
||||
{
|
||||
throw std::runtime_error("Cannot create transaction without calling solver.solve() first.");
|
||||
throw std::runtime_error(
|
||||
"Cannot create transaction without calling solver.solve() first.");
|
||||
}
|
||||
|
||||
m_transaction = solver_create_transaction(solver);
|
||||
|
@ -264,10 +272,10 @@ namespace mamba
|
|||
|
||||
if (solver.only_deps == false)
|
||||
{
|
||||
auto to_string_vec = [](const std::vector<MatchSpec>& vec) -> std::vector<std::string>
|
||||
{
|
||||
auto to_string_vec = [](const std::vector<MatchSpec>& vec) -> std::vector<std::string> {
|
||||
std::vector<std::string> res;
|
||||
for (const auto& el : vec) res.push_back(el.str());
|
||||
for (const auto& el : vec)
|
||||
res.push_back(el.str());
|
||||
return res;
|
||||
};
|
||||
m_history_entry.update = to_string_vec(solver.install_specs());
|
||||
|
@ -281,7 +289,7 @@ namespace mamba
|
|||
if (!empty())
|
||||
{
|
||||
JsonLogger::instance().json_down("actions");
|
||||
JsonLogger::instance().json_write({{"PREFIX", Context::instance().target_prefix}});
|
||||
JsonLogger::instance().json_write({ { "PREFIX", Context::instance().target_prefix } });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,8 +306,7 @@ namespace mamba
|
|||
queue_init(&classes);
|
||||
queue_init(&pkgs);
|
||||
|
||||
int mode = SOLVER_TRANSACTION_SHOW_OBSOLETES |
|
||||
SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE;
|
||||
int mode = SOLVER_TRANSACTION_SHOW_OBSOLETES | SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE;
|
||||
|
||||
transaction_classify(m_transaction, mode, &classes);
|
||||
|
||||
|
@ -309,12 +316,12 @@ namespace mamba
|
|||
cls = classes.elements[i];
|
||||
// cnt = classes.elements[i + 1];
|
||||
|
||||
transaction_classify_pkgs(m_transaction, mode, cls, classes.elements[i + 2],
|
||||
classes.elements[i + 3], &pkgs);
|
||||
transaction_classify_pkgs(
|
||||
m_transaction, mode, cls, classes.elements[i + 2], classes.elements[i + 3], &pkgs);
|
||||
for (int j = 0; j < pkgs.count; j++)
|
||||
{
|
||||
Id p = pkgs.elements[j];
|
||||
Solvable *s = m_transaction->pool->solvables + p;
|
||||
Solvable* s = m_transaction->pool->solvables + p;
|
||||
|
||||
if (filter(s))
|
||||
{
|
||||
|
@ -327,9 +334,11 @@ namespace mamba
|
|||
case SOLVER_TRANSACTION_UPGRADED:
|
||||
case SOLVER_TRANSACTION_CHANGED:
|
||||
case SOLVER_TRANSACTION_REINSTALLED:
|
||||
if (cls == SOLVER_TRANSACTION_REINSTALLED && m_force_reinstall == false) break;
|
||||
if (cls == SOLVER_TRANSACTION_REINSTALLED && m_force_reinstall == false)
|
||||
break;
|
||||
m_to_remove.push_back(s);
|
||||
m_to_install.push_back(m_transaction->pool->solvables + transaction_obs_pkg(m_transaction, p));
|
||||
m_to_install.push_back(m_transaction->pool->solvables
|
||||
+ transaction_obs_pkg(m_transaction, p));
|
||||
break;
|
||||
case SOLVER_TRANSACTION_ERASE:
|
||||
m_to_remove.push_back(s);
|
||||
|
@ -354,10 +363,11 @@ namespace mamba
|
|||
|
||||
std::string MTransaction::find_python_version()
|
||||
{
|
||||
// We need to find the python version that will be there after this Transaction is finished
|
||||
// in order to compile the noarch packages correctly, for example
|
||||
// We need to find the python version that will be there after this
|
||||
// Transaction is finished in order to compile the noarch packages correctly,
|
||||
// for example
|
||||
Pool* pool = m_transaction->pool;
|
||||
assert (pool != nullptr);
|
||||
assert(pool != nullptr);
|
||||
|
||||
std::string py_ver;
|
||||
Id python = pool_str2id(pool, "python", 0);
|
||||
|
@ -391,7 +401,8 @@ namespace mamba
|
|||
// we need to make sure that we're not about to remove python!
|
||||
for (Solvable* s : m_to_remove)
|
||||
{
|
||||
if (s->name == python) return "";
|
||||
if (s->name == python)
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return py_ver;
|
||||
|
@ -400,7 +411,6 @@ namespace mamba
|
|||
class TransactionRollback
|
||||
{
|
||||
public:
|
||||
|
||||
void record(const UnlinkPackage& unlink)
|
||||
{
|
||||
m_unlink_stack.push(unlink);
|
||||
|
@ -413,13 +423,13 @@ namespace mamba
|
|||
|
||||
void rollback()
|
||||
{
|
||||
while(!m_link_stack.empty())
|
||||
while (!m_link_stack.empty())
|
||||
{
|
||||
m_link_stack.top().undo();
|
||||
m_link_stack.pop();
|
||||
}
|
||||
|
||||
while(!m_unlink_stack.empty())
|
||||
while (!m_unlink_stack.empty())
|
||||
{
|
||||
m_unlink_stack.top().undo();
|
||||
m_unlink_stack.pop();
|
||||
|
@ -427,7 +437,6 @@ namespace mamba
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
std::stack<UnlinkPackage> m_unlink_stack;
|
||||
std::stack<LinkPackage> m_link_stack;
|
||||
};
|
||||
|
@ -438,9 +447,11 @@ namespace mamba
|
|||
// back to the top level if any action was required
|
||||
if (!empty())
|
||||
JsonLogger::instance().json_up();
|
||||
JsonLogger::instance().json_write({{"dry_run", Context::instance().dry_run}, {"prefix", Context::instance().target_prefix}});
|
||||
JsonLogger::instance().json_write({ { "dry_run", Context::instance().dry_run },
|
||||
{ "prefix", Context::instance().target_prefix } });
|
||||
if (empty())
|
||||
JsonLogger::instance().json_write({{"message", "All requested packages already installed"}});
|
||||
JsonLogger::instance().json_write(
|
||||
{ { "message", "All requested packages already installed" } });
|
||||
// finally, print the JSON
|
||||
if (Context::instance().json)
|
||||
Console::instance().print(JsonLogger::instance().json_log.unflatten().dump(4), true);
|
||||
|
@ -463,7 +474,7 @@ namespace mamba
|
|||
{
|
||||
Id p = m_transaction->steps.elements[i];
|
||||
Id ttype = transaction_type(m_transaction, p, SOLVER_TRANSACTION_SHOW_ALL);
|
||||
Solvable *s = pool_id2solvable(pool, p);
|
||||
Solvable* s = pool_id2solvable(pool, p);
|
||||
|
||||
if (filter(s))
|
||||
{
|
||||
|
@ -477,10 +488,13 @@ namespace mamba
|
|||
case SOLVER_TRANSACTION_CHANGED:
|
||||
case SOLVER_TRANSACTION_REINSTALLED:
|
||||
{
|
||||
if (ttype == SOLVER_TRANSACTION_REINSTALLED && m_force_reinstall == false) break;
|
||||
if (ttype == SOLVER_TRANSACTION_REINSTALLED && m_force_reinstall == false)
|
||||
break;
|
||||
|
||||
Solvable* s2 = m_transaction->pool->solvables + transaction_obs_pkg(m_transaction, p);
|
||||
Console::stream() << "Changing " << PackageInfo(s).str() << " ==> " << PackageInfo(s2).str();
|
||||
Solvable* s2
|
||||
= m_transaction->pool->solvables + transaction_obs_pkg(m_transaction, p);
|
||||
Console::stream()
|
||||
<< "Changing " << PackageInfo(s).str() << " ==> " << PackageInfo(s2).str();
|
||||
PackageInfo p_unlink(s);
|
||||
PackageInfo p_link(s2);
|
||||
|
||||
|
@ -488,7 +502,6 @@ namespace mamba
|
|||
up.execute();
|
||||
rollback.record(up);
|
||||
|
||||
|
||||
LinkPackage lp(p_link, fs::path(cache_dir), &m_transaction_context);
|
||||
lp.execute();
|
||||
rollback.record(lp);
|
||||
|
@ -565,7 +578,8 @@ namespace mamba
|
|||
}
|
||||
else
|
||||
{
|
||||
channel = s->repo->name; // note this can and should be <unknown> when e.g. installing from a tarball
|
||||
channel = s->repo->name; // note this can and should be <unknown> when
|
||||
// e.g. installing from a tarball
|
||||
}
|
||||
|
||||
to_install_structured.emplace_back(channel, mediafile, s_json);
|
||||
|
@ -613,7 +627,8 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
bool MTransaction::fetch_extract_packages(const std::string& cache_dir, std::vector<MRepo*>& repos)
|
||||
bool MTransaction::fetch_extract_packages(const std::string& cache_dir,
|
||||
std::vector<MRepo*>& repos)
|
||||
{
|
||||
fs::path cache_path(cache_dir);
|
||||
std::vector<std::unique_ptr<PackageDownloadExtractTarget>> targets;
|
||||
|
@ -642,10 +657,7 @@ namespace mamba
|
|||
multi_dl.add(targets[targets.size() - 1]->target(cache_path, m_multi_cache));
|
||||
}
|
||||
|
||||
interruption_guard g([]()
|
||||
{
|
||||
Console::instance().init_multi_progress();
|
||||
});
|
||||
interruption_guard g([]() { Console::instance().init_multi_progress(); });
|
||||
|
||||
bool downloaded = multi_dl.download(true);
|
||||
|
||||
|
@ -742,10 +754,13 @@ namespace mamba
|
|||
Console::print(" No specs added or removed.\n");
|
||||
}
|
||||
|
||||
printers::Table t({"Package", "Version", "Build", "Channel", "Size"});
|
||||
t.set_alignment({printers::alignment::left, printers::alignment::right, printers::alignment::left,
|
||||
printers::alignment::left, printers::alignment::right});
|
||||
t.set_padding({2, 2, 2, 2, 5});
|
||||
printers::Table t({ "Package", "Version", "Build", "Channel", "Size" });
|
||||
t.set_alignment({ printers::alignment::left,
|
||||
printers::alignment::right,
|
||||
printers::alignment::left,
|
||||
printers::alignment::left,
|
||||
printers::alignment::right });
|
||||
t.set_padding({ 2, 2, 2, 2, 5 });
|
||||
Queue classes, pkgs;
|
||||
|
||||
queue_init(&classes);
|
||||
|
@ -757,13 +772,13 @@ namespace mamba
|
|||
std::size_t total_size = 0;
|
||||
auto* pool = m_transaction->pool;
|
||||
|
||||
auto format_row = [this, pool, &total_size](rows& r, Solvable* s, printers::format flag)
|
||||
{
|
||||
auto format_row = [this, pool, &total_size](rows& r, Solvable* s, printers::format flag) {
|
||||
std::ptrdiff_t dlsize = solvable_lookup_num(s, SOLVABLE_DOWNLOADSIZE, -1);
|
||||
printers::FormattedString dlsize_s;
|
||||
if (dlsize != -1)
|
||||
{
|
||||
if (static_cast<std::size_t>(flag) & static_cast<std::size_t>(printers::format::yellow))
|
||||
if (static_cast<std::size_t>(flag)
|
||||
& static_cast<std::size_t>(printers::format::yellow))
|
||||
{
|
||||
dlsize_s.s = "Ignored";
|
||||
}
|
||||
|
@ -778,7 +793,8 @@ namespace mamba
|
|||
to_human_readable_filesize(s, dlsize);
|
||||
dlsize_s.s = s.str();
|
||||
// Hacky hacky
|
||||
if (static_cast<std::size_t>(flag) & static_cast<std::size_t>(printers::format::green))
|
||||
if (static_cast<std::size_t>(flag)
|
||||
& static_cast<std::size_t>(printers::format::green))
|
||||
{
|
||||
total_size += dlsize;
|
||||
}
|
||||
|
@ -797,13 +813,15 @@ namespace mamba
|
|||
}
|
||||
else
|
||||
{
|
||||
channel = s->repo->name; // note this can and should be <unknown> when e.g. installing from a tarball
|
||||
channel = s->repo->name; // note this can and should be <unknown> when
|
||||
// e.g. installing from a tarball
|
||||
}
|
||||
|
||||
r.push_back({name,
|
||||
printers::FormattedString(pool_id2str(pool, s->evr)),
|
||||
printers::FormattedString(build_string ? build_string : ""),
|
||||
printers::FormattedString(cut_repo_name(channel)), dlsize_s});
|
||||
r.push_back({ name,
|
||||
printers::FormattedString(pool_id2str(pool, s->evr)),
|
||||
printers::FormattedString(build_string ? build_string : ""),
|
||||
printers::FormattedString(cut_repo_name(channel)),
|
||||
dlsize_s });
|
||||
};
|
||||
|
||||
int mode = SOLVER_TRANSACTION_SHOW_OBSOLETES | SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE;
|
||||
|
@ -812,13 +830,13 @@ namespace mamba
|
|||
for (int i = 0; i < classes.count; i += 4)
|
||||
{
|
||||
cls = classes.elements[i];
|
||||
transaction_classify_pkgs(m_transaction, mode, cls, classes.elements[i + 2],
|
||||
classes.elements[i + 3], &pkgs);
|
||||
transaction_classify_pkgs(
|
||||
m_transaction, mode, cls, classes.elements[i + 2], classes.elements[i + 3], &pkgs);
|
||||
|
||||
for (int j = 0; j < pkgs.count; j++)
|
||||
{
|
||||
Id p = pkgs.elements[j];
|
||||
Solvable *s = m_transaction->pool->solvables + p;
|
||||
Solvable* s = m_transaction->pool->solvables + p;
|
||||
|
||||
if (filter(s))
|
||||
{
|
||||
|
@ -829,18 +847,28 @@ namespace mamba
|
|||
{
|
||||
case SOLVER_TRANSACTION_UPGRADED:
|
||||
format_row(upgraded, s, printers::format::red);
|
||||
format_row(upgraded, m_transaction->pool->solvables + transaction_obs_pkg(m_transaction, p), printers::format::green);
|
||||
format_row(upgraded,
|
||||
m_transaction->pool->solvables
|
||||
+ transaction_obs_pkg(m_transaction, p),
|
||||
printers::format::green);
|
||||
break;
|
||||
case SOLVER_TRANSACTION_CHANGED:
|
||||
case SOLVER_TRANSACTION_REINSTALLED:
|
||||
if (cls == SOLVER_TRANSACTION_REINSTALLED && m_force_reinstall == false) break;
|
||||
if (cls == SOLVER_TRANSACTION_REINSTALLED && m_force_reinstall == false)
|
||||
break;
|
||||
|
||||
format_row(changed, s, printers::format::red);
|
||||
format_row(changed, m_transaction->pool->solvables + transaction_obs_pkg(m_transaction, p), printers::format::green);
|
||||
format_row(changed,
|
||||
m_transaction->pool->solvables
|
||||
+ transaction_obs_pkg(m_transaction, p),
|
||||
printers::format::green);
|
||||
break;
|
||||
case SOLVER_TRANSACTION_DOWNGRADED:
|
||||
format_row(downgraded, s, printers::format::red);
|
||||
format_row(downgraded, m_transaction->pool->solvables + transaction_obs_pkg(m_transaction, p), printers::format::green);
|
||||
format_row(downgraded,
|
||||
m_transaction->pool->solvables
|
||||
+ transaction_obs_pkg(m_transaction, p),
|
||||
printers::format::green);
|
||||
break;
|
||||
case SOLVER_TRANSACTION_ERASE:
|
||||
format_row(erased, s, printers::format::red);
|
||||
|
@ -901,4 +929,4 @@ namespace mamba
|
|||
t.add_row({ summary.str() });
|
||||
t.print(std::cout);
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -19,11 +19,11 @@ namespace mamba
|
|||
// supply short python version, e.g. 2.7, 3.5...
|
||||
fs::path get_python_short_path(const std::string& python_version)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
return "python.exe";
|
||||
#else
|
||||
#else
|
||||
return fs::path("bin") / concat("python", python_version);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
fs::path get_python_site_packages_short_path(const std::string& python_version)
|
||||
|
@ -33,32 +33,35 @@ namespace mamba
|
|||
return fs::path();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
return fs::path("Lib") / "site-packages";
|
||||
#else
|
||||
#else
|
||||
return fs::path("lib") / concat("python", python_version) / "site-packages";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
fs::path get_bin_directory_short_path()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
return "Scripts";
|
||||
#else
|
||||
#else
|
||||
return "bin";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
fs::path get_python_noarch_target_path(const std::string& source_short_path, const fs::path& target_site_packages_short_path)
|
||||
fs::path get_python_noarch_target_path(const std::string& source_short_path,
|
||||
const fs::path& target_site_packages_short_path)
|
||||
{
|
||||
if (starts_with(source_short_path, "site-packages/"))
|
||||
{
|
||||
// replace `site_packages/` with prefix/site_packages
|
||||
return target_site_packages_short_path / source_short_path.substr(14, source_short_path.size() - 14);
|
||||
return target_site_packages_short_path
|
||||
/ source_short_path.substr(14, source_short_path.size() - 14);
|
||||
}
|
||||
else if (starts_with(source_short_path, "python-scripts/"))
|
||||
{
|
||||
return get_bin_directory_short_path() / source_short_path.substr(15, source_short_path.size() - 15);
|
||||
return get_bin_directory_short_path()
|
||||
/ source_short_path.substr(15, source_short_path.size() - 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
37
src/url.cpp
37
src/url.cpp
|
@ -4,12 +4,12 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "url.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
|
||||
#include "url.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace fs = ghc::filesystem;
|
||||
|
@ -22,16 +22,15 @@ namespace mamba
|
|||
return std::regex_search(url, re);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
std::regex token_re("/t/([a-zA-Z0-9-]*)");
|
||||
auto token_begin = std::sregex_iterator(url.begin(), url.end(), token_re);
|
||||
if (token_begin != std::sregex_iterator())
|
||||
{
|
||||
token = token_begin->str().substr(3u);
|
||||
cleaned_url = std::regex_replace(url, token_re, "", std::regex_constants::format_first_only);
|
||||
cleaned_url
|
||||
= std::regex_replace(url, token_re, "", std::regex_constants::format_first_only);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -65,7 +64,7 @@ namespace mamba
|
|||
{
|
||||
platform = "";
|
||||
size_t pos = std::string::npos;
|
||||
for(auto it = known_platforms.begin(); it != known_platforms.end(); ++it)
|
||||
for (auto it = known_platforms.begin(); it != known_platforms.end(); ++it)
|
||||
{
|
||||
pos = url.find(*it);
|
||||
if (pos != std::string::npos)
|
||||
|
@ -128,8 +127,8 @@ namespace mamba
|
|||
uc = curl_url_set(m_handle, CURLUPART_URL, url.c_str(), curl_flags);
|
||||
if (uc)
|
||||
{
|
||||
throw std::runtime_error("Could not set URL (code: " + std::to_string(uc) +
|
||||
" - url = " + url + ")");
|
||||
throw std::runtime_error("Could not set URL (code: " + std::to_string(uc)
|
||||
+ " - url = " + url + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -310,20 +309,9 @@ namespace mamba
|
|||
|
||||
namespace
|
||||
{
|
||||
const std::vector<std::string> CURLUPART_NAMES =
|
||||
{
|
||||
"url",
|
||||
"scheme",
|
||||
"user",
|
||||
"password",
|
||||
"options",
|
||||
"host",
|
||||
"port",
|
||||
"path",
|
||||
"query",
|
||||
"fragment",
|
||||
"zoneid"
|
||||
};
|
||||
const std::vector<std::string> CURLUPART_NAMES
|
||||
= { "url", "scheme", "user", "password", "options", "host",
|
||||
"port", "path", "query", "fragment", "zoneid" };
|
||||
}
|
||||
|
||||
std::string URLHandler::get_part(CURLUPart part)
|
||||
|
@ -339,7 +327,6 @@ namespace mamba
|
|||
else
|
||||
{
|
||||
return "";
|
||||
//throw std::runtime_error("Could not find " + CURLUPART_NAMES[part] + " of url " + m_url);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,4 +339,4 @@ namespace mamba
|
|||
throw std::runtime_error("Could not set " + s + " in url " + m_url);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
70
src/util.cpp
70
src/util.cpp
|
@ -4,19 +4,20 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cerrno>
|
||||
#include <thread>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
|
||||
#include <cassert>
|
||||
#endif
|
||||
|
||||
#include "util.hpp"
|
||||
#include "context.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -35,7 +36,7 @@ namespace mamba
|
|||
// False
|
||||
bool lexists(const fs::path& path)
|
||||
{
|
||||
return fs::exists(path); // && fs::status_known(fs::symlink_status(path));
|
||||
return fs::exists(path); // && fs::status_known(fs::symlink_status(path));
|
||||
}
|
||||
|
||||
void to_human_readable_filesize(std::ostream& o, double bytes, std::size_t precision)
|
||||
|
@ -85,18 +86,18 @@ namespace mamba
|
|||
TemporaryDirectory::TemporaryDirectory()
|
||||
{
|
||||
bool success = false;
|
||||
#ifndef _WIN32
|
||||
std::string template_path = fs::temp_directory_path() / "mambadXXXXXX";
|
||||
char* pth = mkdtemp((char*)template_path.c_str());
|
||||
success = (pth != nullptr);
|
||||
template_path = pth;
|
||||
#else
|
||||
std::string template_path = fs::temp_directory_path() / "mambadXXXXXX";
|
||||
// include \0 terminator
|
||||
auto err = _mktemp_s((char*)template_path.c_str(), template_path.size() + 1);
|
||||
assert(err == 0);
|
||||
success = fs::create_directory(template_path);
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
std::string template_path = fs::temp_directory_path() / "mambadXXXXXX";
|
||||
char* pth = mkdtemp(const_cast<char*>(template_path.c_str()));
|
||||
success = (pth != nullptr);
|
||||
template_path = pth;
|
||||
#else
|
||||
std::string template_path = fs::temp_directory_path() / "mambadXXXXXX";
|
||||
// include \0 terminator
|
||||
auto err = _mktemp_s(const_cast<char*>(template_path.c_str()), template_path.size() + 1);
|
||||
assert(err == 0);
|
||||
success = fs::create_directory(template_path);
|
||||
#endif
|
||||
if (!success)
|
||||
{
|
||||
throw std::runtime_error("Could not create temporary directory!");
|
||||
|
@ -185,7 +186,8 @@ namespace mamba
|
|||
|
||||
bool ends_with(const std::string_view& str, const std::string_view& suffix)
|
||||
{
|
||||
return str.size() >= suffix.size() && 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
|
||||
return str.size() >= suffix.size()
|
||||
&& 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
|
||||
}
|
||||
|
||||
bool starts_with(const std::string_view& str, const std::string_view& prefix)
|
||||
|
@ -227,7 +229,6 @@ namespace mamba
|
|||
return end == std::string::npos ? "" : input.substr(0, end + 1);
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> split(const std::string_view& input,
|
||||
const std::string_view& sep,
|
||||
std::size_t max_split)
|
||||
|
@ -239,7 +240,8 @@ namespace mamba
|
|||
{
|
||||
if (input[i] == sep[0] && input.substr(i, n) == sep)
|
||||
{
|
||||
if (max_split-- <= 0) break;
|
||||
if (max_split-- <= 0)
|
||||
break;
|
||||
result.emplace_back(input.substr(j, i - j));
|
||||
i = j = i + n;
|
||||
}
|
||||
|
@ -256,19 +258,23 @@ namespace mamba
|
|||
const std::string_view& sep,
|
||||
std::size_t max_split)
|
||||
{
|
||||
if (max_split == SIZE_MAX) return split(input, sep, max_split);
|
||||
if (max_split == SIZE_MAX)
|
||||
return split(input, sep, max_split);
|
||||
|
||||
std::vector<std::string> result;
|
||||
|
||||
std::ptrdiff_t i, j, len = static_cast<std::ptrdiff_t>(input.size()),
|
||||
n = static_cast<std::ptrdiff_t>(sep.size());
|
||||
n = static_cast<std::ptrdiff_t>(sep.size());
|
||||
i = j = len;
|
||||
|
||||
while (i >= n)
|
||||
{
|
||||
if (input[i - 1] == sep[n - 1] && input.substr(i - n, n) == sep)
|
||||
{
|
||||
if (max_split-- <= 0) { break; }
|
||||
if (max_split-- <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
result.emplace_back(input.substr(i, j - i));
|
||||
i = j = i - n;
|
||||
}
|
||||
|
@ -307,9 +313,8 @@ namespace mamba
|
|||
std::string string_transform(const std::string_view& input, int (*functor)(int))
|
||||
{
|
||||
std::string res(input);
|
||||
std::transform(res.begin(), res.end(), res.begin(),
|
||||
[&](unsigned char c) { return functor(c); }
|
||||
);
|
||||
std::transform(
|
||||
res.begin(), res.end(), res.begin(), [&](unsigned char c) { return functor(c); });
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -334,11 +339,12 @@ namespace mamba
|
|||
in.seekg(0, std::ios::beg);
|
||||
in.read(&contents[0], contents.size());
|
||||
in.close();
|
||||
return(contents);
|
||||
return (contents);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::system_error(errno, std::system_category(), "failed to open " + file_path.string());
|
||||
throw std::system_error(
|
||||
errno, std::system_category(), "failed to open " + file_path.string());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,7 +353,8 @@ namespace mamba
|
|||
std::fstream file_stream(file_path, std::ios_base::in | std::ios_base::binary);
|
||||
if (file_stream.fail())
|
||||
{
|
||||
throw std::system_error(errno, std::system_category(), "failed to open " + file_path.string());
|
||||
throw std::system_error(
|
||||
errno, std::system_category(), "failed to open " + file_path.string());
|
||||
}
|
||||
|
||||
std::vector<std::string> output;
|
||||
|
@ -355,7 +362,8 @@ namespace mamba
|
|||
while (std::getline(file_stream, line))
|
||||
{
|
||||
// Remove the trailing \r to accomodate Windows line endings.
|
||||
if ((!line.empty()) && (line.back() == '\r')) line.pop_back();
|
||||
if ((!line.empty()) && (line.back() == '\r'))
|
||||
line.pop_back();
|
||||
|
||||
output.push_back(line);
|
||||
}
|
||||
|
@ -364,4 +372,4 @@ namespace mamba
|
|||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <iostream>
|
||||
#include "openssl/sha.h"
|
||||
#include "openssl/md5.h"
|
||||
#include "validate.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "openssl/md5.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "output.hpp"
|
||||
#include "util.hpp"
|
||||
#include "validate.hpp"
|
||||
|
||||
namespace validate
|
||||
{
|
||||
|
@ -80,4 +81,4 @@ namespace validate
|
|||
{
|
||||
return fs::file_size(path) == validation;
|
||||
}
|
||||
}
|
||||
} // namespace validate
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
|
@ -52,4 +53,4 @@ namespace mamba
|
|||
src_end.close();
|
||||
dst_end.close();
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -7,7 +7,8 @@ namespace mamba
|
|||
TEST(activation, activation)
|
||||
{
|
||||
PosixActivator a;
|
||||
// std::cout << a.add_prefix_to_path("/home/wolfv/miniconda3", 0) << std::endl;
|
||||
// std::cout << a.activate("/home/wolfv/miniconda3/", false) << std::endl;
|
||||
// std::cout << a.add_prefix_to_path("/home/wolfv/miniconda3", 0) <<
|
||||
// std::endl; std::cout << a.activate("/home/wolfv/miniconda3/", false) <<
|
||||
// std::endl;
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
#include "url.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
namespace fs = ghc::filesystem;
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
#ifdef __linux__
|
||||
#ifdef __linux__
|
||||
std::string platform("linux-64");
|
||||
#elif __APPLE__
|
||||
#elif __APPLE__
|
||||
std::string platform("osx-64");
|
||||
#elif _WIN32
|
||||
#elif _WIN32
|
||||
std::string platform("win-64");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
TEST(ChannelContext, init)
|
||||
{
|
||||
|
@ -75,23 +74,23 @@ namespace mamba
|
|||
std::string value4 = "/home/mamba/test/channel_b";
|
||||
Channel& c4 = make_channel(value4);
|
||||
EXPECT_EQ(c4.scheme(), "file");
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
std::string driveletter = fs::absolute(fs::path("/")).string().substr(0, 1);
|
||||
EXPECT_EQ(c4.location(), driveletter + ":/home/mamba/test");
|
||||
#else
|
||||
#else
|
||||
EXPECT_EQ(c4.location(), "/home/mamba/test");
|
||||
#endif
|
||||
#endif
|
||||
EXPECT_EQ(c4.name(), "channel_b");
|
||||
EXPECT_EQ(c4.platform(), "");
|
||||
|
||||
std::string value5 = "/home/mamba/test/channel_b/" + platform;
|
||||
Channel& c5 = make_channel(value5);
|
||||
EXPECT_EQ(c5.scheme(), "file");
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
EXPECT_EQ(c5.location(), driveletter + ":/home/mamba/test");
|
||||
#else
|
||||
#else
|
||||
EXPECT_EQ(c5.location(), "/home/mamba/test");
|
||||
#endif
|
||||
#endif
|
||||
EXPECT_EQ(c5.name(), "channel_b");
|
||||
EXPECT_EQ(c5.platform(), platform);
|
||||
}
|
||||
|
@ -123,7 +122,7 @@ namespace mamba
|
|||
EXPECT_EQ(res.size(), on_win ? 8u : 6u);
|
||||
EXPECT_EQ(res[0], "https://conda.anaconda.org/conda-forge/" + platform);
|
||||
EXPECT_EQ(res[1], "https://conda.anaconda.org/conda-forge/noarch");
|
||||
EXPECT_EQ(res[2], "https://repo.anaconda.com/pkgs/main/" + platform);
|
||||
EXPECT_EQ(res[2], "https://repo.anaconda.com/pkgs/main/" + platform);
|
||||
EXPECT_EQ(res[3], "https://repo.anaconda.com/pkgs/main/noarch");
|
||||
EXPECT_EQ(res[4], "https://repo.anaconda.com/pkgs/r/" + platform);
|
||||
EXPECT_EQ(res[5], "https://repo.anaconda.com/pkgs/r/noarch");
|
||||
|
@ -137,12 +136,12 @@ namespace mamba
|
|||
EXPECT_EQ(res2[4], res[4]);
|
||||
EXPECT_EQ(res2[5], res[5]);
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
EXPECT_EQ(res[6], "https://repo.anaconda.com/pkgs/msys2/" + platform);
|
||||
EXPECT_EQ(res[7], "https://repo.anaconda.com/pkgs/msys2/noarch");
|
||||
EXPECT_EQ(res2[6], res[6]);
|
||||
EXPECT_EQ(res2[7], res[7]);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
std::vector<std::string> local_urls = { "./channel_b", "./channel_a" };
|
||||
std::vector<std::string> local_res = calculate_channel_urls(local_urls, false);
|
||||
|
@ -153,4 +152,4 @@ namespace mamba
|
|||
EXPECT_EQ(local_res[2], current_dir + "channel_a/" + platform);
|
||||
EXPECT_EQ(local_res[3], current_dir + "channel_a/noarch");
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "match_spec.hpp"
|
||||
#include "context.hpp"
|
||||
#include "link.hpp"
|
||||
#include "history.hpp"
|
||||
#include "fsutil.hpp"
|
||||
#include "history.hpp"
|
||||
#include "link.hpp"
|
||||
#include "match_spec.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -128,9 +128,11 @@ namespace mamba
|
|||
EXPECT_EQ(ms.build_number, "<=3");
|
||||
}
|
||||
{
|
||||
MatchSpec ms("xtensor[url=file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2]");
|
||||
MatchSpec ms("xtensor[url=file:///home/wolfv/Downloads/"
|
||||
"xtensor-0.21.4-hc9558a2_0.tar.bz2]");
|
||||
EXPECT_EQ(ms.name, "xtensor");
|
||||
EXPECT_EQ(ms.brackets["url"], "file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2");
|
||||
EXPECT_EQ(ms.brackets["url"],
|
||||
"file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2");
|
||||
EXPECT_EQ(ms.fn, "file:///home/wolfv/Downloads/xtensor-0.21.4-hc9558a2_0.tar.bz2");
|
||||
}
|
||||
{
|
||||
|
@ -204,7 +206,7 @@ namespace mamba
|
|||
if (on_linux)
|
||||
{
|
||||
auto home = env::expand_user("~");
|
||||
EXPECT_EQ(path::starts_with_home(home / "test" / "file.txt" ), true);
|
||||
EXPECT_EQ(path::starts_with_home(home / "test" / "file.txt"), true);
|
||||
EXPECT_EQ(path::starts_with_home("~"), true);
|
||||
EXPECT_EQ(path::starts_with_home("/opt/bin"), false);
|
||||
}
|
||||
|
@ -243,4 +245,4 @@ namespace mamba
|
|||
EXPECT_THROW(path::is_writable("/tmp/this/path/doesnt/exist"), std::runtime_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -10,7 +10,8 @@ namespace mamba
|
|||
auto prefixes = e.list_all_known_prefixes();
|
||||
e.register_env(env::expand_user("~/some/env"));
|
||||
auto new_prefixes = e.list_all_known_prefixes();
|
||||
// the prefix should be cleaned out, because it doesn't have the `conda-meta/history` file
|
||||
// the prefix should be cleaned out, because it doesn't have the
|
||||
// `conda-meta/history` file
|
||||
EXPECT_EQ(new_prefixes.size(), prefixes.size());
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -48,17 +48,16 @@ namespace mamba
|
|||
class test_visitor : private default_visitor<G>
|
||||
{
|
||||
public:
|
||||
|
||||
using base_type = default_visitor<G>;
|
||||
using node_id = typename base_type::node_id;
|
||||
using predecessor_map = std::map<node_id, node_id>;
|
||||
using edge_map = std::map<node_id, node_id>;
|
||||
|
||||
using base_type::start_node;
|
||||
using base_type::finish_edge;
|
||||
using base_type::finish_node;
|
||||
using base_type::start_edge;
|
||||
using base_type::start_node;
|
||||
using base_type::tree_edge;
|
||||
using base_type::finish_edge;
|
||||
|
||||
void back_edge(node_id from, node_id to, const G&)
|
||||
{
|
||||
|
@ -81,7 +80,6 @@ namespace mamba
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
edge_map m_back_edges;
|
||||
edge_map m_cross_edges;
|
||||
};
|
||||
|
@ -91,11 +89,11 @@ namespace mamba
|
|||
using node_list = graph<int>::node_list;
|
||||
using edge_list = graph<int>::edge_list;
|
||||
auto g = build_graph();
|
||||
EXPECT_EQ(g.get_node_list(), node_list({0u, 1u, 2u, 3u, 4u, 5u, 6u}));
|
||||
EXPECT_EQ(g.get_edge_list(0u), edge_list({1u, 2u}));
|
||||
EXPECT_EQ(g.get_edge_list(1u), edge_list({3u, 4u}));
|
||||
EXPECT_EQ(g.get_edge_list(2u), edge_list({3u, 5u}));
|
||||
EXPECT_EQ(g.get_edge_list(3u), edge_list({6u}));
|
||||
EXPECT_EQ(g.get_node_list(), node_list({ 0u, 1u, 2u, 3u, 4u, 5u, 6u }));
|
||||
EXPECT_EQ(g.get_edge_list(0u), edge_list({ 1u, 2u }));
|
||||
EXPECT_EQ(g.get_edge_list(1u), edge_list({ 3u, 4u }));
|
||||
EXPECT_EQ(g.get_edge_list(2u), edge_list({ 3u, 5u }));
|
||||
EXPECT_EQ(g.get_edge_list(3u), edge_list({ 6u }));
|
||||
}
|
||||
|
||||
TEST(graph, depth_first_search)
|
||||
|
@ -124,4 +122,4 @@ namespace mamba
|
|||
EXPECT_TRUE(vis.get_back_edge_map().empty());
|
||||
EXPECT_TRUE(vis.get_cross_edge_map().empty());
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "util.hpp"
|
||||
#include "shell_init.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -12,7 +12,8 @@ namespace mamba
|
|||
|
||||
TEST(shell_init, bashrc_modifications)
|
||||
{
|
||||
// modify_rc_file("/home/wolfv/Programs/mamba/test/.bashrc", "/home/wolfv/superconda/", "bash");
|
||||
// modify_rc_file("/home/wolfv/Programs/mamba/test/.bashrc",
|
||||
// "/home/wolfv/superconda/", "bash");
|
||||
}
|
||||
|
||||
TEST(shell_init, expand_user)
|
||||
|
@ -23,4 +24,4 @@ namespace mamba
|
|||
EXPECT_TRUE(starts_with(expanded.string(), "/home/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -16,32 +16,32 @@ namespace mamba
|
|||
TEST(util, split)
|
||||
{
|
||||
std::string a = "hello.again.it's.me.mario";
|
||||
std::vector<std::string> e1 = {"hello", "again", "it's", "me", "mario"};
|
||||
std::vector<std::string> e1 = { "hello", "again", "it's", "me", "mario" };
|
||||
EXPECT_EQ(split(a, "."), e1);
|
||||
|
||||
std::vector<std::string> s2 = {"hello", "again", "it's.me.mario"};
|
||||
std::vector<std::string> s2 = { "hello", "again", "it's.me.mario" };
|
||||
EXPECT_EQ(split(a, ".", 2), s2);
|
||||
|
||||
EXPECT_EQ(rsplit(a, "."), e1);
|
||||
std::vector<std::string> r2 = {"hello.again.it's", "me", "mario"};
|
||||
std::vector<std::string> r2 = { "hello.again.it's", "me", "mario" };
|
||||
EXPECT_EQ(rsplit(a, ".", 2), r2);
|
||||
|
||||
std::string b = "...";
|
||||
auto es1 = std::vector<std::string>{"", "", "", ""};
|
||||
auto es2 = std::vector<std::string>{"", ".."};
|
||||
auto es1 = std::vector<std::string>{ "", "", "", "" };
|
||||
auto es2 = std::vector<std::string>{ "", ".." };
|
||||
EXPECT_EQ(split(b, "."), es1);
|
||||
EXPECT_EQ(split(b, ".", 1), es2);
|
||||
|
||||
std::vector<std::string> v = {"xtensor==0.12.3"};
|
||||
std::vector<std::string> v = { "xtensor==0.12.3" };
|
||||
EXPECT_EQ(split(v[0], ":"), v);
|
||||
EXPECT_EQ(rsplit(v[0], ":"), v);
|
||||
EXPECT_EQ(split(v[0], ":", 2), v);
|
||||
EXPECT_EQ(rsplit(v[0], ":", 2), v);
|
||||
|
||||
std::vector<std::string> v2 = {"conda-forge/linux64", "", "xtensor==0.12.3"};
|
||||
std::vector<std::string> v2 = { "conda-forge/linux64", "", "xtensor==0.12.3" };
|
||||
EXPECT_EQ(split("conda-forge/linux64::xtensor==0.12.3", ":", 2), v2);
|
||||
EXPECT_EQ(rsplit("conda-forge/linux64::xtensor==0.12.3", ":", 2), v2);
|
||||
std::vector<std::string> v21 = {"conda-forge/linux64:", "xtensor==0.12.3"};
|
||||
std::vector<std::string> v21 = { "conda-forge/linux64:", "xtensor==0.12.3" };
|
||||
|
||||
EXPECT_EQ(rsplit("conda-forge/linux64::xtensor==0.12.3", ":", 1), v21);
|
||||
}
|
||||
|
@ -62,7 +62,8 @@ namespace mamba
|
|||
EXPECT_TRUE(starts_with(prefix, "/Yes/Thats/great/\n"));
|
||||
|
||||
std::string prefix_unicode = "/I/am/Dörte朩æ©fðgb®/PREFIX\n\nabcdefg\nxyz";
|
||||
replace_all(prefix_unicode, "/I/am/Dörte朩æ©fðgb®/PREFIX", "/home/åéäáßðæœ©ðfßfáðß/123123123");
|
||||
replace_all(
|
||||
prefix_unicode, "/I/am/Dörte朩æ©fðgb®/PREFIX", "/home/åéäáßðæœ©ðfßfáðß/123123123");
|
||||
EXPECT_EQ(prefix_unicode, "/home/åéäáßðæœ©ðfßfáðß/123123123\n\nabcdefg\nxyz");
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace mamba
|
|||
{
|
||||
TEST(thread_utils, interrupt)
|
||||
{
|
||||
#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
|
||||
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
int res = 0;
|
||||
// Ensures the compiler doe snot optimize away Context::instance()
|
||||
std::string current_command = Context::instance().current_command;
|
||||
|
@ -16,27 +16,25 @@ namespace mamba
|
|||
|
||||
Console::instance().init_multi_progress();
|
||||
{
|
||||
interruption_guard g([&res]()
|
||||
{
|
||||
// Test for double free (segfault if that happends)
|
||||
Console::instance().init_multi_progress();
|
||||
res = -1;
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
{
|
||||
thread t([&res]()
|
||||
{
|
||||
++res;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||||
interruption_guard g([&res]() {
|
||||
// Test for double free (segfault if that happends)
|
||||
Console::instance().init_multi_progress();
|
||||
res = -1;
|
||||
});
|
||||
t.detach();
|
||||
}
|
||||
|
||||
pthread_kill(get_cleaning_thread_id(), SIGINT);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
{
|
||||
thread t([&res]() {
|
||||
++res;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||||
});
|
||||
t.detach();
|
||||
}
|
||||
|
||||
pthread_kill(get_cleaning_thread_id(), SIGINT);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
EXPECT_EQ(res, -1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "util.hpp"
|
||||
#include "subdirdata.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
TEST(transfer, file_not_exist)
|
||||
{
|
||||
#ifdef __linux__
|
||||
#ifdef __linux__
|
||||
Context::instance().quiet = true;
|
||||
{
|
||||
mamba::MultiDownloadTarget multi_dl;
|
||||
mamba::MSubdirData cf("conda-forge/linux-64",
|
||||
"file:///nonexistent/repodata.json",
|
||||
"/tmp/zyx.json");
|
||||
mamba::MSubdirData cf(
|
||||
"conda-forge/linux-64", "file:///nonexistent/repodata.json", "/tmp/zyx.json");
|
||||
cf.load();
|
||||
multi_dl.add(cf.target());
|
||||
|
||||
|
@ -27,14 +26,13 @@ namespace mamba
|
|||
}
|
||||
{
|
||||
mamba::MultiDownloadTarget multi_dl;
|
||||
mamba::MSubdirData cf("conda-forge/noarch",
|
||||
"file:///nonexistent/repodata.json",
|
||||
"/tmp/zyx.json");
|
||||
mamba::MSubdirData cf(
|
||||
"conda-forge/noarch", "file:///nonexistent/repodata.json", "/tmp/zyx.json");
|
||||
cf.load();
|
||||
multi_dl.add(cf.target());
|
||||
EXPECT_THROW(multi_dl.download(true), std::runtime_error);
|
||||
}
|
||||
Context::instance().quiet = false;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "url.hpp"
|
||||
|
||||
#include "thirdparty/filesystem.hpp"
|
||||
#include "url.hpp"
|
||||
namespace fs = ghc::filesystem;
|
||||
|
||||
namespace mamba
|
||||
|
@ -31,29 +30,29 @@ namespace mamba
|
|||
EXPECT_EQ(m.query(), "query=123&xyz=3333");
|
||||
}
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
URLHandler m("file://C:/Users/wolfv/test/document.json");
|
||||
EXPECT_EQ(m.scheme(), "file");
|
||||
EXPECT_EQ(m.path(), "C:/Users/wolfv/test/document.json");
|
||||
#else
|
||||
#else
|
||||
URLHandler m("file:///home/wolfv/test/document.json");
|
||||
EXPECT_EQ(m.scheme(), "file");
|
||||
EXPECT_EQ(m.path(), "/home/wolfv/test/document.json");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
TEST(url, path_to_url)
|
||||
{
|
||||
auto url = path_to_url("/users/test/miniconda3");
|
||||
#ifndef _WIN32
|
||||
EXPECT_EQ(url, "file:///users/test/miniconda3");
|
||||
#else
|
||||
std::string driveletter = fs::absolute(fs::path("/")).string().substr(0, 1);
|
||||
EXPECT_EQ(url, std::string("file://") + driveletter + ":/users/test/miniconda3");
|
||||
auto url2 = path_to_url("D:\\users\\test\\miniconda3");
|
||||
EXPECT_EQ(url2, "file://D:/users/test/miniconda3");
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
EXPECT_EQ(url, "file:///users/test/miniconda3");
|
||||
#else
|
||||
std::string driveletter = fs::absolute(fs::path("/")).string().substr(0, 1);
|
||||
EXPECT_EQ(url, std::string("file://") + driveletter + ":/users/test/miniconda3");
|
||||
auto url2 = path_to_url("D:\\users\\test\\miniconda3");
|
||||
EXPECT_EQ(url2, "file://D:/users/test/miniconda3");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(url, has_scheme)
|
||||
|
@ -113,7 +112,6 @@ namespace mamba
|
|||
|
||||
TEST(url, split_ananconda_token)
|
||||
{
|
||||
|
||||
std::string input, cleaned_url, token;
|
||||
{
|
||||
input = "https://1.2.3.4/t/tk-123-456/path";
|
||||
|
@ -168,25 +166,27 @@ namespace mamba
|
|||
EXPECT_EQ(auth, "u:p");
|
||||
EXPECT_EQ(token, "x1029384756");
|
||||
|
||||
#ifdef _WIN32
|
||||
split_scheme_auth_token("file://C:/Users/wolfv/test.json", remaining_url, scheme, auth, token);
|
||||
#ifdef _WIN32
|
||||
split_scheme_auth_token(
|
||||
"file://C:/Users/wolfv/test.json", remaining_url, scheme, auth, token);
|
||||
EXPECT_EQ(remaining_url, "C:/Users/wolfv/test.json");
|
||||
EXPECT_EQ(scheme, "file");
|
||||
EXPECT_EQ(auth, "");
|
||||
EXPECT_EQ(token, "");
|
||||
#else
|
||||
#else
|
||||
split_scheme_auth_token("file:///home/wolfv/test.json", remaining_url, scheme, auth, token);
|
||||
EXPECT_EQ(remaining_url, "/home/wolfv/test.json");
|
||||
EXPECT_EQ(scheme, "file");
|
||||
EXPECT_EQ(auth, "");
|
||||
EXPECT_EQ(token, "");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(url, split_platform)
|
||||
{
|
||||
std::string input = "https://1.2.3.4/t/tk-123/linux-64/path";
|
||||
std::vector<std::string> known_platforms = {"noarch", "linux-32", "linux-64", "linux-aarch64"};
|
||||
std::vector<std::string> known_platforms
|
||||
= { "noarch", "linux-32", "linux-64", "linux-aarch64" };
|
||||
std::string cleaned_url, platform;
|
||||
split_platform(known_platforms, input, cleaned_url, platform);
|
||||
EXPECT_EQ(cleaned_url, "https://1.2.3.4/t/tk-123/path");
|
||||
|
@ -201,4 +201,4 @@ namespace mamba
|
|||
EXPECT_TRUE(is_path("/"));
|
||||
EXPECT_FALSE(is_path("file://makefile"));
|
||||
}
|
||||
}
|
||||
} // namespace mamba
|
||||
|
|
Loading…
Reference in New Issue