Merge pull request #1563 from JohanMabille/expected

Plugged tl::expected and refactored MSubdirData construction
This commit is contained in:
Wolf Vollprecht 2022-03-10 19:03:38 +01:00 committed by GitHub
commit d07ee8abac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 403 additions and 62 deletions

View File

@ -283,6 +283,7 @@ macro(libmamba_create_target target_name linkage deps_linkage output_name)
find_library(LIBSOLV_BUILD_STATICRARIES NAMES solv_static)
find_library(LIBSOLVEXT_BUILD_STATICRARIES NAMES solvext_static)
find_package(reproc++ CONFIG REQUIRED)
find_package(tl-expected REQUIRED)
find_library(LIBXML2_LIBRARY NAMES libxml2)
find_library(ICONV_LIBRARY NAMES libiconv)
@ -308,6 +309,7 @@ macro(libmamba_create_target target_name linkage deps_linkage output_name)
${sodium_LIBRARY_RELEASE}
reproc++
reproc
tl::expected
)
add_definitions("-DLIBARCHIVE_STATIC -DCURL_STATICLIB -DSOLV_BUILD_STATIC")
@ -325,6 +327,7 @@ macro(libmamba_create_target target_name linkage deps_linkage output_name)
find_package(OpenSSL REQUIRED)
find_package(yaml-cpp CONFIG REQUIRED)
find_package(reproc++ CONFIG REQUIRED)
find_package(tl-expected REQUIRED)
set(LIBMAMBA_LIBRARIES_DEPS
${LIBSOLV_LIBRARIES}
@ -335,6 +338,7 @@ macro(libmamba_create_target target_name linkage deps_linkage output_name)
${YAML_CPP_LIBRARIES}
reproc++
reproc
tl::expected
)
target_link_libraries(${target_name} PUBLIC

View File

@ -14,6 +14,7 @@ dependencies:
- gtest
- gmock
- cpp-filesystem >=1.5.8
- cpp-expected
- reproc-cpp
- yaml-cpp
- termcolor-cpp

View File

@ -35,6 +35,12 @@ namespace mamba
const std::string& filename);
~DownloadTarget();
DownloadTarget(const DownloadTarget&) = delete;
DownloadTarget& operator=(const DownloadTarget&) = delete;
DownloadTarget(DownloadTarget&&);
DownloadTarget& operator=(DownloadTarget&&);
static size_t write_callback(char* ptr, size_t size, size_t nmemb, void* self);
static size_t header_callback(char* buffer, size_t size, size_t nitems, void* self);

View File

