mirror of https://github.com/mamba-org/mamba.git
Clean util_string (#2339)
clean up the util_string header and add util_string.cpp
This commit is contained in:
parent
6ee8a83a8a
commit
2811c25d75
|
@ -137,6 +137,7 @@ set(LIBMAMBA_SOURCES
|
|||
${LIBMAMBA_SOURCE_DIR}/core/transaction_context.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/link.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/history.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/mamba_fs.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/match_spec.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/menuinst.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/url.cpp
|
||||
|
@ -160,6 +161,8 @@ set(LIBMAMBA_SOURCES
|
|||
${LIBMAMBA_SOURCE_DIR}/core/thread_utils.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/transaction.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/util.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/fsutil.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/util_string.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/util_os.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/validate.cpp
|
||||
${LIBMAMBA_SOURCE_DIR}/core/virtual_packages.cpp
|
||||
|
@ -197,7 +200,6 @@ set(LIBMAMBA_PUBLIC_HEADERS
|
|||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/environments_manager.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/error_handling.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/fetch.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/fsutil.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/satisfiability_error.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/history.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/link.hpp
|
||||
|
@ -224,6 +226,7 @@ set(LIBMAMBA_PUBLIC_HEADERS
|
|||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/transaction_context.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/url.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/fsutil.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util_graph.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util_os.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util_random.hpp
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "mamba/core/mamba_fs.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
|
||||
namespace mamba
|
||||
|
@ -29,7 +29,7 @@ namespace mamba
|
|||
/ / / / / / /_/ / / / / / / /_/ / /_/ /
|
||||
/_/ /_/ /_/\__,_/_/ /_/ /_/_.___/\__,_/
|
||||
)MAMBARAW",
|
||||
"\n"
|
||||
'\n'
|
||||
));
|
||||
|
||||
namespace detail
|
||||
|
|
|
@ -115,13 +115,6 @@ namespace mamba
|
|||
|
||||
/// Returns `true` if the filename matches names of files which should be interpreted as conda
|
||||
/// environment lockfile. NOTE: this does not check if the file exists.
|
||||
inline bool is_env_lockfile_name(const std::string_view filename)
|
||||
{
|
||||
return ends_with(filename, "-lock.yml") || ends_with(filename, "-lock.yaml");
|
||||
}
|
||||
|
||||
|
||||
bool is_env_lockfile_name(std::string_view filename);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "mamba_fs.hpp"
|
||||
|
||||
|
|
|
@ -7,171 +7,43 @@
|
|||
#ifndef MAMBA_CORE_FS_UTIL
|
||||
#define MAMBA_CORE_FS_UTIL
|
||||
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
#include "mamba/core/environment.hpp"
|
||||
#include "mamba/core/mamba_fs.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_scope.hpp"
|
||||
namespace fs
|
||||
{
|
||||
class u8path;
|
||||
}
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
namespace path
|
||||
{
|
||||
inline bool starts_with_home(const fs::u8path& p)
|
||||
{
|
||||
std::string path = p.string();
|
||||
return path[0] == '~'
|
||||
|| starts_with(env::expand_user(path).string(), env::expand_user("~").string());
|
||||
}
|
||||
bool starts_with_home(const fs::u8path& p);
|
||||
|
||||
// TODO more error handling
|
||||
inline void create_directories_sudo_safe(const fs::u8path& path)
|
||||
{
|
||||
if (fs::is_directory(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
void create_directories_sudo_safe(const fs::u8path& path);
|
||||
bool touch(const fs::u8path& path, bool mkdir = false, bool sudo_safe = false);
|
||||
|
||||
fs::u8path 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
|
||||
}
|
||||
|
||||
inline bool touch(fs::u8path 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::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 outfile{ path.std_path(), std::ios::out };
|
||||
|
||||
if (!outfile.good())
|
||||
{
|
||||
LOG_INFO << "Could not touch file at " << path;
|
||||
}
|
||||
|
||||
if (outfile.fail())
|
||||
{
|
||||
throw fs::filesystem_error(
|
||||
"File creation failed",
|
||||
std::make_error_code(std::errc::permission_denied)
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns `true` only if the provided path is either:
|
||||
// - a file we are able to open for writing;
|
||||
// - a directory we are able to create a file in for writing;
|
||||
// - a file name that does not exist but the parent directory in the path exists and we
|
||||
// are able to create a file with that name in that directory for writing.
|
||||
// Returns `false` otherwise.
|
||||
inline bool is_writable(const fs::u8path& path) noexcept
|
||||
{
|
||||
const auto& path_to_write_in = fs::exists(path) ? path : path.parent_path();
|
||||
|
||||
static constexpr auto writable_flags = fs::perms::owner_write | fs::perms::group_write
|
||||
| fs::perms::others_write;
|
||||
std::error_code ec;
|
||||
const auto status = fs::status(path_to_write_in, ec);
|
||||
|
||||
const bool should_be_writable = !ec && status.type() != fs::file_type::not_found
|
||||
&& (status.permissions() & writable_flags)
|
||||
!= fs::perms::none;
|
||||
|
||||
// If it should not be writable, stop there.
|
||||
if (!should_be_writable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it should be, check that it's true by creating or editing a file.
|
||||
const bool is_directory = fs::exists(path)
|
||||
&& fs::is_directory(path, ec); // fs::is_directory
|
||||
// fails if
|
||||
// path does
|
||||
// not exist
|
||||
if (ec)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& test_file_path = is_directory ? path / ".mamba-is-writable-check-delete-me"
|
||||
: path;
|
||||
const auto _ = on_scope_exit(
|
||||
[&]
|
||||
{
|
||||
if (is_directory)
|
||||
{
|
||||
std::error_code ec;
|
||||
fs::remove(test_file_path, ec);
|
||||
}
|
||||
}
|
||||
);
|
||||
std::ofstream test_file{ test_file_path.std_path(),
|
||||
std::ios_base::out | std::ios_base::app };
|
||||
return test_file.is_open();
|
||||
}
|
||||
|
||||
} // namespace path
|
||||
/**
|
||||
* Returns `true` only if the provided path is either:
|
||||
* - a file we are able to open for writing;
|
||||
* - a directory we are able to create a file in for writing;
|
||||
* - a file name that does not exist but the parent directory in the path exists and we
|
||||
* are able to create a file with that name in that directory for writing.
|
||||
* Returns `false` otherwise.
|
||||
*/
|
||||
bool is_writable(const fs::u8path& path) noexcept;
|
||||
}
|
||||
|
||||
namespace mamba_fs
|
||||
{
|
||||
// Like std::rename, but works across file systems by moving the file instead
|
||||
// if the rename fails.
|
||||
// if both rename and move fail, the error code is set to the error code of the
|
||||
// copy_file operation and the `to` file is removed. You will have to handle removal
|
||||
// of the `from` file yourself.
|
||||
inline void rename_or_move(const fs::u8path& from, const fs::u8path& to, std::error_code& ec)
|
||||
{
|
||||
fs::rename(from, to, ec);
|
||||
if (ec)
|
||||
{
|
||||
ec.clear();
|
||||
fs::copy_file(from, to, ec);
|
||||
if (ec)
|
||||
{
|
||||
std::error_code ec2;
|
||||
fs::remove(to, ec2);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace fs
|
||||
} // namespace mamba
|
||||
/** Like std::rename, but works across file systems by moving the file instead
|
||||
* if the rename fails.
|
||||
* if both rename and move fail, the error code is set to the error code of the
|
||||
* copy_file operation and the `to` file is removed. You will have to handle removal
|
||||
* of the `from` file yourself.
|
||||
*/
|
||||
void rename_or_move(const fs::u8path& from, const fs::u8path& to, std::error_code& ec);
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// 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.
|
||||
|
||||
#ifndef MAMBA_CORE_FS_HPP
|
||||
#define MAMBA_CORE_FS_HPP
|
||||
|
||||
|
@ -7,8 +13,6 @@
|
|||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -82,45 +86,14 @@ namespace fs
|
|||
{
|
||||
};
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Maintain `\` on Windows, `/` on other platforms
|
||||
inline std::filesystem::path normalized_separators(std::filesystem::path path)
|
||||
{
|
||||
auto native_string = path.native();
|
||||
static constexpr auto platform_separator = L"\\";
|
||||
static constexpr auto other_separator = L"/";
|
||||
mamba::replace_all(native_string, other_separator, platform_separator);
|
||||
path = std::move(native_string);
|
||||
return path;
|
||||
}
|
||||
#else
|
||||
// noop on non-Windows platforms
|
||||
inline std::filesystem::path normalized_separators(std::filesystem::path path)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
#endif
|
||||
std::filesystem::path normalized_separators(std::filesystem::path path);
|
||||
|
||||
// Returns an utf-8 string given a standard path.
|
||||
inline std::string to_utf8(const std::filesystem::path& path)
|
||||
{
|
||||
#if __cplusplus == 201703L
|
||||
return normalized_separators(path).u8string();
|
||||
#else
|
||||
#error This function implementation is specific to C++17, using another version requires a different implementation here.
|
||||
#endif
|
||||
}
|
||||
std::string to_utf8(const std::filesystem::path& path);
|
||||
|
||||
// Returns standard path given an utf-8 string.
|
||||
inline std::filesystem::path from_utf8(std::string_view u8string)
|
||||
{
|
||||
#if __cplusplus == 201703L
|
||||
return normalized_separators(std::filesystem::u8path(u8string));
|
||||
#else
|
||||
#error This function implementation is specific to C++17, using another version requires a different implementation here.
|
||||
#endif
|
||||
}
|
||||
std::filesystem::path from_utf8(std::string_view u8string);
|
||||
|
||||
// Same as std::filesystem::path except we only accept and output UTF-8 paths
|
||||
class u8path
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "fsutil.hpp"
|
||||
#include "mamba_fs.hpp"
|
||||
#include "package_info.hpp"
|
||||
|
||||
#define PACKAGE_CACHE_MAGIC_FILE "urls.txt"
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#define MAMBA_CORE_SHELL_INIT
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "mamba_fs.hpp"
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include "mamba/core/error_handling.hpp"
|
||||
#include "mamba/core/mamba_fs.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "tl/expected.hpp"
|
||||
|
@ -328,10 +327,7 @@ namespace mamba
|
|||
|
||||
/// Returns `true` if the filename matches names of files which should be interpreted as YAML.
|
||||
/// NOTE: this does not check if the file exists.
|
||||
inline bool is_yaml_file_name(const std::string_view filename)
|
||||
{
|
||||
return ends_with(filename, ".yml") || ends_with(filename, ".yaml");
|
||||
}
|
||||
bool is_yaml_file_name(std::string_view filename);
|
||||
|
||||
std::optional<std::string> proxy_match(const std::string& url);
|
||||
|
||||
|
|
|
@ -21,108 +21,247 @@
|
|||
|
||||
namespace mamba
|
||||
{
|
||||
inline const char* check_char(const char* ptr)
|
||||
{
|
||||
return ptr ? ptr : "";
|
||||
}
|
||||
/**
|
||||
* Return the string if the pointer is not null, otherwise a pointer to an empty string.
|
||||
*/
|
||||
const char* raw_str_or_empty(const char* ptr);
|
||||
|
||||
constexpr const char* WHITESPACES(" \r\n\t\f\v");
|
||||
constexpr const wchar_t* WHITESPACES_WSTR(L" \r\n\t\f\v");
|
||||
char to_lower(char c);
|
||||
wchar_t to_lower(wchar_t c);
|
||||
std::string to_lower(std::string_view str);
|
||||
std::wstring to_lower(std::wstring_view str);
|
||||
// The use of a template here serves to exclude the overload for const Char*
|
||||
template <typename Char>
|
||||
std::basic_string<Char> to_lower(std::basic_string<Char>&& str);
|
||||
extern template std::string to_lower(std::string&& str);
|
||||
extern template std::wstring to_lower(std::wstring&& str);
|
||||
|
||||
bool starts_with(const std::string_view& str, const std::string_view& prefix);
|
||||
bool ends_with(const std::string_view& str, const std::string_view& suffix);
|
||||
bool contains(const std::string_view& str, const std::string_view& sub_str);
|
||||
char to_upper(char c);
|
||||
wchar_t to_upper(wchar_t c);
|
||||
std::string to_upper(std::string_view str);
|
||||
std::wstring to_upper(std::wstring_view str);
|
||||
// The use of a template here serves to exclude the overload for const Char*
|
||||
template <typename Char>
|
||||
std::basic_string<Char> to_upper(std::basic_string<Char>&& str);
|
||||
extern template std::string to_upper(std::string&& str);
|
||||
extern template std::wstring to_upper(std::wstring&& str);
|
||||
|
||||
// TODO: add concepts here, or at least some contraints
|
||||
template <typename T, typename AssociativeContainer>
|
||||
auto contains(const AssociativeContainer& values, const T& value_to_find)
|
||||
-> decltype(values.find(value_to_find) != values.end()) // this should make invalid usage
|
||||
// SFINAE
|
||||
{
|
||||
return values.find(value_to_find) != values.end();
|
||||
}
|
||||
bool starts_with(std::string_view str, std::string_view prefix);
|
||||
|
||||
bool any_starts_with(const std::vector<std::string_view>& str, const std::string_view& prefix);
|
||||
bool ends_with(std::string_view str, std::string_view suffix);
|
||||
|
||||
bool starts_with_any(const std::string_view& str, const std::vector<std::string_view>& prefix);
|
||||
bool contains(std::string_view str, std::string_view sub_str);
|
||||
|
||||
template <class CharType>
|
||||
std::basic_string_view<CharType>
|
||||
strip(const std::basic_string_view<CharType>& input, const std::basic_string_view<CharType>& chars)
|
||||
{
|
||||
size_t start = input.find_first_not_of(chars);
|
||||
if (start == std::basic_string<CharType>::npos)
|
||||
{
|
||||
return std::basic_string_view<CharType>();
|
||||
}
|
||||
size_t stop = input.find_last_not_of(chars) + 1;
|
||||
size_t length = stop - start;
|
||||
return length == 0 ? std::basic_string_view<CharType>() : input.substr(start, length);
|
||||
}
|
||||
/**
|
||||
* Check if any of the strings starts with the prefix.
|
||||
*/
|
||||
template <typename StrRange>
|
||||
bool any_starts_with(const StrRange& strs, std::string_view prefix);
|
||||
template <typename StrRange>
|
||||
bool any_starts_with(const StrRange& strs, std::wstring_view prefix);
|
||||
|
||||
std::string_view strip(const std::string_view& input);
|
||||
std::wstring_view strip(const std::wstring_view& input);
|
||||
std::string_view lstrip(const std::string_view& input);
|
||||
std::string_view rstrip(const std::string_view& input);
|
||||
/**
|
||||
* Check if the string starts with any of the prefix.
|
||||
*/
|
||||
template <typename StrRange>
|
||||
bool starts_with_any(std::string_view str, const StrRange& prefix);
|
||||
template <typename StrRange>
|
||||
bool starts_with_any(std::wstring_view str, const StrRange& prefix);
|
||||
|
||||
std::string_view strip(const std::string_view& input, const std::string_view& chars);
|
||||
std::string_view lstrip(const std::string_view& input, const std::string_view& chars);
|
||||
std::string_view rstrip(const std::string_view& input, const std::string_view& chars);
|
||||
std::string_view lstrip(std::string_view input, char c);
|
||||
std::wstring_view lstrip(std::wstring_view input, wchar_t c);
|
||||
std::string_view lstrip(std::string_view input, std::string_view chars);
|
||||
std::wstring_view lstrip(std::wstring_view input, std::wstring_view chars);
|
||||
std::string_view lstrip(std::string_view input);
|
||||
std::wstring_view lstrip(std::wstring_view input);
|
||||
|
||||
// FIXME: doesnt support const char* mixed with other string types as input.
|
||||
template <class CharType>
|
||||
std::vector<std::basic_string<CharType>> split(
|
||||
const std::basic_string_view<CharType> input,
|
||||
const std::basic_string_view<CharType> sep,
|
||||
std::size_t max_split = SIZE_MAX
|
||||
)
|
||||
{
|
||||
std::vector<std::basic_string<CharType>> result;
|
||||
std::size_t i = 0, j = 0, len = input.size(), n = sep.size();
|
||||
std::string_view rstrip(std::string_view input, char c);
|
||||
std::wstring_view rstrip(std::wstring_view input, wchar_t c);
|
||||
std::string_view rstrip(std::string_view input, std::string_view chars);
|
||||
std::wstring_view rstrip(std::wstring_view input, std::wstring_view chars);
|
||||
std::string_view rstrip(std::string_view input);
|
||||
std::wstring_view rstrip(std::wstring_view input);
|
||||
|
||||
while (i + n <= len)
|
||||
{
|
||||
if (input[i] == sep[0] && input.substr(i, n) == sep)
|
||||
{
|
||||
if (max_split-- <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
result.emplace_back(input.substr(j, i - j));
|
||||
i = j = i + n;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
result.emplace_back(input.substr(j, len - j));
|
||||
return result;
|
||||
}
|
||||
|
||||
// unfortunately, c++ doesn't support templating function s. t. strip(std::string, std::string)
|
||||
// works, so this is a workaround that fixes it
|
||||
// FIXME: this overload should not be necessary, but the generic version doesn't
|
||||
// work with const char* and mixed with other types for some reason.
|
||||
inline std::vector<std::string>
|
||||
split(const std::string_view& input, const std::string_view& sep, std::size_t max_split = SIZE_MAX)
|
||||
{
|
||||
return split<char>(input, sep, max_split);
|
||||
}
|
||||
std::string_view strip(std::string_view input, char c);
|
||||
std::wstring_view strip(std::wstring_view input, wchar_t c);
|
||||
std::string_view strip(std::string_view input, std::string_view chars);
|
||||
std::wstring_view strip(std::wstring_view input, std::wstring_view chars);
|
||||
std::string_view strip(std::string_view input);
|
||||
std::wstring_view strip(std::wstring_view input);
|
||||
|
||||
std::vector<std::string>
|
||||
rsplit(const std::string_view& input, const std::string_view& sep, std::size_t max_split = SIZE_MAX);
|
||||
split(std::string_view input, std::string_view sep, std::size_t max_split = SIZE_MAX);
|
||||
std::vector<std::wstring>
|
||||
split(std::wstring_view input, std::wstring_view sep, std::size_t max_split = SIZE_MAX);
|
||||
|
||||
namespace details
|
||||
std::vector<std::string>
|
||||
rsplit(std::string_view input, std::string_view sep, std::size_t max_split = SIZE_MAX);
|
||||
std::vector<std::wstring>
|
||||
rsplit(std::wstring_view input, std::wstring_view sep, std::size_t max_split = SIZE_MAX);
|
||||
|
||||
void replace_all(std::string& data, std::string_view search, std::string_view replace);
|
||||
void replace_all(std::wstring& data, std::wstring_view search, std::wstring_view replace);
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct PlusEqual
|
||||
{
|
||||
template <typename T, typename U>
|
||||
auto operator()(T& left, const U& right)
|
||||
{
|
||||
left += right;
|
||||
}
|
||||
auto operator()(T& left, const U& right);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the function @p func on each element of a join iteration.
|
||||
*
|
||||
* The join iteration of an iterator pair (@p first, @p last) with a separator @p sep is
|
||||
* defined by iterating through the ``n`` elements of the iterator pair, interleaving the
|
||||
* separator in between the elements (thus appearing ``n-1`` times).
|
||||
*/
|
||||
template <typename InputIt, typename UnaryFunction, typename Value>
|
||||
UnaryFunction join_for_each(InputIt first, InputIt last, UnaryFunction func, const Value& sep);
|
||||
|
||||
/**
|
||||
* Concatenate the elements of the container @p container by interleaving a separator.
|
||||
*
|
||||
* Joining is done by successively joining (using the provided @p joiner) the aggregate with
|
||||
* element of the container and the separator, such that the separator only appears
|
||||
* in-between two elements of the range.
|
||||
*
|
||||
* @see join_for_each
|
||||
*/
|
||||
template <class Range, class Value, class Joiner = detail::PlusEqual>
|
||||
auto join(const Value& sep, const Range& container, Joiner joiner = detail::PlusEqual{}) ->
|
||||
typename Range::value_type;
|
||||
|
||||
/**
|
||||
* Execute the function @p func on each element of a tuncated join iteration.
|
||||
*
|
||||
* The join iteration of an iterator pair (@p first, @p last) with a separator @p sep
|
||||
* and a trunction symbol @p etc is define by the join iteration of either all the elements
|
||||
* in the iterator pair if they are less than @p threshold, a limited number of elements, with
|
||||
* middle elements represented by @p etc.
|
||||
* defined by iterating through the ``n`` elements of the iterator pair, interleaving the
|
||||
* separator in between the elements (thus appearing ``n-1`` times).
|
||||
*
|
||||
* @param first The iterator pointing to the begining of the range of elements to join.
|
||||
* @param last The iterator pointing to past the end of the range of elements to join.
|
||||
* @param func The unary function to apply to all elements (separation and truncation included).
|
||||
* @param sep The separator used in between elements.
|
||||
* @param etc The value used to represent the truncation of the elements.
|
||||
* @param threshold Distance between the iterator pair beyond which truncation is preformed.
|
||||
* @param show Number of elements to keep at the begining/end when truncation is preformed.
|
||||
*
|
||||
* @see join_for_each
|
||||
*/
|
||||
template <typename InputIt, typename UnaryFunction, typename Value>
|
||||
UnaryFunction join_trunc_for_each(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
UnaryFunction func,
|
||||
const Value& sep,
|
||||
const Value& etc,
|
||||
std::size_t threshold = 5,
|
||||
std::pair<std::size_t, std::size_t> show = { 2, 1 }
|
||||
);
|
||||
|
||||
/**
|
||||
* Join elements of a range, with possible truncation.
|
||||
*
|
||||
* @param range Elements to join.
|
||||
* @param sep The separator used in between elements.
|
||||
* @param etc The value used to represent the truncation of the elements.
|
||||
* @param threshold Distance between the iterator pair beyond which truncation is preformed.
|
||||
* @param show Number of elements to keep at the begining/end when truncation is preformed.
|
||||
*
|
||||
* @see join_trunc_for_each
|
||||
* @see join
|
||||
*/
|
||||
template <typename Range, typename Joiner = detail::PlusEqual>
|
||||
auto join_trunc(
|
||||
const Range& range,
|
||||
std::string_view sep = ", ",
|
||||
std::string_view etc = "...",
|
||||
std::size_t threshold = 5,
|
||||
std::pair<std::size_t, std::size_t> show = { 2, 1 },
|
||||
Joiner joiner = detail::PlusEqual{}
|
||||
) -> typename Range::value_type;
|
||||
;
|
||||
|
||||
/************************
|
||||
* Implementation misc *
|
||||
************************/
|
||||
|
||||
inline const char* raw_str_or_empty(const char* ptr)
|
||||
{
|
||||
return ptr ? ptr : "";
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Implementation of start_with functions *
|
||||
********************************************/
|
||||
|
||||
template <typename StrRange, typename Char>
|
||||
bool any_starts_with(const StrRange& strs, std::basic_string_view<Char> prefix)
|
||||
{
|
||||
return std::any_of(
|
||||
strs.cbegin(),
|
||||
strs.cend(),
|
||||
[&prefix](const auto& s) { return starts_with(s, prefix); }
|
||||
);
|
||||
}
|
||||
|
||||
template <typename StrRange>
|
||||
bool any_starts_with(const StrRange& strs, std::string_view prefix)
|
||||
{
|
||||
return any_starts_with<StrRange, decltype(prefix)::value_type>(strs, prefix);
|
||||
}
|
||||
|
||||
template <typename StrRange>
|
||||
bool any_starts_with(const StrRange& strs, std::wstring_view prefix)
|
||||
{
|
||||
return any_starts_with<StrRange, decltype(prefix)::value_type>(strs, prefix);
|
||||
}
|
||||
|
||||
extern template bool any_starts_with(const std::vector<std::string>&, std::string_view);
|
||||
extern template bool any_starts_with(const std::vector<std::string_view>&, std::string_view);
|
||||
|
||||
template <typename StrRange, typename Char>
|
||||
bool starts_with_any(std::basic_string_view<Char> str, const StrRange& prefix)
|
||||
{
|
||||
return std::any_of(
|
||||
prefix.cbegin(),
|
||||
prefix.cend(),
|
||||
[&str](const auto& p) { return starts_with(str, p); }
|
||||
);
|
||||
}
|
||||
|
||||
template <typename StrRange>
|
||||
bool starts_with_any(std::string_view str, const StrRange& prefix)
|
||||
{
|
||||
return starts_with_any<StrRange, char>(str, prefix);
|
||||
}
|
||||
|
||||
template <typename StrRange>
|
||||
bool starts_with_any(std::wstring_view str, const StrRange& prefix)
|
||||
{
|
||||
return starts_with_any<StrRange, wchar_t>(str, prefix);
|
||||
}
|
||||
|
||||
extern template bool starts_with_any(std::string_view, const std::vector<std::string>&);
|
||||
extern template bool starts_with_any(std::string_view, const std::vector<std::string_view>&);
|
||||
|
||||
/**************************************
|
||||
* Implementation of join functions *
|
||||
**************************************/
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T, typename U>
|
||||
auto PlusEqual::operator()(T& left, const U& right)
|
||||
{
|
||||
left += right;
|
||||
}
|
||||
|
||||
template <class T, class = void>
|
||||
struct has_reserve : std::false_type
|
||||
|
@ -147,13 +286,6 @@ namespace mamba
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the function @p func on each element of a join iteration.
|
||||
*
|
||||
* The join iteration of an iterator pair (@p first, @p last) with a separator @p sep is
|
||||
* defined by iterating through the ``n`` elements of the iterator pair, interleaving the
|
||||
* separator in between the elements (thus appearing ``n-1`` times).
|
||||
*/
|
||||
// TODO(C++20) Take an input range and return a range
|
||||
template <typename InputIt, typename UnaryFunction, typename Value>
|
||||
UnaryFunction join_for_each(InputIt first, InputIt last, UnaryFunction func, const Value& sep)
|
||||
|
@ -170,25 +302,15 @@ namespace mamba
|
|||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate the elements of the container @p container by interleaving a separator.
|
||||
*
|
||||
* Joining is done by successively joining (using the provided @p joiner) the aggregate with
|
||||
* element of the container and the separator, such that the separator only appears
|
||||
* in-between two elements of the range.
|
||||
*
|
||||
* @see join_for_each
|
||||
*/
|
||||
template <class Range, class Value, class Joiner = details::PlusEqual>
|
||||
auto join(const Value& sep, const Range& container, Joiner joiner = details::PlusEqual{}) ->
|
||||
typename Range::value_type
|
||||
template <class Range, class Value, class Joiner>
|
||||
auto join(const Value& sep, const Range& container, Joiner joiner) -> typename Range::value_type
|
||||
{
|
||||
using Result = typename Range::value_type;
|
||||
Result out{};
|
||||
if constexpr (details::has_reserve_v<Result>)
|
||||
if constexpr (detail::has_reserve_v<Result>)
|
||||
{
|
||||
std::size_t final_size = 0;
|
||||
auto inc_size = [&final_size](const auto& val) { final_size += details::size(val); };
|
||||
auto inc_size = [&final_size](const auto& val) { final_size += detail::size(val); };
|
||||
join_for_each(container.begin(), container.end(), inc_size, sep);
|
||||
out.reserve(final_size);
|
||||
}
|
||||
|
@ -197,26 +319,10 @@ namespace mamba
|
|||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the function @p func on each element of a tuncated join iteration.
|
||||
*
|
||||
* The join iteration of an iterator pair (@p first, @p last) with a separator @p sep
|
||||
* and a trunction symbol @p etc is define by the join iteration of either all the elements
|
||||
* in the iterator pair if they are less than @p threshold, a limited number of elements, with
|
||||
* middle elements represented by @p etc.
|
||||
* defined by iterating through the ``n`` elements of the iterator pair, interleaving the
|
||||
* separator in between the elements (thus appearing ``n-1`` times).
|
||||
*
|
||||
* @param first The iterator pointing to the begining of the range of elements to join.
|
||||
* @param last The iterator pointing to past the end of the range of elements to join.
|
||||
* @param func The unary function to apply to all elements (separation and truncation included).
|
||||
* @param sep The separator used in between elements.
|
||||
* @param etc The value used to represent the truncation of the elements.
|
||||
* @param threshold Distance between the iterator pair beyond which truncation is preformed.
|
||||
* @param show Number of elements to keep at the begining/end when truncation is preformed.
|
||||
*
|
||||
* @see join_for_each
|
||||
*/
|
||||
/********************************************
|
||||
* Implementation of join_trunc functions *
|
||||
********************************************/
|
||||
|
||||
// TODO(C++20) Take an input range and return a range
|
||||
template <typename InputIt, typename UnaryFunction, typename Value>
|
||||
UnaryFunction join_trunc_for_each(
|
||||
|
@ -225,8 +331,8 @@ namespace mamba
|
|||
UnaryFunction func,
|
||||
const Value& sep,
|
||||
const Value& etc,
|
||||
std::size_t threshold = 5,
|
||||
std::pair<std::size_t, std::size_t> show = { 2, 1 }
|
||||
std::size_t threshold,
|
||||
std::pair<std::size_t, std::size_t> show
|
||||
)
|
||||
{
|
||||
if (util::cmp_less_equal(last - first, threshold))
|
||||
|
@ -262,34 +368,22 @@ namespace mamba
|
|||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join elements of a range, with possible truncation.
|
||||
*
|
||||
* @param range Elements to join.
|
||||
* @param sep The separator used in between elements.
|
||||
* @param etc The value used to represent the truncation of the elements.
|
||||
* @param threshold Distance between the iterator pair beyond which truncation is preformed.
|
||||
* @param show Number of elements to keep at the begining/end when truncation is preformed.
|
||||
*
|
||||
* @see join_trunc_for_each
|
||||
* @see join
|
||||
*/
|
||||
template <typename Range, typename Joiner = details::PlusEqual>
|
||||
template <typename Range, typename Joiner>
|
||||
auto join_trunc(
|
||||
const Range& range,
|
||||
std::string_view sep = ", ",
|
||||
std::string_view etc = "...",
|
||||
std::size_t threshold = 5,
|
||||
std::pair<std::size_t, std::size_t> show = { 2, 1 },
|
||||
Joiner joiner = details::PlusEqual{}
|
||||
std::string_view sep,
|
||||
std::string_view etc,
|
||||
std::size_t threshold,
|
||||
std::pair<std::size_t, std::size_t> show,
|
||||
Joiner joiner
|
||||
) -> typename Range::value_type
|
||||
{
|
||||
using Result = typename Range::value_type;
|
||||
Result out{};
|
||||
if constexpr (details::has_reserve_v<Result>)
|
||||
if constexpr (detail::has_reserve_v<Result>)
|
||||
{
|
||||
std::size_t final_size = 0;
|
||||
auto inc_size = [&final_size](const auto& val) { final_size += details::size(val); };
|
||||
auto inc_size = [&final_size](const auto& val) { final_size += detail::size(val); };
|
||||
join_trunc_for_each(range.begin(), range.end(), inc_size, sep, etc, threshold, show);
|
||||
out.reserve(final_size);
|
||||
}
|
||||
|
@ -299,27 +393,11 @@ namespace mamba
|
|||
return out;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> without_duplicates(std::vector<T> values)
|
||||
{
|
||||
const auto end_it = std::unique(values.begin(), values.end());
|
||||
values.erase(end_it, values.end());
|
||||
return values;
|
||||
}
|
||||
|
||||
// Note: this function only works for non-unicode!
|
||||
std::string to_upper(const std::string_view& input);
|
||||
std::string to_lower(const std::string_view& input);
|
||||
|
||||
template <typename... Args>
|
||||
std::string concat(const Args&... args)
|
||||
{
|
||||
std::string result;
|
||||
result.reserve((details::size(args) + ...));
|
||||
result.reserve((detail::size(args) + ...));
|
||||
((result += args), ...);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// 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 "mamba/api/channel_loader.hpp"
|
||||
|
||||
#include "mamba/core/channel.hpp"
|
||||
|
@ -5,7 +11,7 @@
|
|||
#include "mamba/core/repo.hpp"
|
||||
#include "mamba/core/subdirdata.hpp"
|
||||
#include "mamba/core/thread_utils.hpp"
|
||||
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -140,7 +146,7 @@ namespace mamba
|
|||
auto& subdir = subdirs[i];
|
||||
if (!subdir.loaded())
|
||||
{
|
||||
if (!ctx.offline && mamba::ends_with(subdir.name(), "/noarch"))
|
||||
if (!ctx.offline && ends_with(subdir.name(), "/noarch"))
|
||||
{
|
||||
error_list.push_back(mamba_error(
|
||||
"Subdir " + subdir.name() + " not loaded!",
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/mamba_fs.hpp"
|
||||
#include "mamba/core/package_cache.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "../core/progress_bar_impl.hpp"
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "mamba/core/package_cache.hpp"
|
||||
#include "mamba/core/pinning.hpp"
|
||||
#include "mamba/core/transaction.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/core/virtual_packages.hpp"
|
||||
|
||||
namespace mamba
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "mamba/api/channel_loader.hpp"
|
||||
#include "mamba/api/configuration.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/pinning.hpp"
|
||||
#include "mamba/core/transaction.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/core/virtual_packages.hpp"
|
||||
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
void update(bool update_all, bool prune)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/shell_init.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/package_cache.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/core/validate.hpp"
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h>
|
||||
#include <spdlog/pattern_formatter.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
@ -19,6 +21,7 @@
|
|||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_os.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -314,45 +317,43 @@ namespace mamba
|
|||
|
||||
void Context::debug_print() const
|
||||
{
|
||||
#define PRINT_CTX(xname) << #xname ": " << xname << '\n'
|
||||
#define PRINT_CTX(xout, xname) fmt::print(xout, "{}: {}\n", #xname, xname)
|
||||
|
||||
#define PRINT_CTX_VEC(xname) << #xname ": [" << join(", ", xname) << ']' << '\n'
|
||||
#define PRINT_CTX_VEC(xout, xname) fmt::print(xout, "{}: [{}]\n", #xname, fmt::join(xname, ", "))
|
||||
|
||||
// clang-format off
|
||||
Console::stream() << std::boolalpha
|
||||
<< ">>> MAMBA CONTEXT <<< \n"
|
||||
PRINT_CTX(target_prefix)
|
||||
PRINT_CTX(root_prefix)
|
||||
PRINT_CTX(dry_run)
|
||||
PRINT_CTX(always_yes)
|
||||
PRINT_CTX(allow_softlinks)
|
||||
PRINT_CTX(offline)
|
||||
PRINT_CTX(quiet)
|
||||
PRINT_CTX(no_rc)
|
||||
PRINT_CTX(no_env)
|
||||
PRINT_CTX(ssl_no_revoke)
|
||||
PRINT_CTX(ssl_verify)
|
||||
PRINT_CTX(retry_timeout)
|
||||
PRINT_CTX(retry_backoff)
|
||||
PRINT_CTX(max_retries)
|
||||
PRINT_CTX(connect_timeout_secs)
|
||||
PRINT_CTX(add_pip_as_python_dependency)
|
||||
PRINT_CTX(override_channels_enabled)
|
||||
PRINT_CTX(use_only_tar_bz2)
|
||||
PRINT_CTX(auto_activate_base)
|
||||
PRINT_CTX(extra_safety_checks)
|
||||
PRINT_CTX(download_threads)
|
||||
PRINT_CTX(verbosity)
|
||||
PRINT_CTX(channel_alias)
|
||||
<< "channel_priority: " << (int) channel_priority << '\n'
|
||||
PRINT_CTX_VEC(default_channels)
|
||||
PRINT_CTX_VEC(channels)
|
||||
PRINT_CTX_VEC(pinned_packages)
|
||||
PRINT_CTX(platform)
|
||||
<< ">>> END MAMBA CONTEXT <<< \n"
|
||||
<< std::endl;
|
||||
// clang-format on
|
||||
auto out = Console::stream();
|
||||
out << std::boolalpha << ">>> MAMBA CONTEXT <<< \n";
|
||||
PRINT_CTX(out, target_prefix);
|
||||
PRINT_CTX(out, root_prefix);
|
||||
PRINT_CTX(out, dry_run);
|
||||
PRINT_CTX(out, always_yes);
|
||||
PRINT_CTX(out, allow_softlinks);
|
||||
PRINT_CTX(out, offline);
|
||||
PRINT_CTX(out, quiet);
|
||||
PRINT_CTX(out, no_rc);
|
||||
PRINT_CTX(out, no_env);
|
||||
PRINT_CTX(out, ssl_no_revoke);
|
||||
PRINT_CTX(out, ssl_verify);
|
||||
PRINT_CTX(out, retry_timeout);
|
||||
PRINT_CTX(out, retry_backoff);
|
||||
PRINT_CTX(out, max_retries);
|
||||
PRINT_CTX(out, connect_timeout_secs);
|
||||
PRINT_CTX(out, add_pip_as_python_dependency);
|
||||
PRINT_CTX(out, override_channels_enabled);
|
||||
PRINT_CTX(out, use_only_tar_bz2);
|
||||
PRINT_CTX(out, auto_activate_base);
|
||||
PRINT_CTX(out, extra_safety_checks);
|
||||
PRINT_CTX(out, download_threads);
|
||||
PRINT_CTX(out, verbosity);
|
||||
PRINT_CTX(out, channel_alias);
|
||||
out << "channel_priority: " << (int) channel_priority << '\n';
|
||||
PRINT_CTX_VEC(out, default_channels);
|
||||
PRINT_CTX_VEC(out, channels);
|
||||
PRINT_CTX_VEC(out, pinned_packages);
|
||||
PRINT_CTX(out, platform);
|
||||
out << ">>> END MAMBA CONTEXT <<< \n" << std::endl;
|
||||
#undef PRINT_CTX
|
||||
#undef PRINT_CTX_VEC
|
||||
}
|
||||
|
||||
void Context::dump_backtrace_no_guards()
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
#include <spdlog/spdlog.h>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include "mamba/core/mamba_fs.hpp"
|
||||
#include "mamba/core/match_spec.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -247,4 +249,9 @@ namespace mamba
|
|||
|
||||
return results;
|
||||
}
|
||||
|
||||
bool is_env_lockfile_name(std::string_view filename)
|
||||
{
|
||||
return ends_with(filename, "-lock.yml") || ends_with(filename, "-lock.yaml");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
// 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 "mamba/core/environment.hpp"
|
||||
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "mamba/core/output.hpp"
|
||||
|
@ -86,7 +92,7 @@ namespace mamba
|
|||
if (env_path)
|
||||
{
|
||||
std::string path = env_path.value();
|
||||
const auto parts = mamba::split(path, pathsep());
|
||||
const auto parts = split(path, pathsep());
|
||||
const std::vector<fs::u8path> search_paths(parts.begin(), parts.end());
|
||||
return which(exe, search_paths);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/thread_utils.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/version.hpp"
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
// Copyright (c) 2023, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "mamba/core/fsutil.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
#include "mamba/core/environment.hpp"
|
||||
#include "mamba/core/mamba_fs.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_scope.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba::path
|
||||
{
|
||||
bool starts_with_home(const fs::u8path& p)
|
||||
{
|
||||
std::string path = p.string();
|
||||
return path[0] == '~'
|
||||
|| starts_with(env::expand_user(path).string(), env::expand_user("~").string());
|
||||
}
|
||||
|
||||
// TODO more error handling
|
||||
void create_directories_sudo_safe(const fs::u8path& path)
|
||||
{
|
||||
if (fs::is_directory(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fs::u8path 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
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool touch_impl(fs::u8path path, bool mkdir, bool sudo_safe)
|
||||
{
|
||||
// TODO error handling!
|
||||
path = env::expand_user(path);
|
||||
if (lexists(path))
|
||||
{
|
||||
fs::last_write_time(path, fs::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 outfile{ path.std_path(), std::ios::out };
|
||||
|
||||
if (!outfile.good())
|
||||
{
|
||||
LOG_INFO << "Could not touch file at " << path;
|
||||
}
|
||||
|
||||
if (outfile.fail())
|
||||
{
|
||||
throw fs::filesystem_error(
|
||||
"File creation failed",
|
||||
std::make_error_code(std::errc::permission_denied)
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool touch(const fs::u8path& path, bool mkdir, bool sudo_safe)
|
||||
{
|
||||
return touch_impl(path, mkdir, sudo_safe);
|
||||
}
|
||||
|
||||
bool is_writable(const fs::u8path& path) noexcept
|
||||
{
|
||||
const auto& path_to_write_in = fs::exists(path) ? path : path.parent_path();
|
||||
|
||||
static constexpr auto writable_flags = fs::perms::owner_write | fs::perms::group_write
|
||||
| fs::perms::others_write;
|
||||
std::error_code ec;
|
||||
const auto status = fs::status(path_to_write_in, ec);
|
||||
|
||||
const bool should_be_writable = !ec && status.type() != fs::file_type::not_found
|
||||
&& (status.permissions() & writable_flags) != fs::perms::none;
|
||||
|
||||
// If it should not be writable, stop there.
|
||||
if (!should_be_writable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it should be, check that it's true by creating or editing a file.
|
||||
const bool is_directory = fs::exists(path) && fs::is_directory(path, ec); // fs::is_directory
|
||||
// fails if
|
||||
// path does
|
||||
// not exist
|
||||
if (ec)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& test_file_path = is_directory ? path / ".mamba-is-writable-check-delete-me"
|
||||
: path;
|
||||
const auto _ = on_scope_exit(
|
||||
[&]
|
||||
{
|
||||
if (is_directory)
|
||||
{
|
||||
std::error_code ec;
|
||||
fs::remove(test_file_path, ec);
|
||||
}
|
||||
}
|
||||
);
|
||||
std::ofstream test_file{ test_file_path.std_path(), std::ios_base::out | std::ios_base::app };
|
||||
return test_file.is_open();
|
||||
}
|
||||
} // namespace path
|
||||
|
||||
namespace mamba::mamba_fs
|
||||
{
|
||||
void rename_or_move(const fs::u8path& from, const fs::u8path& to, std::error_code& ec)
|
||||
{
|
||||
fs::rename(from, to, ec);
|
||||
if (ec)
|
||||
{
|
||||
ec.clear();
|
||||
fs::copy_file(from, to, ec);
|
||||
if (ec)
|
||||
{
|
||||
std::error_code ec2;
|
||||
fs::remove(to, ec2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,8 @@
|
|||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/fsutil.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include "mamba/core/menuinst.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/transaction_context.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_os.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/core/validate.hpp"
|
||||
|
||||
#if _WIN32
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// 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 "mamba/core/mamba_fs.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace fs
|
||||
{
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Maintain `\` on Windows, `/` on other platforms
|
||||
std::filesystem::path normalized_separators(std::filesystem::path path)
|
||||
{
|
||||
auto native_string = path.native();
|
||||
static constexpr auto platform_separator = L"\\";
|
||||
static constexpr auto other_separator = L"/";
|
||||
mamba::replace_all(native_string, other_separator, platform_separator);
|
||||
path = std::move(native_string);
|
||||
return path;
|
||||
}
|
||||
#else
|
||||
// noop on non-Windows platforms
|
||||
std::filesystem::path normalized_separators(std::filesystem::path path)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __cplusplus == 201703L
|
||||
std::string to_utf8(const std::filesystem::path& path)
|
||||
{
|
||||
return normalized_separators(path).u8string();
|
||||
}
|
||||
|
||||
std::filesystem::path from_utf8(std::string_view u8string)
|
||||
{
|
||||
return normalized_separators(std::filesystem::u8path(u8string));
|
||||
}
|
||||
#else
|
||||
#error UTF8 functions implementation is specific to C++17, using another version requires a different implementation.
|
||||
#endif
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
#include "mamba/core/environment.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
#include <string>
|
||||
// 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 "mamba/core/context.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/transaction_context.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <shlobj.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/transaction_context.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
namespace detail
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "mamba/core/thread_utils.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "progress_bar_impl.hpp"
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/package_paths.hpp"
|
||||
#include "mamba/core/thread_utils.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_os.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/core/validate.hpp"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <tuple>
|
||||
|
||||
#include "mamba/core/channel.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "solv-cpp/queue.hpp"
|
||||
|
||||
|
@ -129,13 +129,13 @@ namespace mamba
|
|||
{
|
||||
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));
|
||||
url = channel + "/" + raw_str_or_empty(solvable_lookup_str(s, SOLVABLE_MEDIAFILE));
|
||||
}
|
||||
}
|
||||
|
||||
subdir = check_char(solvable_lookup_str(s, SOLVABLE_MEDIADIR));
|
||||
fn = check_char(solvable_lookup_str(s, SOLVABLE_MEDIAFILE));
|
||||
str = check_char(solvable_lookup_str(s, SOLVABLE_LICENSE));
|
||||
subdir = raw_str_or_empty(solvable_lookup_str(s, SOLVABLE_MEDIADIR));
|
||||
fn = raw_str_or_empty(solvable_lookup_str(s, SOLVABLE_MEDIAFILE));
|
||||
str = raw_str_or_empty(solvable_lookup_str(s, SOLVABLE_LICENSE));
|
||||
if (str)
|
||||
{
|
||||
license = str;
|
||||
|
@ -152,7 +152,7 @@ namespace mamba
|
|||
{
|
||||
sha256 = str;
|
||||
}
|
||||
signatures = check_char(solvable_lookup_str(s, SIGNATURE_DATA));
|
||||
signatures = raw_str_or_empty(solvable_lookup_str(s, SIGNATURE_DATA));
|
||||
if (signatures.empty())
|
||||
{
|
||||
signatures = "{}";
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <fstream>
|
||||
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
|
||||
namespace mamba
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/pool.hpp"
|
||||
#include "mamba/core/repo.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "solv-cpp/queue.hpp"
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/package_info.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "solv-cpp/queue.hpp"
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ extern "C" // Incomplete header
|
|||
#include "mamba/core/package_info.hpp"
|
||||
#include "mamba/core/pool.hpp"
|
||||
#include "mamba/core/repo.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
|
||||
#define MAMBA_TOOL_VERSION "1.1"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <thread>
|
||||
|
||||
#include <fmt/color.h>
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <reproc++/run.hpp>
|
||||
|
@ -17,6 +18,7 @@
|
|||
#include "mamba/core/execution.hpp"
|
||||
#include "mamba/core/util_os.hpp"
|
||||
#include "mamba/core/util_random.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#ifndef _WIN32
|
||||
extern "C"
|
||||
|
@ -290,7 +292,7 @@ namespace mamba
|
|||
}
|
||||
|
||||
LOG_DEBUG << "Currently running processes: " << get_all_running_processes_info();
|
||||
LOG_DEBUG << "Remaining args to run as command: " << join(" ", command);
|
||||
fmt::print(LOG_DEBUG, "Remaining args to run as command: {}", fmt::join(command, " "));
|
||||
|
||||
// replace the wrapping bash with new process entirely
|
||||
#ifndef _WIN32
|
||||
|
@ -305,7 +307,7 @@ namespace mamba
|
|||
command
|
||||
);
|
||||
|
||||
LOG_DEBUG << "Running wrapped script: " << join(" ", command);
|
||||
fmt::print(LOG_DEBUG, "Running wrapped script: {}", fmt::join(command, " "));
|
||||
|
||||
bool sinkout = stream_options & (int) STREAM_OPTIONS::SINKOUT;
|
||||
bool sinkerr = stream_options & (int) STREAM_OPTIONS::SINKERR;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mamba/core/shell_init.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_os.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "progress_bar_impl.hpp"
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ extern "C" // Incomplete header
|
|||
#include "mamba/core/repo.hpp"
|
||||
#include "mamba/core/satisfiability_error.hpp"
|
||||
#include "mamba/core/solver.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "solv-cpp/queue.hpp"
|
||||
|
||||
|
@ -345,8 +345,8 @@ namespace mamba
|
|||
}
|
||||
|
||||
modified_spec.channel = selected_channel;
|
||||
modified_spec.version = check_char(pool_id2str(pool, s->evr));
|
||||
modified_spec.build_string = check_char(
|
||||
modified_spec.version = raw_str_or_empty(pool_id2str(pool, s->evr));
|
||||
modified_spec.build_string = raw_str_or_empty(
|
||||
solvable_lookup_str(s, SOLVABLE_BUILDFLAVOR)
|
||||
);
|
||||
LOG_INFO << "Reinstall " << modified_spec.conda_build_form() << " from channel "
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/package_cache.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "progress_bar_impl.hpp"
|
||||
|
||||
|
@ -474,6 +474,17 @@ namespace mamba
|
|||
return m_check_targets;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> without_duplicates(std::vector<T>&& values)
|
||||
{
|
||||
const auto end_it = std::unique(values.begin(), values.end());
|
||||
values.erase(end_it, values.end());
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
bool MSubdirData::load(MultiPackageCache& caches)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,8 @@ extern "C" // Incomplete header
|
|||
#include "mamba/core/pool.hpp"
|
||||
#include "mamba/core/thread_utils.hpp"
|
||||
#include "mamba/core/transaction.hpp"
|
||||
#include "mamba/core/util_scope.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "solv-cpp/queue.hpp"
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "mamba/core/environment.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/transaction_context.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
extern const char data_compile_pyc_py[];
|
||||
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
|
||||
#include <regex>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
|
||||
#include "openssl/evp.h"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -54,6 +54,7 @@ extern "C"
|
|||
#include "mamba/core/util_compare.hpp"
|
||||
#include "mamba/core/util_os.hpp"
|
||||
#include "mamba/core/util_random.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -221,187 +222,6 @@ namespace mamba
|
|||
return m_path;
|
||||
}
|
||||
|
||||
/********************
|
||||
* utils for string *
|
||||
********************/
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool starts_with(const std::string_view& str, const std::string_view& prefix)
|
||||
{
|
||||
return str.size() >= prefix.size() && 0 == str.compare(0, prefix.size(), prefix);
|
||||
}
|
||||
|
||||
bool any_starts_with(const std::vector<std::string_view>& str, const std::string_view& prefix)
|
||||
{
|
||||
for (auto& s : str)
|
||||
{
|
||||
if (starts_with(s, prefix))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool starts_with_any(const std::string_view& str, const std::vector<std::string_view>& prefix)
|
||||
{
|
||||
for (auto& p : prefix)
|
||||
{
|
||||
if (starts_with(str, p))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool contains(const std::string_view& str, const std::string_view& sub_str)
|
||||
{
|
||||
return str.find(sub_str) != std::string::npos;
|
||||
}
|
||||
|
||||
std::string_view strip(const std::string_view& input)
|
||||
{
|
||||
return strip(input, WHITESPACES);
|
||||
}
|
||||
|
||||
// todo one could deduplicate this code with the one in strip() by using C++ 20 with concepts
|
||||
std::wstring_view strip(const std::wstring_view& input)
|
||||
{
|
||||
return strip<wchar_t>(input, WHITESPACES_WSTR);
|
||||
}
|
||||
|
||||
std::string_view strip(const std::string_view& input, const std::string_view& chars)
|
||||
{
|
||||
return strip<char>(input, chars);
|
||||
}
|
||||
|
||||
std::string_view lstrip(const std::string_view& input)
|
||||
{
|
||||
return lstrip(input, WHITESPACES);
|
||||
}
|
||||
|
||||
std::string_view rstrip(const std::string_view& input)
|
||||
{
|
||||
return rstrip(input, WHITESPACES);
|
||||
}
|
||||
|
||||
std::string_view lstrip(const std::string_view& input, const std::string_view& chars)
|
||||
{
|
||||
size_t start = input.find_first_not_of(chars);
|
||||
return start == std::string::npos ? "" : input.substr(start);
|
||||
}
|
||||
|
||||
std::string_view rstrip(const std::string_view& input, const std::string_view& chars)
|
||||
{
|
||||
size_t end = input.find_last_not_of(chars);
|
||||
return end == std::string::npos ? "" : input.substr(0, end + 1);
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
rsplit(const std::string_view& input, const std::string_view& sep, std::size_t 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());
|
||||
i = j = len;
|
||||
|
||||
while (i >= n)
|
||||
{
|
||||
if (input[i - 1] == sep[n - 1] && input.substr(i - n, n) == sep)
|
||||
{
|
||||
if (max_split-- <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
result.emplace_back(input.substr(i, j - i));
|
||||
i = j = i - n;
|
||||
}
|
||||
else
|
||||
{
|
||||
i--;
|
||||
}
|
||||
}
|
||||
result.emplace_back(input.substr(0, j));
|
||||
std::reverse(result.begin(), result.end());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace details
|
||||
{
|
||||
std::size_t size(const char* s)
|
||||
{
|
||||
return std::strlen(s);
|
||||
}
|
||||
std::size_t size(const wchar_t* s)
|
||||
{
|
||||
return std::wcslen(s);
|
||||
}
|
||||
std::size_t size(const char /*c*/)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class S>
|
||||
void replace_all_impl(S& data, const S& search, const S& replace)
|
||||
{
|
||||
if (search.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::size_t pos = data.find(search);
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
data.replace(pos, search.size(), replace);
|
||||
pos = data.find(search, pos + replace.size());
|
||||
}
|
||||
}
|
||||
|
||||
void replace_all(std::string& data, const std::string& search, const std::string& replace)
|
||||
{
|
||||
replace_all_impl<std::string>(data, search, replace);
|
||||
}
|
||||
|
||||
void replace_all(std::wstring& data, const std::wstring& search, const std::wstring& replace)
|
||||
{
|
||||
replace_all_impl<std::wstring>(data, search, replace);
|
||||
}
|
||||
|
||||
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); }
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string to_upper(const std::string_view& input)
|
||||
{
|
||||
return string_transform(input, std::toupper);
|
||||
}
|
||||
|
||||
std::string to_lower(const std::string_view& input)
|
||||
{
|
||||
return string_transform(input, std::tolower);
|
||||
}
|
||||
|
||||
std::string read_contents(const fs::u8path& file_path, std::ios::openmode mode)
|
||||
{
|
||||
std::ifstream in(file_path.std_path(), std::ios::in | mode);
|
||||
|
@ -1653,6 +1473,11 @@ namespace mamba
|
|||
return std::make_tuple(command_args, std::move(script_file));
|
||||
}
|
||||
|
||||
bool is_yaml_file_name(std::string_view filename)
|
||||
{
|
||||
return ends_with(filename, ".yml") || ends_with(filename, ".yaml");
|
||||
}
|
||||
|
||||
tl::expected<std::string, mamba_error> encode_base64(const std::string_view& input)
|
||||
{
|
||||
const auto pl = 4 * ((input.size() + 2) / 3);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_os.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -0,0 +1,438 @@
|
|||
// Copyright (c) 2023, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <cwctype>
|
||||
#include <exception>
|
||||
#include <type_traits>
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
/***************************************************
|
||||
* Implementation of to_lower to_upper functions *
|
||||
***************************************************/
|
||||
|
||||
char to_lower(char c)
|
||||
{
|
||||
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
}
|
||||
|
||||
wchar_t to_lower(wchar_t c)
|
||||
{
|
||||
return static_cast<wchar_t>(std::tolower(static_cast<wchar_t>(c)));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename Char>
|
||||
std::basic_string<Char> to_lower_impl(std::basic_string_view<Char> str)
|
||||
{
|
||||
auto out = std::basic_string<Char>();
|
||||
std::transform(
|
||||
str.cbegin(),
|
||||
str.cend(),
|
||||
std::back_inserter(out),
|
||||
[](auto c) { return to_lower(c); }
|
||||
);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
std::string to_lower(std::string_view str)
|
||||
{
|
||||
return to_lower_impl(str);
|
||||
}
|
||||
|
||||
std::wstring to_lower(std::wstring_view str)
|
||||
{
|
||||
return to_lower_impl(str);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
std::basic_string<Char> to_lower(std::basic_string<Char>&& str)
|
||||
{
|
||||
std::transform(str.cbegin(), str.cend(), str.begin(), [](auto c) { return to_lower(c); });
|
||||
return str;
|
||||
}
|
||||
|
||||
template std::string to_lower(std::string&& str);
|
||||
template std::wstring to_lower(std::wstring&& str);
|
||||
|
||||
char to_upper(char c)
|
||||
{
|
||||
return static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
|
||||
}
|
||||
|
||||
wchar_t to_upper(wchar_t c)
|
||||
{
|
||||
return static_cast<wchar_t>(std::toupper(static_cast<wchar_t>(c)));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename Char>
|
||||
std::basic_string<Char> to_upper_impl(std::basic_string_view<Char> str)
|
||||
{
|
||||
auto out = std::basic_string<Char>();
|
||||
std::transform(
|
||||
str.cbegin(),
|
||||
str.cend(),
|
||||
std::back_inserter(out),
|
||||
[](auto c) { return to_upper(c); }
|
||||
);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
std::string to_upper(std::string_view str)
|
||||
{
|
||||
return to_upper_impl(str);
|
||||
}
|
||||
|
||||
std::wstring to_upper(std::wstring_view str)
|
||||
{
|
||||
return to_upper_impl(str);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
std::basic_string<Char> to_upper(std::basic_string<Char>&& str)
|
||||
{
|
||||
std::transform(str.cbegin(), str.cend(), str.begin(), [](auto c) { return to_upper(c); });
|
||||
return str;
|
||||
}
|
||||
|
||||
template std::string to_upper(std::string&& str);
|
||||
template std::wstring to_upper(std::wstring&& str);
|
||||
|
||||
/*******************************************
|
||||
* Implementation of start_with functions *
|
||||
*******************************************/
|
||||
|
||||
// TODO(C++20) This is a method of string_view
|
||||
bool contains(std::string_view str, std::string_view sub_str)
|
||||
{
|
||||
return str.find(sub_str) != std::string::npos;
|
||||
}
|
||||
|
||||
// TODO(C++20) This is a method of string_view
|
||||
bool ends_with(std::string_view str, std::string_view suffix)
|
||||
{
|
||||
return str.size() >= suffix.size()
|
||||
&& 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
|
||||
}
|
||||
|
||||
// TODO(C++20) This is a method of string_view
|
||||
bool starts_with(std::string_view str, std::string_view prefix)
|
||||
{
|
||||
return str.size() >= prefix.size() && 0 == str.compare(0, prefix.size(), prefix);
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* Implementation of starts_with functions *
|
||||
*********************************************/
|
||||
|
||||
template bool any_starts_with(const std::vector<std::string>&, std::string_view);
|
||||
template bool any_starts_with(const std::vector<std::string_view>&, std::string_view);
|
||||
|
||||
template bool starts_with_any(std::string_view, const std::vector<std::string>&);
|
||||
template bool starts_with_any(std::string_view, const std::vector<std::string_view>&);
|
||||
|
||||
/***************************************
|
||||
* Implementation of strip functions *
|
||||
***************************************/
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr const char* WHITESPACES(" \r\n\t\f\v");
|
||||
constexpr const wchar_t* WHITESPACES_WSTR(L" \r\n\t\f\v");
|
||||
|
||||
template <typename Char, typename CharOrStrView>
|
||||
std::basic_string_view<Char>
|
||||
lstrip_impl(std::basic_string_view<Char> input, CharOrStrView chars)
|
||||
{
|
||||
std::size_t const start = input.find_first_not_of(chars);
|
||||
return (start == std::string::npos) ? std::basic_string_view<Char>{}
|
||||
: input.substr(start);
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view lstrip(std::string_view input, char c)
|
||||
{
|
||||
return lstrip_impl(input, c);
|
||||
}
|
||||
std::wstring_view lstrip(std::wstring_view input, wchar_t c)
|
||||
{
|
||||
return lstrip_impl(input, c);
|
||||
}
|
||||
std::string_view lstrip(std::string_view input, std::string_view chars)
|
||||
{
|
||||
return lstrip_impl(input, chars);
|
||||
}
|
||||
std::wstring_view lstrip(std::wstring_view input, std::wstring_view chars)
|
||||
{
|
||||
return lstrip_impl(input, chars);
|
||||
}
|
||||
std::string_view lstrip(std::string_view input)
|
||||
{
|
||||
return lstrip(input, WHITESPACES);
|
||||
}
|
||||
std::wstring_view lstrip(std::wstring_view input)
|
||||
{
|
||||
return lstrip(input, WHITESPACES_WSTR);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename Char, typename CharOrStrView>
|
||||
std::basic_string_view<Char>
|
||||
rstrip_impl(std::basic_string_view<Char> input, CharOrStrView chars)
|
||||
{
|
||||
std::size_t const end = input.find_last_not_of(chars);
|
||||
return (end == std::string::npos) ? std::basic_string_view<Char>{}
|
||||
: input.substr(0, end + 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view rstrip(std::string_view input, char c)
|
||||
{
|
||||
return rstrip_impl(input, c);
|
||||
}
|
||||
std::wstring_view rstrip(std::wstring_view input, wchar_t c)
|
||||
{
|
||||
return rstrip_impl(input, c);
|
||||
}
|
||||
std::string_view rstrip(std::string_view input, std::string_view chars)
|
||||
{
|
||||
return rstrip_impl(input, chars);
|
||||
}
|
||||
std::wstring_view rstrip(std::wstring_view input, std::wstring_view chars)
|
||||
{
|
||||
return rstrip_impl(input, chars);
|
||||
}
|
||||
std::string_view rstrip(std::string_view input)
|
||||
{
|
||||
return rstrip(input, WHITESPACES);
|
||||
}
|
||||
std::wstring_view rstrip(std::wstring_view input)
|
||||
{
|
||||
return rstrip(input, WHITESPACES_WSTR);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename Char, typename CharOrStrView>
|
||||
std::basic_string_view<Char>
|
||||
strip_impl(std::basic_string_view<Char> input, CharOrStrView chars)
|
||||
{
|
||||
std::size_t const start = input.find_first_not_of(chars);
|
||||
if (start == std::basic_string_view<Char>::npos)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
std::size_t const stop = input.find_last_not_of(chars) + 1;
|
||||
std::size_t const length = stop - start;
|
||||
return (length == 0) ? std::basic_string_view<Char>{} : input.substr(start, length);
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view strip(std::string_view input, char c)
|
||||
{
|
||||
return strip_impl(input, c);
|
||||
}
|
||||
std::wstring_view strip(std::wstring_view input, wchar_t c)
|
||||
{
|
||||
return strip_impl(input, c);
|
||||
}
|
||||
std::string_view strip(std::string_view input, std::string_view chars)
|
||||
{
|
||||
return strip_impl(input, chars);
|
||||
}
|
||||
std::wstring_view strip(std::wstring_view input, std::wstring_view chars)
|
||||
{
|
||||
return strip_impl(input, chars);
|
||||
}
|
||||
std::string_view strip(std::string_view input)
|
||||
{
|
||||
return strip(input, WHITESPACES);
|
||||
}
|
||||
std::wstring_view strip(std::wstring_view input)
|
||||
{
|
||||
return strip(input, WHITESPACES_WSTR);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Implementation of split functions *
|
||||
***************************************/
|
||||
|
||||
namespace
|
||||
{
|
||||
template <class Char>
|
||||
std::vector<std::basic_string<Char>> split(
|
||||
const std::basic_string_view<Char> input,
|
||||
const std::basic_string_view<Char> sep,
|
||||
std::size_t max_split = SIZE_MAX
|
||||
)
|
||||
{
|
||||
if (sep.size() < 1)
|
||||
{
|
||||
throw std::invalid_argument("Separator must have size greater than 0");
|
||||
}
|
||||
|
||||
std::vector<std::basic_string<Char>> result;
|
||||
|
||||
std::size_t const len = input.size();
|
||||
std::size_t const n = sep.size();
|
||||
std::size_t i = 0;
|
||||
std::size_t j = 0;
|
||||
|
||||
while (i + n <= len)
|
||||
{
|
||||
if (input[i] == sep[0] && input.substr(i, n) == sep)
|
||||
{
|
||||
if (max_split-- <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
result.emplace_back(input.substr(j, i - j));
|
||||
i = j = i + n;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
result.emplace_back(input.substr(j, len - j));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Char>
|
||||
std::vector<std::basic_string<Char>> rsplit(
|
||||
const std::basic_string_view<Char> input,
|
||||
const std::basic_string_view<Char> sep,
|
||||
std::size_t max_split = SIZE_MAX
|
||||
)
|
||||
{
|
||||
if (max_split == SIZE_MAX)
|
||||
{
|
||||
return split(input, sep, max_split);
|
||||
}
|
||||
if (sep.size() < 1)
|
||||
{
|
||||
throw std::invalid_argument("Separator must have size greater than 0");
|
||||
}
|
||||
|
||||
std::vector<std::basic_string<Char>> result;
|
||||
|
||||
std::size_t const len = input.size();
|
||||
std::size_t const n = sep.size();
|
||||
std::size_t i = len;
|
||||
std::size_t j = len;
|
||||
|
||||
while (i >= n)
|
||||
{
|
||||
if (input[i - 1] == sep[n - 1] && input.substr(i - n, n) == sep)
|
||||
{
|
||||
if (max_split-- <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
result.emplace_back(input.substr(i, j - i));
|
||||
i = j = i - n;
|
||||
}
|
||||
else
|
||||
{
|
||||
i--;
|
||||
}
|
||||
}
|
||||
result.emplace_back(input.substr(0, j));
|
||||
std::reverse(result.begin(), result.end());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
split(std::string_view input, std::string_view sep, std::size_t max_split)
|
||||
{
|
||||
return split<decltype(input)::value_type>(input, sep, max_split);
|
||||
}
|
||||
|
||||
std::vector<std::wstring>
|
||||
split(std::wstring_view input, std::wstring_view sep, std::size_t max_split)
|
||||
{
|
||||
return split<decltype(input)::value_type>(input, sep, max_split);
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
rsplit(std::string_view input, std::string_view sep, std::size_t max_split)
|
||||
{
|
||||
return rsplit<decltype(input)::value_type>(input, sep, max_split);
|
||||
}
|
||||
|
||||
std::vector<std::wstring>
|
||||
rsplit(std::wstring_view input, std::wstring_view sep, std::size_t max_split)
|
||||
{
|
||||
return rsplit<decltype(input)::value_type>(input, sep, max_split);
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Implementation of replace functions *
|
||||
*****************************************/
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename Char>
|
||||
void replace_all_impl(
|
||||
std::basic_string<Char>& data,
|
||||
std::basic_string_view<Char> search,
|
||||
std::basic_string_view<Char> replace
|
||||
)
|
||||
{
|
||||
if (search.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::size_t pos = data.find(search);
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
data.replace(pos, search.size(), replace);
|
||||
pos = data.find(search, pos + replace.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void replace_all(std::string& data, std::string_view search, std::string_view replace)
|
||||
{
|
||||
replace_all_impl(data, search, replace);
|
||||
}
|
||||
|
||||
void replace_all(std::wstring& data, std::wstring_view search, std::wstring_view replace)
|
||||
{
|
||||
replace_all_impl(data, search, replace);
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Implementation of join functions *
|
||||
**************************************/
|
||||
|
||||
namespace detail
|
||||
{
|
||||
std::size_t size(const char* s)
|
||||
{
|
||||
return std::strlen(s);
|
||||
}
|
||||
std::size_t size(const wchar_t* s)
|
||||
{
|
||||
return std::wcslen(s);
|
||||
}
|
||||
std::size_t size(const char /*c*/)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,18 +13,16 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "mamba/core/fetch.hpp"
|
||||
#include "mamba/core/fsutil.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
|
||||
#include "openssl/evp.h"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
|
||||
template <class B>
|
||||
std::vector<unsigned char> hex_to_bytes(const B& buffer, std::size_t size) noexcept
|
||||
{
|
||||
|
@ -666,7 +664,7 @@ namespace validate
|
|||
std::vector<std::string_view> possible_upgrades;
|
||||
for (auto& s : upgrade_prefixes)
|
||||
{
|
||||
s += ".";
|
||||
s += '.';
|
||||
possible_upgrades.push_back(s);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// 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 "mamba/core/virtual_packages.hpp"
|
||||
|
||||
#include "mamba/core/context.hpp"
|
||||
|
@ -5,6 +11,7 @@
|
|||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_os.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
// 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 <gtest/gtest.h>
|
||||
|
||||
#include "mamba/api/configuration.hpp"
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "test_data.hpp"
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// 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 <chrono>
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
|
@ -5,6 +11,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/environment.hpp"
|
||||
#include "mamba/core/fsutil.hpp"
|
||||
#include "mamba/core/history.hpp"
|
||||
#include "mamba/core/link.hpp"
|
||||
|
@ -499,66 +506,6 @@ namespace mamba
|
|||
EXPECT_EQ(quote_for_shell(args8, "cmdexe"), "ab \"\"");
|
||||
}
|
||||
|
||||
TEST(utils, strip)
|
||||
{
|
||||
{
|
||||
std::string x(strip(" testwhitespacestrip "));
|
||||
EXPECT_EQ(x, "testwhitespacestrip");
|
||||
std::string y(rstrip(" testwhitespacestrip "));
|
||||
EXPECT_EQ(y, " testwhitespacestrip");
|
||||
std::string z(lstrip(" testwhitespacestrip "));
|
||||
EXPECT_EQ(z, "testwhitespacestrip ");
|
||||
}
|
||||
{
|
||||
std::string x(strip(" "));
|
||||
EXPECT_EQ(x, "");
|
||||
std::string y(rstrip(" "));
|
||||
EXPECT_EQ(y, "");
|
||||
std::string z(lstrip(" "));
|
||||
EXPECT_EQ(z, "");
|
||||
}
|
||||
{
|
||||
std::string x(strip("a"));
|
||||
EXPECT_EQ(x, "a");
|
||||
std::string y(rstrip("a"));
|
||||
EXPECT_EQ(y, "a");
|
||||
std::string z(lstrip("a"));
|
||||
EXPECT_EQ(z, "a");
|
||||
}
|
||||
{
|
||||
std::string x(strip(" a "));
|
||||
EXPECT_EQ(x, "a");
|
||||
std::string y(rstrip(" a "));
|
||||
EXPECT_EQ(y, " a");
|
||||
std::string z(lstrip(" a "));
|
||||
EXPECT_EQ(z, "a ");
|
||||
}
|
||||
{
|
||||
std::string x(strip("abc"));
|
||||
EXPECT_EQ(x, "abc");
|
||||
std::string y(rstrip("abc"));
|
||||
EXPECT_EQ(y, "abc");
|
||||
std::string z(lstrip("abc"));
|
||||
EXPECT_EQ(z, "abc");
|
||||
}
|
||||
{
|
||||
std::string x(strip(" \r \t \n "));
|
||||
EXPECT_EQ(x, "");
|
||||
std::string y(rstrip(" \r \t \n "));
|
||||
EXPECT_EQ(y, "");
|
||||
std::string z(lstrip(" \r \t \n "));
|
||||
EXPECT_EQ(z, "");
|
||||
}
|
||||
{
|
||||
std::string x(strip("\r \t \n testwhitespacestrip \r \t \n"));
|
||||
EXPECT_EQ(x, "testwhitespacestrip");
|
||||
std::string y(rstrip(" \r \t \n testwhitespacestrip \r \t \n"));
|
||||
EXPECT_EQ(y, " \r \t \n testwhitespacestrip");
|
||||
std::string z(lstrip(" \r \t \n testwhitespacestrip \r \t \n "));
|
||||
EXPECT_EQ(z, "testwhitespacestrip \r \t \n ");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(utils, lexists)
|
||||
{
|
||||
fs::create_symlink("empty_target", "nonexistinglink");
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mamba/core/environment.hpp"
|
||||
#include "mamba/core/environments_manager.hpp"
|
||||
#include "mamba/core/mamba_fs.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mamba/core/invoke.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "mamba/core/environment.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
// 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 <gtest/gtest.h>
|
||||
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/environment.hpp"
|
||||
#include "mamba/core/execution.hpp"
|
||||
#include "mamba/core/fsutil.hpp"
|
||||
#include "mamba/core/mamba_fs.hpp"
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
// Copyright (c) 2023, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mamba/core/mamba_fs.hpp"
|
||||
|
@ -5,6 +13,20 @@
|
|||
|
||||
namespace mamba
|
||||
{
|
||||
TEST(util_string, to_lower)
|
||||
{
|
||||
EXPECT_EQ(to_lower('A'), 'a');
|
||||
EXPECT_EQ(to_lower('b'), 'b');
|
||||
EXPECT_EQ(to_lower("ThisIsARandomTTTeeesssT"), "thisisarandomttteeessst");
|
||||
}
|
||||
|
||||
TEST(util_string, to_upper)
|
||||
{
|
||||
EXPECT_EQ(to_upper('a'), 'A');
|
||||
EXPECT_EQ(to_upper('B'), 'B');
|
||||
EXPECT_EQ(to_upper("ThisIsARandomTTTeeesssT"), "THISISARANDOMTTTEEESSST");
|
||||
}
|
||||
|
||||
TEST(util_string, starts_with)
|
||||
{
|
||||
EXPECT_TRUE(starts_with(":hello", ""));
|
||||
|
@ -37,23 +59,25 @@ namespace mamba
|
|||
|
||||
TEST(util_string, any_starts_with)
|
||||
{
|
||||
EXPECT_FALSE(any_starts_with({}, "not"));
|
||||
EXPECT_FALSE(any_starts_with({}, ""));
|
||||
EXPECT_TRUE(any_starts_with({ ":hello", "world" }, ""));
|
||||
EXPECT_TRUE(any_starts_with({ ":hello", "world" }, ":"));
|
||||
EXPECT_TRUE(any_starts_with({ ":hello", "world" }, ":h"));
|
||||
EXPECT_TRUE(any_starts_with({ ":hello", "world" }, ":hello"));
|
||||
EXPECT_FALSE(any_starts_with({ ":hello", "world" }, "orld"));
|
||||
EXPECT_TRUE(any_starts_with({ "áäᜩgþhëb", "®hüghœ©®xb" }, "áäá"));
|
||||
using StrVec = std::vector<std::string_view>;
|
||||
EXPECT_FALSE(any_starts_with(StrVec{}, { "not" }));
|
||||
EXPECT_FALSE(any_starts_with(StrVec{}, ""));
|
||||
EXPECT_TRUE(any_starts_with(StrVec{ ":hello", "world" }, ""));
|
||||
EXPECT_TRUE(any_starts_with(StrVec{ ":hello", "world" }, ":"));
|
||||
EXPECT_TRUE(any_starts_with(StrVec{ ":hello", "world" }, ":h"));
|
||||
EXPECT_TRUE(any_starts_with(StrVec{ ":hello", "world" }, ":hello"));
|
||||
EXPECT_FALSE(any_starts_with(StrVec{ ":hello", "world" }, "orld"));
|
||||
EXPECT_TRUE(any_starts_with(StrVec{ "áäᜩgþhëb", "®hüghœ©®xb" }, "áäá"));
|
||||
}
|
||||
|
||||
TEST(util_string, starts_with_any)
|
||||
{
|
||||
EXPECT_TRUE(starts_with_any(":hello", { "", "not" }));
|
||||
EXPECT_TRUE(starts_with_any(":hello", { ":hello", "not" }));
|
||||
EXPECT_FALSE(starts_with_any(":hello", {}));
|
||||
EXPECT_FALSE(starts_with_any(":hello", { "not", "any" }));
|
||||
EXPECT_TRUE(starts_with_any("áäᜩgþhëb®hüghœ©®xb", { "áäᜩgþhëb", "®hüghœ©®xb" }));
|
||||
using StrVec = std::vector<std::string_view>;
|
||||
EXPECT_TRUE(starts_with_any(":hello", StrVec{ "", "not" }));
|
||||
EXPECT_TRUE(starts_with_any(":hello", StrVec{ ":hello", "not" }));
|
||||
EXPECT_FALSE(starts_with_any(":hello", StrVec{}));
|
||||
EXPECT_FALSE(starts_with_any(":hello", StrVec{ "not", "any" }));
|
||||
EXPECT_TRUE(starts_with_any("áäᜩgþhëb®hüghœ©®xb", StrVec{ "áäᜩgþhëb", "®hüghœ©®xb" }));
|
||||
}
|
||||
|
||||
TEST(util_string, strip)
|
||||
|
@ -80,6 +104,66 @@ namespace mamba
|
|||
EXPECT_EQ(rstrip(":::hello%:%", ":"), ":::hello%:%");
|
||||
}
|
||||
|
||||
TEST(utils, strip_whitespaces)
|
||||
{
|
||||
{
|
||||
std::string x(strip(" testwhitespacestrip "));
|
||||
EXPECT_EQ(x, "testwhitespacestrip");
|
||||
std::string y(rstrip(" testwhitespacestrip "));
|
||||
EXPECT_EQ(y, " testwhitespacestrip");
|
||||
std::string z(lstrip(" testwhitespacestrip "));
|
||||
EXPECT_EQ(z, "testwhitespacestrip ");
|
||||
}
|
||||
{
|
||||
std::string x(strip(" "));
|
||||
EXPECT_EQ(x, "");
|
||||
std::string y(rstrip(" "));
|
||||
EXPECT_EQ(y, "");
|
||||
std::string z(lstrip(" "));
|
||||
EXPECT_EQ(z, "");
|
||||
}
|
||||
{
|
||||
std::string x(strip("a"));
|
||||
EXPECT_EQ(x, "a");
|
||||
std::string y(rstrip("a"));
|
||||
EXPECT_EQ(y, "a");
|
||||
std::string z(lstrip("a"));
|
||||
EXPECT_EQ(z, "a");
|
||||
}
|
||||
{
|
||||
std::string x(strip(" a "));
|
||||
EXPECT_EQ(x, "a");
|
||||
std::string y(rstrip(" a "));
|
||||
EXPECT_EQ(y, " a");
|
||||
std::string z(lstrip(" a "));
|
||||
EXPECT_EQ(z, "a ");
|
||||
}
|
||||
{
|
||||
std::string x(strip("abc"));
|
||||
EXPECT_EQ(x, "abc");
|
||||
std::string y(rstrip("abc"));
|
||||
EXPECT_EQ(y, "abc");
|
||||
std::string z(lstrip("abc"));
|
||||
EXPECT_EQ(z, "abc");
|
||||
}
|
||||
{
|
||||
std::string x(strip(" \r \t \n "));
|
||||
EXPECT_EQ(x, "");
|
||||
std::string y(rstrip(" \r \t \n "));
|
||||
EXPECT_EQ(y, "");
|
||||
std::string z(lstrip(" \r \t \n "));
|
||||
EXPECT_EQ(z, "");
|
||||
}
|
||||
{
|
||||
std::string x(strip("\r \t \n testwhitespacestrip \r \t \n"));
|
||||
EXPECT_EQ(x, "testwhitespacestrip");
|
||||
std::string y(rstrip(" \r \t \n testwhitespacestrip \r \t \n"));
|
||||
EXPECT_EQ(y, " \r \t \n testwhitespacestrip");
|
||||
std::string z(lstrip(" \r \t \n testwhitespacestrip \r \t \n "));
|
||||
EXPECT_EQ(z, "testwhitespacestrip \r \t \n ");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(util_string, split)
|
||||
{
|
||||
std::string a = "hello.again.it's.me.mario";
|
||||
|
@ -171,15 +255,6 @@ namespace mamba
|
|||
EXPECT_EQ(prefix_unicode, "/home/åéäáßðæœ©ðfßfáðß/123123123\n\nabcdefg\nxyz");
|
||||
}
|
||||
|
||||
TEST(util_string, to_upper_lower)
|
||||
{
|
||||
std::string a = "ThisIsARandomTTTeeesssT";
|
||||
EXPECT_EQ(to_upper(a), "THISISARANDOMTTTEEESSST");
|
||||
// std::wstring b = "áäᜩgþhëb®hüghœ©®xb";
|
||||
// EXPECT_EQ(to_upper(b), "ÁÄÁŒ©GÞHËB®HÜGHŒ©®XB");
|
||||
// EXPECT_EQ(to_lower(a), "thisisarandomttteeessst");
|
||||
}
|
||||
|
||||
TEST(util_string, concat)
|
||||
{
|
||||
EXPECT_EQ(concat("aa", std::string("bb"), std::string_view("cc"), 'd'), "aabbccd");
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include "mamba/core/environment.hpp"
|
||||
#include "mamba/core/fsutil.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/core/validate.hpp"
|
||||
|
||||
#include "test_data.hpp"
|
||||
|
@ -1840,7 +1840,7 @@ namespace validate
|
|||
])"_json;
|
||||
|
||||
const RootImpl root(create_root_update("2.root.json", patch));
|
||||
bool mirrors_role_found = contains(root.roles(), "mirrors");
|
||||
const bool mirrors_role_found = root.roles().find("mirrors") != root.roles().cend();
|
||||
EXPECT_TRUE(mirrors_role_found);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
#include "mamba/core/subdirdata.hpp"
|
||||
#include "mamba/core/transaction.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_graph.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/core/validate.hpp"
|
||||
#include "mamba/core/virtual_packages.hpp"
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "package.hpp"
|
||||
|
||||
#include "mamba/core/package_handling.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
using namespace mamba; // NOLINT(build/namespaces)
|
||||
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
// 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
|
||||
#include "mamba/api/configuration.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/run.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
|
||||
void
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "mamba/api/configuration.hpp"
|
||||
#include "mamba/core/fsutil.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
|
||||
#include "common_options.hpp"
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include "mamba/core/package_handling.hpp"
|
||||
#include "mamba/core/package_info.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "common_options.hpp"
|
||||
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
// 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 <string>
|
||||
|
||||
#include "mamba/api/configuration.hpp"
|
||||
#include "mamba/api/create.hpp"
|
||||
#include "mamba/api/remove.hpp"
|
||||
|
@ -5,6 +13,7 @@
|
|||
#include "mamba/core/environments_manager.hpp"
|
||||
#include "mamba/core/prefix_data.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "common_options.hpp"
|
||||
|
||||
|
|
|
@ -3,10 +3,14 @@
|
|||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
#include "mamba/api/configuration.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "mamba/api/list.hpp"
|
||||
#include "mamba/core/environment.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "common_options.hpp"
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "mamba/api/configuration.hpp"
|
||||
#include "mamba/core/package_handling.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
|
||||
#include "common_options.hpp"
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <thread>
|
||||
|
||||
#include <fmt/color.h>
|
||||
#include <fmt/format.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <reproc++/run.hpp>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
@ -68,10 +69,12 @@ set_ps_command(CLI::App* subcom)
|
|||
prefix = env_name(prefix);
|
||||
}
|
||||
|
||||
table.add_row({ el["pid"].get<std::string>(),
|
||||
el["name"].get<std::string>(),
|
||||
prefix,
|
||||
join(" ", el["command"].get<std::vector<std::string>>()) });
|
||||
table.add_row({
|
||||
el["pid"].get<std::string>(),
|
||||
el["name"].get<std::string>(),
|
||||
prefix,
|
||||
fmt::format("{}", fmt::join(el["command"].get<std::vector<std::string>>(), " ")),
|
||||
});
|
||||
}
|
||||
|
||||
table.print(std::cout);
|
||||
|
|
Loading…
Reference in New Issue