| @@ -44,7 +44,7 @@ int pkg_create(const options& opts) { | |||
| [&](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, | |||
| "Failed to access file [.bold.red[{}]]: .br.yellow[{}]", | |||
| "Failed to access file [.bold.red[{}]]: .br.yellow[{}]"_styled, | |||
| file.value, | |||
| ec.message()); | |||
| write_error_marker("failed-package-json5-scan"); | |||
| @@ -5,6 +5,7 @@ | |||
| #include <dds/util/result.hpp> | |||
| #include <boost/leaf/handle_exception.hpp> | |||
| #include <fansi/styled.hpp> | |||
| #include <json5/parse_data.hpp> | |||
| #include <neo/assert.hpp> | |||
| #include <neo/url/parse.hpp> | |||
| @@ -12,25 +13,40 @@ | |||
| #include <iostream> | |||
| #include <string_view> | |||
| using namespace fansi::literals; | |||
| namespace dds::cli::cmd { | |||
| struct e_importing { | |||
| std::string value; | |||
| }; | |||
| static int _pkg_import(const options& opts) { | |||
| return pkg_cache::with_cache( // | |||
| opts.pkg_cache_dir.value_or(pkg_cache::default_local_path()), | |||
| pkg_cache_flags::write_lock | pkg_cache_flags::create_if_absent, | |||
| [&](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) { | |||
| 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; | |||
| }); | |||
| @@ -52,6 +68,14 @@ int pkg_import(const options& opts) { | |||
| [](dds::e_sqlite3_error_exc e) { | |||
| dds_log(error, "Unexpected database error: {}", e.message); | |||
| 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 | |||
| @@ -59,7 +59,7 @@ pkg_cache pkg_cache::_open_for_directory(bool writeable, path_ref dirpath) { | |||
| 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()); | |||
| if (!_write_enabled) { | |||
| dds_log(critical, | |||
| @@ -83,19 +83,32 @@ void pkg_cache::add_sdist(const sdist& sd, if_exists ife_action) { | |||
| dds_log(info, msg + " - Replacing"); | |||
| } | |||
| } | |||
| // Create a temporary location where we are creating it | |||
| auto tmp_copy = sd_dest; | |||
| tmp_copy.replace_filename(".tmp-import"); | |||
| if (fs::exists(tmp_copy)) { | |||
| fs::remove_all(tmp_copy); | |||
| } | |||
| 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)) { | |||
| fs::remove_all(sd_dest); | |||
| } | |||
| fs::rename(tmp_copy, 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 { | |||
| @@ -81,7 +81,7 @@ public: | |||
| 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; | |||
| @@ -62,7 +62,7 @@ void dds::get_all(const std::vector<pkg_id>& pkgs, pkg_cache& repo, const pkg_db | |||
| dds_log(info, "Download package: {}", inf.ident.to_string()); | |||
| auto tsd = get_package_sdist(inf); | |||
| 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) { | |||
| @@ -49,7 +49,6 @@ def test_import_sdist_archive(_test_pkg: Tuple[Path, Project]) -> None: | |||
| def test_import_sdist_stdin(_test_pkg: Tuple[Path, Project]) -> None: | |||
| sdist, project = _test_pkg | |||
| repo_content_path = project.dds.repo_dir / 'foo@1.2.3' | |||
| pipe = subprocess.Popen( | |||
| list(proc.flatten_cmd([ | |||
| project.dds.path, | |||
| @@ -70,6 +69,15 @@ def test_import_sdist_stdin(_test_pkg: Tuple[Path, Project]) -> None: | |||
| rc = pipe.wait() | |||
| 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(), \ | |||
| 'The package did not appear in the local cache' | |||
| assert repo_content_path.joinpath('library.jsonc').is_file(), \ | |||