@ -9,6 +9,7 @@
#include <string>
#include <unordered_map>
#include "tl/expected.hpp"
#include "history.hpp"
#include "package_info.hpp"
@ -16,12 +17,21 @@
namespace mamba
{
enum class prefixdata_error
{
unknown,
load
};
class PrefixData
{
public:
using package_map = std::unordered_map<std::string, PackageInfo>;
PrefixData(const fs::path& prefix_path);
template <class T>
using expected = tl::expected<T, mamba_error<prefixdata_error>>;
static expected<PrefixData> create(const fs::path& prefix_path);
void add_packages(const std::vector<PackageInfo>& packages);
const package_map& records() const;
@ -32,6 +42,7 @@ namespace mamba
std::vector<PackageInfo> sorted_records() const;
private:
PrefixData(const fs::path& prefix_path);
void load();
History m_history;

View File

@ -280,7 +280,7 @@ namespace mamba
const ProgressBar& progress_bar() const;
private:
ProgressBar* p_progress_bar;
ProgressBar* p_progress_bar = nullptr;
std::size_t m_width = 0;
void set_same_widths(const ProgressBarRepr& r);
@ -359,7 +359,7 @@ namespace mamba
int width() const;
private:
ProgressBar* p_bar;
ProgressBar* p_bar = nullptr;
friend class ProgressBarManager;
};

View File

@ -11,6 +11,7 @@
#include <regex>
#include <string>
#include "tl/expected.hpp"
#include "nlohmann/json.hpp"
#include "mamba/core/channel.hpp"
@ -31,6 +32,13 @@ namespace decompress
namespace mamba
{
enum class subdirdata_error
{
unknown,
load
};
/**
* Represents a channel subdirectory (i.e. a platform)
* packages index. Handles downloading of the index
@ -39,11 +47,22 @@ namespace mamba
class MSubdirData
{
public:
MSubdirData(const Channel& channel,
const std::string& platform,
const std::string& url,
MultiPackageCache& caches,
const std::string& repodata_fn = "repodata.json");
template <class T>
using expected = tl::expected<T, mamba_error<subdirdata_error>>;
static expected<MSubdirData> create(const Channel& channel,
const std::string& platform,
const std::string& url,
MultiPackageCache& caches,
const std::string& repodata_fn = "repodata.json");
~MSubdirData() = default;
MSubdirData(const MSubdirData&) = delete;
MSubdirData& operator=(const MSubdirData&) = delete;
MSubdirData(MSubdirData&&);
MSubdirData& operator=(MSubdirData&&);
// TODO return seconds as double
fs::file_time_type::duration check_cache(const fs::path& cache_file,
@ -62,19 +81,24 @@ namespace mamba
MRepo& create_repo(MPool& pool);
private:
MSubdirData(const Channel& channel,
const std::string& platform,
const std::string& url,
MultiPackageCache& caches,
const std::string& repodata_fn = "repodata.json");
bool load();
bool decompress();
void create_target(nlohmann::json& mod_etag);
std::size_t get_cache_control_max_age(const std::string& val);
std::unique_ptr<DownloadTarget> m_target;
std::unique_ptr<DownloadTarget> m_target = nullptr;
bool m_json_cache_valid = false;
bool m_solv_cache_valid = false;
fs::path m_valid_cache_path, m_expired_cache_path;
std::ofstream out_file;
fs::path m_valid_cache_path;
fs::path m_expired_cache_path;
ProgressProxy m_progress_bar;
@ -84,7 +108,7 @@ namespace mamba
std::string m_name;
std::string m_json_fn;
std::string m_solv_fn;
MultiPackageCache& m_caches;
MultiPackageCache* p_caches;
bool m_is_noarch;
nlohmann::json m_mod_etag;
std::unique_ptr<TemporaryFile> m_temp_file;

View File

@ -52,12 +52,6 @@ namespace mamba
const static std::regex token_re("/t/([a-zA-Z0-9-_]{0,2}[a-zA-Z0-9-]*)");
const static std::regex http_basicauth_re("://([^\\s]+):([^\\s]+)@");
class mamba_error : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
};
bool is_package_file(const std::string_view& fn);
bool lexists(const fs::path& p);
@ -117,6 +111,26 @@ namespace mamba
return result;
}
enum class unspecified_error
{
unkown
};
template <class error_type>
class mamba_error : public std::runtime_error
{
public:
using base_type = std::runtime_error;
mamba_error(const std::string& msg, error_type ec);
mamba_error(const char* msg, error_type ec);
error_type error_code() const noexcept;
private:
error_type m_error_code;
};
class TemporaryDirectory
{
public:
@ -467,6 +481,30 @@ namespace mamba
std::tuple<std::vector<std::string>, std::unique_ptr<TemporaryFile>> prepare_wrapped_call(
const fs::path& prefix, const std::vector<std::string>& cmd);
/******************************
* mamba_error implementation *
******************************/
template <class ET>
mamba_error<ET>::mamba_error(const std::string& msg, ET ec)
: base_type(msg)
, m_error_code(ec)
{
}
template <class ET>
mamba_error<ET>::mamba_error(const char* msg, ET ec)
: base_type(msg)
, m_error_code(ec)
{
}
template <class ET>
ET mamba_error<ET>::error_code() const noexcept
{
return m_error_code;
}
} // namespace mamba
#endif // MAMBA_UTIL_HPP

View File

@ -24,6 +24,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR};${CMAKE_MODULE_PATH}")
include(CMakeFindDependencyMacro)
find_dependency(nlohmann_json)
find_dependency(Threads)
find_dependency(tl-expected)
if(NOT (TARGET libmamba OR TARGET libmamba-static OR TARGET libmamba-full-static))
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")

View File

