@@ -165,6 +165,62 @@ void catalog::store(const package_info& pkg) { | |||
} | |||
} | |||
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 { | |||
return sqlite3::exec_iter<std::string, std::string>( // | |||
_stmt_cache, |
@@ -4,6 +4,7 @@ | |||
#include <dds/package_id.hpp> | |||
#include <dds/repo/remote.hpp> | |||
#include <dds/util/fs.hpp> | |||
#include <dds/catalog/git.hpp> | |||
#include <neo/sqlite3/database.hpp> | |||
#include <neo/sqlite3/statement.hpp> | |||
@@ -38,6 +39,7 @@ public: | |||
static catalog open(path_ref db_path) { return open(db_path.string()); } | |||
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<dependency> dependencies_of(const package_id& pkg) const noexcept; |
@@ -0,0 +1,63 @@ | |||
#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; | |||
} |
@@ -0,0 +1,17 @@ | |||
#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 |
@@ -0,0 +1,20 @@ | |||
#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 |
@@ -1,5 +1,6 @@ | |||
#include <dds/build.hpp> | |||
#include <dds/catalog/catalog.hpp> | |||
#include <dds/catalog/get.hpp> | |||
#include <dds/repo/remote.hpp> | |||
#include <dds/repo/repo.hpp> | |||
#include <dds/sdist.hpp> | |||
@@ -159,7 +160,19 @@ struct cli_catalog { | |||
"requirement", | |||
"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}; | |||
int run() { |
@@ -4,6 +4,9 @@ | |||
#include <dds/sdist.hpp> | |||
#include <dds/temp.hpp> | |||
#include <dds/catalog/git.hpp> | |||
#include <dds/catalog/get.hpp> | |||
#include <libman/library.hpp> | |||
#include <semver/version.hpp> | |||
@@ -15,19 +18,6 @@ | |||
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 { | |||
package_id pk_id; | |||
std::variant<git_remote_listing> remote; |
@@ -0,0 +1,33 @@ | |||
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') |