[&](std::error_code ec, e_human_message msg, boost::leaf::e_file_name file) { | [&](std::error_code ec, e_human_message msg, boost::leaf::e_file_name file) { | ||||
dds_log(error, "Error: .bold.red[{}]"_styled, msg.value); | dds_log(error, "Error: .bold.red[{}]"_styled, msg.value); | ||||
dds_log(error, | dds_log(error, | ||||
"Failed to access file [.bold.red[{}]]: .br.yellow[{}]", | |||||
"Failed to access file [.bold.red[{}]]: .br.yellow[{}]"_styled, | |||||
file.value, | file.value, | ||||
ec.message()); | ec.message()); | ||||
write_error_marker("failed-package-json5-scan"); | write_error_marker("failed-package-json5-scan"); |
#include <dds/util/result.hpp> | #include <dds/util/result.hpp> | ||||
#include <boost/leaf/handle_exception.hpp> | #include <boost/leaf/handle_exception.hpp> | ||||
#include <fansi/styled.hpp> | |||||
#include <json5/parse_data.hpp> | #include <json5/parse_data.hpp> | ||||
#include <neo/assert.hpp> | #include <neo/assert.hpp> | ||||
#include <neo/url/parse.hpp> | #include <neo/url/parse.hpp> | ||||
#include <iostream> | #include <iostream> | ||||
#include <string_view> | #include <string_view> | ||||
using namespace fansi::literals; | |||||
namespace dds::cli::cmd { | namespace dds::cli::cmd { | ||||
struct e_importing { | |||||
std::string value; | |||||
}; | |||||
static int _pkg_import(const options& opts) { | static int _pkg_import(const options& opts) { | ||||
return pkg_cache::with_cache( // | return pkg_cache::with_cache( // | ||||
opts.pkg_cache_dir.value_or(pkg_cache::default_local_path()), | opts.pkg_cache_dir.value_or(pkg_cache::default_local_path()), | ||||
pkg_cache_flags::write_lock | pkg_cache_flags::create_if_absent, | pkg_cache_flags::write_lock | pkg_cache_flags::create_if_absent, | ||||
[&](auto repo) { | [&](auto repo) { | ||||
for (std::string_view tgz_where : opts.pkg.import.items) { | |||||
neo_assertion_breadcrumbs("Importing sdist", tgz_where); | |||||
auto tmp_sd | |||||
= (tgz_where.starts_with("http://") || tgz_where.starts_with("https://")) | |||||
? download_expand_sdist_targz(tgz_where) | |||||
: expand_sdist_targz(tgz_where); | |||||
neo_assertion_breadcrumbs("Importing from temporary directory", | |||||
tmp_sd.tmpdir.path()); | |||||
repo.add_sdist(tmp_sd.sdist, dds::if_exists(opts.if_exists)); | |||||
// Lambda to import an sdist object | |||||
auto import_sdist | |||||
= [&](const sdist& sd) { repo.import_sdist(sd, dds::if_exists(opts.if_exists)); }; | |||||
for (std::string_view sdist_where : opts.pkg.import.items) { | |||||
DDS_E_SCOPE(e_importing{std::string(sdist_where)}); | |||||
neo_assertion_breadcrumbs("Importing sdist", sdist_where); | |||||
if (sdist_where.starts_with("http://") || sdist_where.starts_with("https://")) { | |||||
auto tmp_sd = download_expand_sdist_targz(sdist_where); | |||||
import_sdist(tmp_sd.sdist); | |||||
} else if (fs::is_directory(sdist_where)) { | |||||
auto sd = sdist::from_directory(sdist_where); | |||||
import_sdist(sd); | |||||
} else { | |||||
auto tmp_sd = expand_sdist_targz(sdist_where); | |||||
import_sdist(tmp_sd.sdist); | |||||
} | |||||
} | } | ||||
if (opts.pkg.import.from_stdin) { | if (opts.pkg.import.from_stdin) { | ||||
auto tmp_sd = dds::expand_sdist_from_istream(std::cin, "<stdin>"); | auto tmp_sd = dds::expand_sdist_from_istream(std::cin, "<stdin>"); | ||||
repo.add_sdist(tmp_sd.sdist, dds::if_exists(opts.if_exists)); | |||||
repo.import_sdist(tmp_sd.sdist, dds::if_exists(opts.if_exists)); | |||||
} | } | ||||
return 0; | return 0; | ||||
}); | }); | ||||
[](dds::e_sqlite3_error_exc e) { | [](dds::e_sqlite3_error_exc e) { | ||||
dds_log(error, "Unexpected database error: {}", e.message); | dds_log(error, "Unexpected database error: {}", e.message); | ||||
return 1; | return 1; | ||||
}, | |||||
[](e_system_error_exc err, e_importing what) { | |||||
dds_log( | |||||
error, | |||||
"Error while importing source distribution from [.bold.red[{}]]: .br.yellow[{}]"_styled, | |||||
what.value, | |||||
err.message); | |||||
return 1; | |||||
}); | }); | ||||
} | } | ||||
} // namespace dds::cli::cmd | } // namespace dds::cli::cmd |
return {writeable, dirpath, std::move(entries)}; | return {writeable, dirpath, std::move(entries)}; | ||||
} | } | ||||
void pkg_cache::add_sdist(const sdist& sd, if_exists ife_action) { | |||||
void pkg_cache::import_sdist(const sdist& sd, if_exists ife_action) { | |||||
neo_assertion_breadcrumbs("Importing sdist archive", sd.manifest.id.to_string()); | neo_assertion_breadcrumbs("Importing sdist archive", sd.manifest.id.to_string()); | ||||
if (!_write_enabled) { | if (!_write_enabled) { | ||||
dds_log(critical, | dds_log(critical, | ||||
dds_log(info, msg + " - Replacing"); | dds_log(info, msg + " - Replacing"); | ||||
} | } | ||||
} | } | ||||
// Create a temporary location where we are creating it | |||||
auto tmp_copy = sd_dest; | auto tmp_copy = sd_dest; | ||||
tmp_copy.replace_filename(".tmp-import"); | tmp_copy.replace_filename(".tmp-import"); | ||||
if (fs::exists(tmp_copy)) { | if (fs::exists(tmp_copy)) { | ||||
fs::remove_all(tmp_copy); | fs::remove_all(tmp_copy); | ||||
} | } | ||||
fs::create_directories(tmp_copy.parent_path()); | fs::create_directories(tmp_copy.parent_path()); | ||||
fs::copy(sd.path, tmp_copy, fs::copy_options::recursive); | |||||
// Re-create an sdist from the given sdist. This will prune non-sdist files, rather than just | |||||
// fs::copy_all from the source, which may contain extras. | |||||
sdist_params params{ | |||||
.project_dir = sd.path, | |||||
.dest_path = tmp_copy, | |||||
.include_apps = true, | |||||
.include_tests = true, | |||||
}; | |||||
create_sdist_in_dir(tmp_copy, params); | |||||
// Swap out the temporary to the final location | |||||
if (fs::exists(sd_dest)) { | if (fs::exists(sd_dest)) { | ||||
fs::remove_all(sd_dest); | fs::remove_all(sd_dest); | ||||
} | } | ||||
fs::rename(tmp_copy, sd_dest); | fs::rename(tmp_copy, sd_dest); | ||||
_sdists.insert(sdist::from_directory(sd_dest)); | _sdists.insert(sdist::from_directory(sd_dest)); | ||||
dds_log(info, "Source distribution '{}' successfully exported", sd.manifest.id.to_string()); | |||||
dds_log(info, "Source distribution for '{}' successfully imported", sd.manifest.id.to_string()); | |||||
} | } | ||||
const sdist* pkg_cache::find(const pkg_id& pkg) const noexcept { | const sdist* pkg_cache::find(const pkg_id& pkg) const noexcept { |
static fs::path default_local_path() noexcept; | static fs::path default_local_path() noexcept; | ||||
void add_sdist(const sdist&, if_exists = if_exists::throw_exc); | |||||
void import_sdist(const sdist&, if_exists = if_exists::throw_exc); | |||||
const sdist* find(const pkg_id& pk) const noexcept; | const sdist* find(const pkg_id& pk) const noexcept; | ||||
dds_log(info, "Download package: {}", inf.ident.to_string()); | dds_log(info, "Download package: {}", inf.ident.to_string()); | ||||
auto tsd = get_package_sdist(inf); | auto tsd = get_package_sdist(inf); | ||||
std::scoped_lock lk{repo_mut}; | std::scoped_lock lk{repo_mut}; | ||||
repo.add_sdist(tsd.sdist, if_exists::throw_exc); | |||||
repo.import_sdist(tsd.sdist, if_exists::throw_exc); | |||||
}); | }); | ||||
if (!okay) { | if (!okay) { |
def test_import_sdist_stdin(_test_pkg: Tuple[Path, Project]) -> None: | def test_import_sdist_stdin(_test_pkg: Tuple[Path, Project]) -> None: | ||||
sdist, project = _test_pkg | sdist, project = _test_pkg | ||||
repo_content_path = project.dds.repo_dir / 'foo@1.2.3' | |||||
pipe = subprocess.Popen( | pipe = subprocess.Popen( | ||||
list(proc.flatten_cmd([ | list(proc.flatten_cmd([ | ||||
project.dds.path, | project.dds.path, | ||||
rc = pipe.wait() | rc = pipe.wait() | ||||
assert rc == 0, 'Subprocess failed' | assert rc == 0, 'Subprocess failed' | ||||
_check_import(project.dds.repo_dir / 'foo@1.2.3') | |||||
def test_import_sdist_dir(test_project: Project) -> None: | |||||
test_project.dds.run(['pkg', 'import', test_project.dds.repo_dir_arg, test_project.root]) | |||||
_check_import(test_project.dds.repo_dir / 'foo@1.2.3') | |||||
def _check_import(repo_content_path: Path) -> None: | |||||
assert repo_content_path.is_dir(), \ | assert repo_content_path.is_dir(), \ | ||||
'The package did not appear in the local cache' | 'The package did not appear in the local cache' | ||||
assert repo_content_path.joinpath('library.jsonc').is_file(), \ | assert repo_content_path.joinpath('library.jsonc').is_file(), \ |