@ -14,9 +14,15 @@ namespace mamba
{
if (!fs::exists(pkgs_dir))
{
// TODO : us tl::expected mechanis
throw std::runtime_error("Specified pkgs_dir does not exist\n");
}
PrefixData prefix_data(pkgs_dir);
auto sprefix_data = PrefixData::create(pkgs_dir);
if (!sprefix_data)
{
throw std::runtime_error("Specified pkgs_dir does not exist\n");
}
PrefixData& prefix_data = sprefix_data.value();
for (const auto& entry : fs::directory_iterator(pkgs_dir))
{
fs::path repodata_record_json = entry.path() / "info" / "repodata_record.json";
@ -38,7 +44,7 @@ namespace mamba
std::vector<std::string> channel_urls = ctx.channels;
std::vector<std::shared_ptr<MSubdirData>> subdirs;
std::vector<MSubdirData> subdirs;
MultiDownloadTarget multi_dl;
std::vector<std::pair<int, int>> priorities;
@ -53,10 +59,18 @@ namespace mamba
{
for (auto& [platform, url] : channel->platform_urls(true))
{
auto sdir = std::make_shared<MSubdirData>(*channel, platform, url, package_caches);
auto sdires = MSubdirData::create(*channel, platform, url, package_caches);
if (!sdires.has_value())
{
// TODO: error handling
continue;
}
// auto sdir = std::make_shared<MSubdirData>(*channel, platform, url,
// package_caches);
auto sdir = std::move(sdires).value();
multi_dl.add(sdir->target());
subdirs.push_back(sdir);
multi_dl.add(sdir.target());
subdirs.push_back(std::move(sdir));
if (ctx.channel_priority == ChannelPriority::kDisabled)
{
priorities.push_back(std::make_pair(0, 0));
@ -90,22 +104,22 @@ namespace mamba
for (std::size_t i = 0; i < subdirs.size(); ++i)
{
auto& subdir = subdirs[i];
if (!subdir->loaded())
if (!subdir.loaded())
{
if (ctx.offline || !mamba::ends_with(subdir->name(), "/noarch"))
if (ctx.offline || !mamba::ends_with(subdir.name(), "/noarch"))
{
continue;
}
else
{
throw std::runtime_error("Subdir " + subdir->name() + " not loaded!");
throw std::runtime_error("Subdir " + subdir.name() + " not loaded!");
}
}
auto& prio = priorities[i];
try
{
MRepo& repo = subdir->create_repo(pool);
MRepo& repo = subdir.create_repo(pool);
repo.set_priority(prio.first, prio.second);
}
catch (std::runtime_error& e)
@ -113,14 +127,14 @@ namespace mamba
if (is_retry & RETRY_SUBDIR_FETCH)
{
std::stringstream ss;
ss << "Could not load repodata.json for " << subdir->name() << " after retry."
ss << "Could not load repodata.json for " << subdir.name() << " after retry."
<< "Please check repodata source. Exiting." << std::endl;
throw std::runtime_error(ss.str());
}
LOG_WARNING << "Could not load repodata.json for " << subdir->name()
LOG_WARNING << "Could not load repodata.json for " << subdir.name()
<< ". Deleting cache, and retrying.";
subdir->clear_cache();
subdir.clear_cache();
loading_failed = true;
}
}

View File

@ -358,8 +358,13 @@ namespace mamba
MPool pool;
load_channels(pool, package_caches, is_retry);
PrefixData prefix_data(ctx.target_prefix);
auto sprefix_data = PrefixData::create(ctx.target_prefix);
if (!sprefix_data)
{
// TODO: propagate tl::expected mechanism
throw std::runtime_error("could not load prefix data");
}
PrefixData& prefix_data = sprefix_data.value();
std::vector<std::string> prefix_pkgs;
for (auto& it : prefix_data.records())
@ -463,7 +468,14 @@ namespace mamba
{
MPool pool;
auto& ctx = Context::instance();
PrefixData prefix_data(ctx.target_prefix);
auto sprefix_data = PrefixData::create(ctx.target_prefix);
if (!sprefix_data)
{
// TODO: propagate tl::expected mechanism
throw std::runtime_error("could not load prefix data");
}
PrefixData& prefix_data = sprefix_data.value();
fs::path pkgs_dirs(Context::instance().root_prefix / "pkgs");
MultiPackageCache pkg_caches({ pkgs_dirs });

View File

@ -46,7 +46,13 @@ namespace mamba
{
auto& ctx = Context::instance();
PrefixData prefix_data(ctx.target_prefix);
auto sprefix_data = PrefixData::create(ctx.target_prefix);
if (!sprefix_data)
{
// TODO: propagate tl::expected mechanism
throw std::runtime_error("could not load prefix data");
}
PrefixData& prefix_data = sprefix_data.value();
std::regex spec_pat(regex);

View File

@ -35,8 +35,13 @@ namespace mamba
if (remove_all)
{
PrefixData prefix_data(ctx.target_prefix);
auto sprefix_data = PrefixData::create(ctx.target_prefix);
if (!sprefix_data)
{
// TODO: propagate tl::expected mechanism
throw std::runtime_error("could not load prefix data");
}
PrefixData& prefix_data = sprefix_data.value();
for (const auto& package : prefix_data.records())
{
remove_specs.push_back(package.second.name);
@ -67,7 +72,13 @@ namespace mamba
throw std::runtime_error("Aborted.");
}
PrefixData prefix_data(ctx.target_prefix);
auto sprefix_data = PrefixData::create(ctx.target_prefix);
if (!sprefix_data)
{
// TODO: propagate tl::expected mechanism
throw std::runtime_error("could not load prefix data");
}
PrefixData& prefix_data = sprefix_data.value();
MPool pool;
MRepo::create(pool, prefix_data);

View File

@ -29,7 +29,13 @@ namespace mamba
MultiPackageCache package_caches(ctx.pkgs_dirs);
if (use_local)
{
auto prefix_data = PrefixData(ctx.target_prefix);
auto sprefix_data = PrefixData::create(ctx.target_prefix);
if (!sprefix_data)
{
// TODO: propagate tl::expected mechanism
throw std::runtime_error("could not load prefix data");
}
PrefixData& prefix_data = sprefix_data.value();
MRepo::create(pool, prefix_data);
Console::stream() << "Loaded current active prefix: " << ctx.target_prefix << std::endl;
}

View File

@ -37,7 +37,13 @@ namespace mamba
load_channels(pool, package_caches, 0);
PrefixData prefix_data(ctx.target_prefix);
auto sprefix_data = PrefixData::create(ctx.target_prefix);
if (!sprefix_data)
{
// TODO: propagate tl::expected mechanism
throw std::runtime_error("could not load prefix data");
}
PrefixData& prefix_data = sprefix_data.value();
std::vector<std::string> prefix_pkgs;
for (auto& it : prefix_data.records())

View File

@ -152,6 +152,72 @@ namespace mamba
init_curl_target(m_url);
}
DownloadTarget::~DownloadTarget()
{
curl_easy_cleanup(m_handle);
curl_slist_free_all(m_headers);
}
DownloadTarget::DownloadTarget(DownloadTarget&& rhs)
: result(std::move(rhs.result))
, failed(std::move(rhs.failed))
, http_status(std::move(rhs.http_status))
, downloaded_size(std::move(rhs.downloaded_size))
, avg_speed(std::move(rhs.avg_speed))
, final_url(std::move(rhs.final_url))
, etag(std::move(rhs.etag))
, mod(std::move(rhs.mod))
, cache_control(std::move(rhs.cache_control))
, m_finalize_callback(std::move(rhs.m_finalize_callback))
, m_name(std::move(rhs.m_name))
, m_filename(std::move(rhs.m_filename))
, m_url(std::move(rhs.m_url))
, m_expected_size(std::move(rhs.m_expected_size))
, m_next_retry(std::move(rhs.m_next_retry))
, m_retry_wait_seconds(std::move(rhs.m_retry_wait_seconds))
, m_retries(std::move(rhs.m_retries))
, m_handle(std::move(rhs.m_handle))
, m_headers(std::move(rhs.m_headers))
, m_has_progress_bar(std::move(rhs.m_has_progress_bar))
, m_ignore_failure(std::move(rhs.m_ignore_failure))
, m_progress_bar(std::move(rhs.m_progress_bar))
, m_file(std::move(rhs.m_file))
{
rhs.m_handle = nullptr;
rhs.m_headers = nullptr;
std::copy(rhs.m_errbuf, rhs.m_errbuf + CURL_ERROR_SIZE, m_errbuf);
}
DownloadTarget& DownloadTarget::operator=(DownloadTarget&& rhs)
{
using std::swap;
swap(result, rhs.result);
swap(failed, rhs.failed);
swap(http_status, rhs.http_status);
swap(downloaded_size, rhs.downloaded_size);
swap(avg_speed, rhs.avg_speed);
swap(final_url, rhs.final_url);
swap(etag, rhs.etag);
swap(mod, rhs.mod);
swap(cache_control, rhs.cache_control);
swap(m_finalize_callback, m_finalize_callback);
swap(m_name, rhs.m_name);
swap(m_filename, rhs.m_filename);
swap(m_url, rhs.m_url);
swap(m_expected_size, rhs.m_expected_size);
swap(m_next_retry, rhs.m_next_retry);
swap(m_retry_wait_seconds, rhs.m_retry_wait_seconds);
swap(m_retries, rhs.m_retries);
swap(m_handle, rhs.m_handle);
swap(m_headers, rhs.m_headers);
swap(m_has_progress_bar, rhs.m_has_progress_bar);
swap(m_ignore_failure, rhs.m_ignore_failure);
swap(m_progress_bar, rhs.m_progress_bar);
swap(m_errbuf, rhs.m_errbuf);
swap(m_file, rhs.m_file);
return *this;
}
void DownloadTarget::init_curl_handle(CURL* handle, const std::string& url)
{
curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
@ -237,7 +303,6 @@ namespace mamba
return 0;
}
void DownloadTarget::init_curl_target(const std::string& url)
{
init_curl_handle(m_handle, url);
@ -307,11 +372,6 @@ namespace mamba
}
}
DownloadTarget::~DownloadTarget()
{
curl_easy_cleanup(m_handle);
curl_slist_free_all(m_headers);
}
size_t DownloadTarget::write_callback(char* ptr, size_t size, size_t nmemb, void* self)
{
@ -613,7 +673,9 @@ namespace mamba
bool ret = true;
if (m_finalize_callback)
{
ret = m_finalize_callback();
}
else
{
if (m_has_progress_bar)

View File

@ -14,6 +14,24 @@
namespace mamba
{
auto PrefixData::create(const fs::path& prefix_path) -> expected<PrefixData>
{
try
{
return PrefixData(prefix_path);
}
catch (std::exception& e)
{
return tl::make_unexpected(mamba_error(e.what(), prefixdata_error::load));
}
catch (...)
{
return tl::make_unexpected(mamba_error("Unkown error when trying to load prefix data "
+ std::string(prefix_path),
prefixdata_error::unknown));
}
}
PrefixData::PrefixData(const fs::path& prefix_path)
: m_history(prefix_path)
, m_prefix_path(prefix_path)

View File

@ -160,17 +160,39 @@ namespace mamba
}
auto MSubdirData::create(const Channel& channel,
const std::string& platform,
const std::string& url,
MultiPackageCache& caches,
const std::string& repodata_fn) -> expected<MSubdirData>
{
try
{
return MSubdirData(channel, platform, url, caches, repodata_fn);
}
catch (std::exception& e)
{
return tl::make_unexpected(mamba_error(e.what(), subdirdata_error::load));
}
catch (...)
{
return tl::make_unexpected(mamba_error(
"Unkown error when trying to load subdir data " + url, subdirdata_error::unknown));
}
}
MSubdirData::MSubdirData(const Channel& channel,
const std::string& platform,
const std::string& url,
MultiPackageCache& caches,
const std::string& repodata_fn)
: m_progress_bar(ProgressProxy())
: m_target(nullptr)
, m_progress_bar()
, m_loaded(false)
, m_download_complete(false)
, m_repodata_url(concat(url, "/", repodata_fn))
, m_name(concat(channel.canonical_name(), "/", platform))
, m_caches(caches)
, p_caches(&caches)
, m_is_noarch(platform == "noarch")
, p_channel(&channel)
{
@ -179,6 +201,63 @@ namespace mamba
load();
}
MSubdirData::MSubdirData(MSubdirData&& rhs)
: m_target(std::move(rhs.m_target))
, m_json_cache_valid(rhs.m_json_cache_valid)
, m_solv_cache_valid(rhs.m_solv_cache_valid)
, m_valid_cache_path(std::move(rhs.m_valid_cache_path))
, m_expired_cache_path(std::move(rhs.m_expired_cache_path))
, m_progress_bar(std::move(rhs.m_progress_bar))
, m_loaded(rhs.m_loaded)
, m_download_complete(rhs.m_download_complete)
, m_repodata_url(std::move(rhs.m_repodata_url))
, m_name(std::move(rhs.m_name))
, m_json_fn(std::move(rhs.m_json_fn))
, m_solv_fn(std::move(rhs.m_solv_fn))
, p_caches(rhs.p_caches)
, m_is_noarch(rhs.m_is_noarch)
, m_mod_etag(std::move(rhs.m_mod_etag))
, m_temp_file(std::move(rhs.m_temp_file))
, p_channel(rhs.p_channel)
{
if (m_target != nullptr)
{
m_target->set_finalize_callback(&MSubdirData::finalize_transfer, this);
}
}
MSubdirData& MSubdirData::operator=(MSubdirData&& rhs)
{
using std::swap;
swap(m_target, rhs.m_target);
swap(m_json_cache_valid, rhs.m_json_cache_valid);
swap(m_solv_cache_valid, rhs.m_solv_cache_valid);
swap(m_valid_cache_path, rhs.m_valid_cache_path);
swap(m_expired_cache_path, rhs.m_expired_cache_path);
swap(m_progress_bar, m_progress_bar);
swap(m_loaded, rhs.m_loaded);
swap(m_download_complete, rhs.m_download_complete);
swap(m_repodata_url, rhs.m_repodata_url);
swap(m_name, rhs.m_name);
swap(m_json_fn, rhs.m_json_fn);
swap(m_solv_fn, rhs.m_solv_fn);
swap(p_caches, rhs.p_caches);
swap(m_is_noarch, rhs.m_is_noarch);
swap(m_mod_etag, rhs.m_mod_etag);
swap(m_temp_file, rhs.m_temp_file);
swap(p_channel, rhs.p_channel);
if (m_target != nullptr)
{
m_target->set_finalize_callback(&MSubdirData::finalize_transfer, this);
}
if (rhs.m_target != nullptr)
{
rhs.m_target->set_finalize_callback(&MSubdirData::finalize_transfer, &rhs);
}
return *this;
}
fs::file_time_type::duration MSubdirData::check_cache(
const fs::path& cache_file, const fs::file_time_type::clock::time_point& ref)
{
@ -216,7 +295,7 @@ namespace mamba
LOG_INFO << "Searching index cache file for repo '" << m_repodata_url << "'";
for (const auto& cache_path : m_caches.paths())
for (const auto& cache_path : p_caches->paths())
{
auto json_file = cache_path / "cache" / m_json_fn;
auto solv_file = cache_path / "cache" / m_solv_fn;
@ -366,7 +445,7 @@ namespace mamba
}
fs::path json_file, solv_file;
fs::path writable_cache_path = m_caches.first_writable_path();
fs::path writable_cache_path = p_caches->first_writable_path();
if (m_target->http_status == 304)
{

View File

@ -11,7 +11,14 @@ namespace mamba
{
std::vector<std::string> specs;
std::string pin;
PrefixData prefix_data("");
auto sprefix_data = PrefixData::create("");
if (!sprefix_data)
{
// TODO: propagate tl::expected mechanism
throw std::runtime_error("could not load prefix data");
}
PrefixData& prefix_data = sprefix_data.value();
ASSERT_EQ(prefix_data.records().size(), 0);
specs = { "python" };

View File

@ -13,7 +13,10 @@ namespace mamba
const mamba::Channel& c = mamba::make_channel("conda-forge");
mamba::MultiDownloadTarget multi_dl;
mamba::MultiPackageCache pkg_cache({ "/tmp/" });
mamba::MSubdirData cf(c, "linux-64", "file:///nonexistent/repodata.json", pkg_cache);
mamba::MSubdirData cf
= mamba::MSubdirData::create(
c, "linux-64", "file:///nonexistent/repodata.json", pkg_cache)
.value();
multi_dl.add(cf.target());
// file:// url should not retry
@ -28,7 +31,9 @@ namespace mamba
const mamba::Channel& c = mamba::make_channel("conda-forge");
mamba::MultiDownloadTarget multi_dl;
mamba::MultiPackageCache pkg_cache({ "/tmp/" });
mamba::MSubdirData cf(c, "noarch", "file:///nonexistent/repodata.json", pkg_cache);
mamba::MSubdirData cf = mamba::MSubdirData::create(
c, "noarch", "file:///nonexistent/repodata.json", pkg_cache)
.value();
multi_dl.add(cf.target());
EXPECT_THROW(multi_dl.download(MAMBA_DOWNLOAD_FAILFAST), std::runtime_error);
}

View File

@ -14,6 +14,7 @@ dependencies:
- gtest
- gmock
- cpp-filesystem >=1.5.8
- cpp-expected
- reproc-cpp
- yaml-cpp
- termcolor-cpp

View File

@ -57,7 +57,7 @@ PYBIND11_MODULE(bindings, m)
py::class_<mamba::LockFile>(m, "LockFile").def(py::init<fs::path>());
py::register_exception<mamba_error>(m, "MambaNativeException");
py::register_exception<mamba_error<unspecified_error>>(m, "MambaNativeException");
py::add_ostream_redirect(m, "ostream_redirect");
@ -236,12 +236,26 @@ PYBIND11_MODULE(bindings, m)
return res_stream.str();
});
py::register_exception<mamba_error<subdirdata_error>>(m, "SubdirDataError");
py::class_<MSubdirData>(m, "SubdirData")
.def(py::init<const Channel&,
const std::string&,
const std::string&,
MultiPackageCache&,
const std::string&>())
.def(py::init(
[](const Channel& channel,
const std::string& platform,
const std::string& url,
MultiPackageCache& caches,
const std::string& repodata_fn) -> MSubdirData
{
auto sres = MSubdirData::create(channel, platform, url, caches, repodata_fn);
if (sres.has_value())
{
return std::move(sres.value());
}
else
{
throw sres.error();
}
}))
.def("create_repo", &MSubdirData::create_repo, py::return_value_policy::reference)
.def("loaded", &MSubdirData::loaded)
.def("cache_path", &MSubdirData::cache_path);
@ -306,7 +320,19 @@ PYBIND11_MODULE(bindings, m)
.def("set_log_level", &Context::set_log_level);
py::class_<PrefixData>(m, "PrefixData")
.def(py::init<const fs::path&>())
.def(py::init(
[](const fs::path& prefix_path) -> PrefixData
{
auto sres = PrefixData::create(prefix_path);
if (sres.has_value())
{
return std::move(sres.value());
}
else
{
throw sres.error();
}
}))
.def_property_readonly("package_records", &PrefixData::records)
.def("add_packages", &PrefixData::add_packages);

View File

@ -14,6 +14,7 @@ dependencies:
- gtest
- gmock
- cpp-filesystem >=1.5.8
- cpp-expected
- reproc-cpp
- yaml-cpp
- termcolor-cpp

View File

@ -14,6 +14,7 @@ dependencies:
- gtest
- gmock
- cpp-filesystem >=1.5.8
- cpp-expected
- reproc-cpp
- yaml-cpp
- termcolor-cpp

View File

@ -66,7 +66,8 @@ set_env_command(CLI::App* com)
if (explicit_format)
{
PrefixData pd(ctx.target_prefix);
// TODO: handle error
auto pd = PrefixData::create(ctx.target_prefix).value();
auto records = pd.sorted_records();
std::cout << "# This file may be used to create an environment using:\n"
<< "# $ conda create --name <env> --file <this file>\n"
@ -87,7 +88,7 @@ set_env_command(CLI::App* com)
}
else
{
PrefixData pd(ctx.target_prefix);
auto pd = PrefixData::create(ctx.target_prefix).value();
History& hist = pd.history();
auto versions_map = pd.records();