| } | } | ||||
| } | } | ||||
| std::optional<package_info> catalog::get(const package_id& pk_id) const noexcept { | |||||
| auto& st = _stmt_cache(R"( | |||||
| SELECT | |||||
| pkg_id, | |||||
| name, | |||||
| version, | |||||
| git_url, | |||||
| git_ref, | |||||
| lm_name, | |||||
| lm_namespace | |||||
| FROM dds_cat_pkgs | |||||
| WHERE name = ? AND version = ? | |||||
| )"_sql); | |||||
| st.reset(); | |||||
| st.bindings = std::forward_as_tuple(pk_id.name, pk_id.version.to_string()); | |||||
| auto opt_tup = sqlite3::unpack_single_opt<std::int64_t, | |||||
| std::string, | |||||
| std::string, | |||||
| std::optional<std::string>, | |||||
| std::optional<std::string>, | |||||
| std::optional<std::string>, | |||||
| std::optional<std::string>>(st); | |||||
| if (!opt_tup) { | |||||
| return std::nullopt; | |||||
| } | |||||
| const auto& [pkg_id, name, version, git_url, git_ref, lm_name, lm_namespace] = *opt_tup; | |||||
| assert(pk_id.name == name); | |||||
| assert(pk_id.version == semver::version::parse(version)); | |||||
| assert(git_url); | |||||
| assert(git_ref); | |||||
| auto deps = sqlite3::exec_iter<std::string, std::string>( // | |||||
| _stmt_cache, | |||||
| R"( | |||||
| SELECT dep_name, low | |||||
| FROM dds_cat_pkg_deps | |||||
| WHERE pkg_id = ? | |||||
| )"_sql, | |||||
| std::tie(pkg_id)) | |||||
| | ranges::views::transform([](auto&& pair) { | |||||
| const auto& [name, ver] = pair; | |||||
| return dependency{name, semver::version::parse(ver)}; | |||||
| }) // | |||||
| | ranges::to_vector; | |||||
| return package_info{ | |||||
| pk_id, | |||||
| deps, | |||||
| git_remote_listing{ | |||||
| *git_url, | |||||
| *git_ref, | |||||
| lm_name ? std::make_optional(lm::usage{*lm_name, *lm_namespace}) : std::nullopt, | |||||
| }, | |||||
| }; | |||||
| } | |||||
| std::vector<package_id> catalog::by_name(std::string_view sv) const noexcept { | std::vector<package_id> catalog::by_name(std::string_view sv) const noexcept { | ||||
| return sqlite3::exec_iter<std::string, std::string>( // | return sqlite3::exec_iter<std::string, std::string>( // | ||||
| _stmt_cache, | _stmt_cache, |
| #include <dds/package_id.hpp> | #include <dds/package_id.hpp> | ||||
| #include <dds/repo/remote.hpp> | #include <dds/repo/remote.hpp> | ||||
| #include <dds/util/fs.hpp> | #include <dds/util/fs.hpp> | ||||
| #include <dds/catalog/git.hpp> | |||||
| #include <neo/sqlite3/database.hpp> | #include <neo/sqlite3/database.hpp> | ||||
| #include <neo/sqlite3/statement.hpp> | #include <neo/sqlite3/statement.hpp> | ||||
| static catalog open(path_ref db_path) { return open(db_path.string()); } | static catalog open(path_ref db_path) { return open(db_path.string()); } | ||||
| void store(const package_info& info); | void store(const package_info& info); | ||||
| std::optional<package_info> get(const package_id& id) const noexcept; | |||||
| std::vector<package_id> by_name(std::string_view sv) const noexcept; | std::vector<package_id> by_name(std::string_view sv) const noexcept; | ||||
| std::vector<dependency> dependencies_of(const package_id& pkg) const noexcept; | std::vector<dependency> dependencies_of(const package_id& pkg) const noexcept; |
| #include "./get.hpp" | |||||
| #include <dds/catalog/catalog.hpp> | |||||
| #include <dds/proc.hpp> | |||||
| #include <spdlog/spdlog.h> | |||||
| using namespace dds; | |||||
| namespace { | |||||
| temporary_sdist do_pull_sdist(const package_info& listing, const git_remote_listing& git) { | |||||
| auto tmpdir = dds::temporary_dir::create(); | |||||
| using namespace std::literals; | |||||
| spdlog::info("Cloning Git repository: {} [{}] ...", git.url, git.ref); | |||||
| auto command = {"git"s, | |||||
| "clone"s, | |||||
| "--depth=1"s, | |||||
| "--branch"s, | |||||
| git.ref, | |||||
| git.url, | |||||
| tmpdir.path().generic_string()}; | |||||
| auto git_res = run_proc(command); | |||||
| if (!git_res.okay()) { | |||||
| throw std::runtime_error( | |||||
| fmt::format("Git clone operation failed [Git command: {}] [Exitted {}]:\n{}", | |||||
| quote_command(command), | |||||
| git_res.retc, | |||||
| git_res.output)); | |||||
| } | |||||
| spdlog::info("Create sdist from clone ..."); | |||||
| if (git.auto_lib.has_value()) { | |||||
| spdlog::info("Generating library data automatically"); | |||||
| auto pkg_strm = dds::open(tmpdir.path() / "package.dds", std::ios::binary | std::ios::out); | |||||
| pkg_strm << "Name: " << listing.ident.name << '\n' // | |||||
| << "Version: " << listing.ident.version.to_string() << '\n' // | |||||
| << "Namespace: " << git.auto_lib->namespace_; | |||||
| auto lib_strm = dds::open(tmpdir.path() / "library.dds", std::ios::binary | std::ios::out); | |||||
| lib_strm << "Name: " << git.auto_lib->name; | |||||
| } | |||||
| sdist_params params; | |||||
| params.project_dir = tmpdir.path(); | |||||
| auto sd_tmp_dir = dds::temporary_dir::create(); | |||||
| params.dest_path = sd_tmp_dir.path(); | |||||
| params.force = true; | |||||
| auto sd = create_sdist(params); | |||||
| return {sd_tmp_dir, sd}; | |||||
| } | |||||
| } // namespace | |||||
| temporary_sdist dds::get_package_sdist(const package_info& pkg) { | |||||
| auto tsd = std::visit([&](auto&& remote) { return do_pull_sdist(pkg, remote); }, pkg.remote); | |||||
| if (!(tsd.sdist.manifest.pk_id == pkg.ident)) { | |||||
| throw std::runtime_error(fmt::format( | |||||
| "The package name@version in the generated sdist does not match the name listed in " | |||||
| "the remote listing file (expected '{}', but got '{}')", | |||||
| pkg.ident.to_string(), | |||||
| tsd.sdist.manifest.pk_id.to_string())); | |||||
| } | |||||
| return tsd; | |||||
| } |
| #pragma once | |||||
| #include <dds/sdist.hpp> | |||||
| #include <dds/temp.hpp> | |||||
| namespace dds { | |||||
| struct package_info; | |||||
| struct temporary_sdist { | |||||
| temporary_dir tmpdir; | |||||
| dds::sdist sdist; | |||||
| }; | |||||
| temporary_sdist get_package_sdist(const package_info&); | |||||
| } // namespace dds |
| #pragma once | |||||
| #include <dds/util/fs.hpp> | |||||
| #include <libman/package.hpp> | |||||
| #include <optional> | |||||
| #include <string> | |||||
| namespace dds { | |||||
| struct git_remote_listing { | |||||
| std::string url; | |||||
| std::string ref; | |||||
| std::optional<lm::usage> auto_lib; | |||||
| void clone(path_ref path) const; | |||||
| }; | |||||
| } // namespace dds |
| #include <dds/build.hpp> | #include <dds/build.hpp> | ||||
| #include <dds/catalog/catalog.hpp> | #include <dds/catalog/catalog.hpp> | ||||
| #include <dds/catalog/get.hpp> | |||||
| #include <dds/repo/remote.hpp> | #include <dds/repo/remote.hpp> | ||||
| #include <dds/repo/repo.hpp> | #include <dds/repo/repo.hpp> | ||||
| #include <dds/sdist.hpp> | #include <dds/sdist.hpp> | ||||
| "requirement", | "requirement", | ||||
| "The package IDs to obtain"}; | "The package IDs to obtain"}; | ||||
| int run() { return 23; } | |||||
| int run() { | |||||
| auto cat = dds::catalog::open(path.Get()); | |||||
| for (const auto& req : requirements.Get()) { | |||||
| auto id = dds::package_id::parse(req); | |||||
| auto info = cat.get(id); | |||||
| if (!info) { | |||||
| throw std::runtime_error( | |||||
| fmt::format("No package in the catalog matched the given ID")); | |||||
| } | |||||
| dds::get_package_sdist(*info); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| } get{*this}; | } get{*this}; | ||||
| int run() { | int run() { |
| #include <dds/sdist.hpp> | #include <dds/sdist.hpp> | ||||
| #include <dds/temp.hpp> | #include <dds/temp.hpp> | ||||
| #include <dds/catalog/git.hpp> | |||||
| #include <dds/catalog/get.hpp> | |||||
| #include <libman/library.hpp> | #include <libman/library.hpp> | ||||
| #include <semver/version.hpp> | #include <semver/version.hpp> | ||||
| namespace dds { | namespace dds { | ||||
| struct temporary_sdist { | |||||
| temporary_dir tmpdir; | |||||
| dds::sdist sdist; | |||||
| }; | |||||
| struct git_remote_listing { | |||||
| std::string url; | |||||
| std::string ref; | |||||
| std::optional<lm::usage> auto_lib; | |||||
| void clone(path_ref path) const; | |||||
| }; | |||||
| struct remote_listing { | struct remote_listing { | ||||
| package_id pk_id; | package_id pk_id; | ||||
| std::variant<git_remote_listing> remote; | std::variant<git_remote_listing> remote; |
| import json | |||||
| from tests import dds, DDS | |||||
| from tests.fileutil import ensure_dir | |||||
| def test_get(dds: DDS): | |||||
| dds.scope.enter_context(ensure_dir(dds.build_dir)) | |||||
| cat_path = dds.build_dir / 'catalog.db' | |||||
| dds.catalog_create(cat_path) | |||||
| json_path = dds.build_dir / 'catalog.json' | |||||
| import_data = { | |||||
| 'version': 1, | |||||
| 'packages': { | |||||
| 'neo-sqlite3': { | |||||
| '0.2.2': { | |||||
| 'depends': {}, | |||||
| 'git': { | |||||
| 'url': 'https://github.com/vector-of-bool/neo-sqlite3.git', | |||||
| 'ref': '0.2.2', | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| } | |||||
| dds.scope.enter_context( | |||||
| dds.set_contents(json_path, | |||||
| json.dumps(import_data).encode())) | |||||
| dds.catalog_import(cat_path, json_path) | |||||
| dds.catalog_get(cat_path, 'neo-sqlite3@0.2.2') |