mirror of https://github.com/mamba-org/mamba.git
159 lines
5.4 KiB
C++
159 lines
5.4 KiB
C++
// 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 "common_options.hpp"
|
|
#include "constructor.hpp"
|
|
|
|
#include "mamba/api/configuration.hpp"
|
|
#include "mamba/api/install.hpp"
|
|
|
|
#include "mamba/core/package_handling.hpp"
|
|
#include "mamba/core/util.hpp"
|
|
#include "mamba/core/package_info.hpp"
|
|
|
|
|
|
using namespace mamba; // NOLINT(build/namespaces)
|
|
|
|
void
|
|
init_constructor_parser(CLI::App* subcom)
|
|
{
|
|
auto& config = Configuration::instance();
|
|
|
|
auto& prefix = config.insert(Configurable("constructor_prefix", fs::path(""))
|
|
.group("cli")
|
|
.description("Extract the conda pkgs in <prefix>/pkgs"));
|
|
|
|
subcom->add_option("-p,--prefix", prefix.set_cli_config(""), prefix.description());
|
|
|
|
auto& extract_conda_pkgs
|
|
= config.insert(Configurable("constructor_extract_conda_pkgs", false)
|
|
.group("cli")
|
|
.description("Extract the conda pkgs in <prefix>/pkgs"));
|
|
subcom->add_flag("--extract-conda-pkgs",
|
|
extract_conda_pkgs.set_cli_config(0),
|
|
extract_conda_pkgs.description());
|
|
|
|
auto& extract_tarball = config.insert(Configurable("constructor_extract_tarball", false)
|
|
.group("cli")
|
|
.description("Extract given tarball into prefix"));
|
|
subcom->add_flag(
|
|
"--extract-tarball", extract_tarball.set_cli_config(0), extract_tarball.description());
|
|
}
|
|
|
|
void
|
|
set_constructor_command(CLI::App* subcom)
|
|
{
|
|
init_constructor_parser(subcom);
|
|
|
|
subcom->callback([&]() {
|
|
auto& c = Configuration::instance();
|
|
|
|
auto& prefix = c.at("constructor_prefix").compute().value<fs::path>();
|
|
auto& extract_conda_pkgs = c.at("constructor_extract_conda_pkgs").compute().value<bool>();
|
|
auto& extract_tarball = c.at("constructor_extract_tarball").compute().value<bool>();
|
|
|
|
construct(prefix, extract_conda_pkgs, extract_tarball);
|
|
});
|
|
}
|
|
|
|
|
|
void
|
|
construct(const fs::path& prefix, bool extract_conda_pkgs, bool extract_tarball)
|
|
{
|
|
auto& config = Configuration::instance();
|
|
|
|
config.at("show_banner").set_value(false);
|
|
config.at("use_target_prefix_fallback").set_value(true);
|
|
config.at("target_prefix_checks")
|
|
.set_value(MAMBA_ALLOW_EXISTING_PREFIX | MAMBA_ALLOW_MISSING_PREFIX);
|
|
config.load();
|
|
|
|
if (extract_conda_pkgs)
|
|
{
|
|
fs::path pkgs_dir = prefix / "pkgs";
|
|
fs::path urls_file = pkgs_dir / "urls";
|
|
|
|
auto [package_details, _] = detail::parse_urls_to_package_info(read_lines(urls_file));
|
|
|
|
for (const auto& entry : fs::directory_iterator(pkgs_dir))
|
|
{
|
|
if (is_package_file(entry.path().filename().string()))
|
|
{
|
|
LOG_TRACE << "Extracting " << entry.path().filename() << std::endl;
|
|
std::cout << "Extracting " << entry.path().filename() << std::endl;
|
|
|
|
fs::path base_path = extract(entry.path());
|
|
|
|
fs::path repodata_record_path = base_path / "info" / "repodata_record.json";
|
|
fs::path index_path = base_path / "info" / "index.json";
|
|
|
|
nlohmann::json index;
|
|
std::ifstream index_file(index_path);
|
|
index_file >> index;
|
|
|
|
std::string pkg_name = index["name"];
|
|
|
|
index["fn"] = entry.path().filename();
|
|
for (const auto& pkg_info : package_details)
|
|
{
|
|
if (pkg_info.fn == entry.path().filename())
|
|
{
|
|
index["url"] = pkg_info.url;
|
|
index["channel"] = pkg_info.channel;
|
|
index["size"] = fs::file_size(entry.path());
|
|
if (!pkg_info.md5.empty())
|
|
{
|
|
index["md5"] = pkg_info.md5;
|
|
}
|
|
if (!pkg_info.sha256.empty())
|
|
{
|
|
index["sha256"] = pkg_info.sha256;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
LOG_TRACE << "Writing " << repodata_record_path;
|
|
std::ofstream repodata_record(repodata_record_path);
|
|
repodata_record << index.dump(4);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (extract_tarball)
|
|
{
|
|
fs::path extract_tarball_path = prefix / "_tmp.tar.bz2";
|
|
read_binary_from_stdin_and_write_to_file(extract_tarball_path);
|
|
extract_archive(extract_tarball_path, prefix);
|
|
fs::remove(extract_tarball_path);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
read_binary_from_stdin_and_write_to_file(fs::path& filename)
|
|
{
|
|
std::ofstream out_stream = open_ofstream(filename, std::ofstream::binary);
|
|
// Need to reopen stdin as binary
|
|
std::freopen(nullptr, "rb", stdin);
|
|
if (std::ferror(stdin))
|
|
{
|
|
throw std::runtime_error("Re-opening stdin as binary failed.");
|
|
}
|
|
std::size_t len;
|
|
std::array<char, 1024> buffer;
|
|
|
|
while ((len = std::fread(buffer.data(), sizeof(char), buffer.size(), stdin)) > 0)
|
|
{
|
|
if (std::ferror(stdin) && !std::feof(stdin))
|
|
{
|
|
throw std::runtime_error("Reading from stdin failed.");
|
|
}
|
|
out_stream.write(buffer.data(), len);
|
|
}
|
|
out_stream.close();
|
|
}
|