@@ -6,4 +6,5 @@ Uses: Niebler/range-v3 | |||
Uses: nlohmann/json | |||
Uses: neo/buffer | |||
Uses: neo/sqlite3 | |||
Uses: semver/semver | |||
Uses: semver/semver | |||
Uses: pubgrub/pubgrub |
@@ -4,9 +4,10 @@ Version: 0.1.0 | |||
Depends: neo-buffer 0.1.0 | |||
Depends: spdlog 1.4.2 | |||
Depends: ms-wil 2019.11.10 | |||
Depends: range-v3 0.9.1 | |||
Depends: range-v3 0.10.0 | |||
Depends: nlohmann-json 3.7.1 | |||
Depends: neo-sqlite3 0.2.2 | |||
Depends: semver 0.2.0 | |||
Depends: semver 0.2.1 | |||
Depends: pubgrub 0.1.2 | |||
Test-Driver: Catch-Main |
@@ -1,4 +1,5 @@ | |||
Remote-Package: range-v3 0.9.1; git url=https://github.com/ericniebler/range-v3.git ref=0.9.1 auto=Niebler/range-v3 | |||
Remote-Package: range-v3 0.10.0; git url=https://github.com/ericniebler/range-v3.git ref=0.10.0 auto=Niebler/range-v3 | |||
Remote-Package: spdlog 1.4.2; git url=https://github.com/gabime/spdlog.git ref=v1.4.2 auto=spdlog/spdlog | |||
# Even a shallow clone of nlohmann-json is HUGE. This fork has only the minimal | |||
@@ -11,4 +12,5 @@ Remote-Package: ms-wil 2019.11.10; git url=https://github.com/vector-of-bool/wil | |||
Remote-Package: neo-buffer 0.1.0; git url=https://github.com/vector-of-bool/neo-buffer.git ref=develop | |||
Remote-Package: neo-sqlite3 0.2.2; git url=https://github.com/vector-of-bool/neo-sqlite3.git ref=0.2.2 | |||
Remote-Package: semver 0.2.0; git url=https://github.com/vector-of-bool/semver.git ref=0.2.0 | |||
Remote-Package: semver 0.2.1; git url=https://github.com/vector-of-bool/semver.git ref=0.2.1 | |||
Remote-Package: pubgrub 0.1.2; git url=https://github.com/vector-of-bool/pubgrub.git ref=0.1.2 |
@@ -1,5 +1,7 @@ | |||
#include "./catalog.hpp" | |||
#include <dds/solve/solve.hpp> | |||
#include <neo/sqlite3/exec.hpp> | |||
#include <neo/sqlite3/iter_tuples.hpp> | |||
#include <neo/sqlite3/single.hpp> | |||
@@ -157,11 +159,16 @@ void catalog::store(const package_info& pkg) { | |||
)"_sql); | |||
for (const auto& dep : pkg.deps) { | |||
new_dep_st.reset(); | |||
if (dep.versions.num_intervals() != 1) { | |||
throw std::runtime_error( | |||
"Package dependency may only contain a single version interval"); | |||
} | |||
auto iv_1 = *dep.versions.iter_intervals().begin(); | |||
sqlite3::exec(new_dep_st, | |||
std::forward_as_tuple(db_pkg_id, | |||
dep.name, | |||
dep.version.to_string(), | |||
"[placeholder]")); | |||
iv_1.low.to_string(), | |||
iv_1.high.to_string())); | |||
} | |||
} | |||
@@ -196,23 +203,11 @@ std::optional<package_info> catalog::get(const package_id& pk_id) const noexcept | |||
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; | |||
auto deps = dependencies_of(pk_id); | |||
return package_info{ | |||
pk_id, | |||
deps, | |||
std::move(deps), | |||
git_remote_listing{ | |||
*git_url, | |||
*git_ref, | |||
@@ -239,6 +234,7 @@ std::vector<package_id> catalog::by_name(std::string_view sv) const noexcept { | |||
std::vector<dependency> catalog::dependencies_of(const package_id& pkg) const noexcept { | |||
return sqlite3::exec_iter<std::string, | |||
std::string, | |||
std::string>( // | |||
_stmt_cache, | |||
R"( | |||
@@ -247,15 +243,15 @@ std::vector<dependency> catalog::dependencies_of(const package_id& pkg) const no | |||
FROM dds_cat_pkgs | |||
WHERE name = ? AND version = ? | |||
) | |||
SELECT dep_name, low | |||
SELECT dep_name, low, high | |||
FROM dds_cat_pkg_deps | |||
WHERE pkg_id IN this_pkg_id | |||
ORDER BY dep_name | |||
)"_sql, | |||
std::forward_as_tuple(pkg.name, pkg.version.to_string())) // | |||
| ranges::views::transform([](auto&& pair) { | |||
auto& [name, ver] = pair; | |||
return dependency{name, semver::version::parse(ver)}; | |||
auto& [name, low, high] = pair; | |||
return dependency{name, {semver::version::parse(low), semver::version::parse(high)}}; | |||
}) // | |||
| ranges::to_vector; | |||
} | |||
@@ -308,9 +304,10 @@ void catalog::import_json_str(std::string_view content) { | |||
pkg_name, | |||
version_, | |||
dep_name)); | |||
auto range = semver::range::parse(std::string(dep_version)); | |||
info.deps.push_back({ | |||
std::string(dep_name), | |||
semver::version::parse(std::string(dep_version)), | |||
{range.low(), range.high()}, | |||
}); | |||
} | |||
@@ -334,3 +331,9 @@ void catalog::import_json_str(std::string_view content) { | |||
} | |||
} | |||
} | |||
std::vector<package_id> catalog::solve_requirements(const std::vector<dependency>& deps) const { | |||
return dds::solve(deps, | |||
[&](std::string_view pkg_name) { return this->by_name(pkg_name); }, | |||
[&](const package_id& pkg) { return this->dependencies_of(pkg); }); | |||
} |
@@ -1,9 +1,9 @@ | |||
#pragma once | |||
#include <dds/catalog/git.hpp> | |||
#include <dds/deps.hpp> | |||
#include <dds/package_id.hpp> | |||
#include <dds/util/fs.hpp> | |||
#include <dds/catalog/git.hpp> | |||
#include <neo/sqlite3/database.hpp> | |||
#include <neo/sqlite3/statement.hpp> | |||
@@ -38,7 +38,7 @@ public: | |||
static catalog open(const std::string& db_path); | |||
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; | |||
@@ -49,6 +49,8 @@ public: | |||
auto content = dds::slurp_file(json_path); | |||
import_json_str(content); | |||
} | |||
std::vector<package_id> solve_requirements(const std::vector<dependency>& deps) const; | |||
}; | |||
} // namespace dds |
@@ -34,8 +34,8 @@ TEST_CASE_METHOD(catalog_test_case, "Package requirements") { | |||
db.store(dds::package_info{ | |||
dds::package_id{"foo", semver::version::parse("1.2.3")}, | |||
{ | |||
{"bar", semver::version::parse("1.2.5")}, | |||
{"baz", semver::version::parse("5.3.2")}, | |||
{"bar", {semver::version::parse("1.2.3"), semver::version::parse("1.4.0")}}, | |||
{"baz", {semver::version::parse("5.3.0"), semver::version::parse("6.0.0")}}, | |||
}, | |||
dds::git_remote_listing{"http://example.com", "master", std::nullopt}, | |||
}); | |||
@@ -55,7 +55,7 @@ TEST_CASE_METHOD(catalog_test_case, "Parse JSON repo") { | |||
"foo": { | |||
"1.2.3": { | |||
"depends": { | |||
"bar": "4.2.1" | |||
"bar": "~4.2.1" | |||
}, | |||
"git": { | |||
"url": "http://example.com", | |||
@@ -72,5 +72,43 @@ TEST_CASE_METHOD(catalog_test_case, "Parse JSON repo") { | |||
auto deps = db.dependencies_of(pkgs[0]); | |||
REQUIRE(deps.size() == 1); | |||
CHECK(deps[0].name == "bar"); | |||
CHECK(deps[0].version == semver::version::parse("4.2.1")); | |||
CHECK(deps[0].versions | |||
== dds::version_range_set{semver::version::parse("4.2.1"), | |||
semver::version::parse("4.3.0")}); | |||
} | |||
TEST_CASE_METHOD(catalog_test_case, "Simple solve") { | |||
db.import_json_str(R"({ | |||
"version": 1, | |||
"packages": { | |||
"foo": { | |||
"1.2.3": { | |||
"depends": { | |||
"bar": "~4.2.1" | |||
}, | |||
"git": { | |||
"url": "http://example.com", | |||
"ref": "master" | |||
} | |||
} | |||
}, | |||
"bar": { | |||
"4.2.3": { | |||
"depends": {}, | |||
"git": { | |||
"url": "http://example.com", | |||
"ref": "master" | |||
} | |||
} | |||
} | |||
} | |||
})"); | |||
auto sln = db.solve_requirements({{"foo", | |||
dds::version_range_set{semver::version::parse("1.0.0"), | |||
semver::version::parse("2.0.0")}}}); | |||
REQUIRE(sln.size() == 2); | |||
CHECK(sln[0].name == "foo"); | |||
CHECK(sln[0].version == semver::version::parse("1.2.3")); | |||
CHECK(sln[1].name == "bar"); | |||
CHECK(sln[1].version == semver::version::parse("4.2.3")); | |||
} |
@@ -227,7 +227,8 @@ struct cli_catalog { | |||
std::vector<dds::dependency> deps; | |||
for (const auto& dep : this->deps.Get()) { | |||
auto dep_id = dds::package_id::parse(dep); | |||
deps.push_back({dep_id.name, dep_id.version}); | |||
assert(false && "TODO"); | |||
// deps.push_back({dep_id.name, dep_id.version}); | |||
} | |||
dds::package_info info{ident, std::move(deps), {}}; | |||
@@ -540,7 +541,7 @@ struct cli_deps { | |||
int run() { | |||
const auto man = parent.load_package_manifest(); | |||
for (const auto& dep : man.dependencies) { | |||
std::cout << dep.name << " " << dep.version.to_string() << '\n'; | |||
std::cout << dep.name << " " << dep.versions << '\n'; | |||
} | |||
return 0; | |||
} | |||
@@ -556,31 +557,29 @@ struct cli_deps { | |||
repo_path_flag repo_where{cmd}; | |||
catalog_path_flag catalog_path{cmd}; | |||
int run() { | |||
auto man = parent.load_package_manifest(); | |||
auto catalog = catalog_path.open(); | |||
bool failed = false; | |||
auto man = parent.load_package_manifest(); | |||
auto catalog = catalog_path.open(); | |||
bool failed = false; | |||
auto solved_deps = catalog.solve_requirements(man.dependencies); | |||
dds::repository::with_repository( // | |||
repo_where.Get(), | |||
dds::repo_flags::write_lock | dds::repo_flags::create_if_absent, | |||
[&](dds::repository repo) { | |||
for (auto& dep : man.dependencies) { | |||
auto exists = !!repo.find(dep.name, dep.version); | |||
for (const dds::package_id& pk : solved_deps) { | |||
auto exists = !!repo.find(pk); | |||
if (!exists) { | |||
spdlog::info("Pull remote: {}@{}", dep.name, dep.version.to_string()); | |||
auto opt_pkg = catalog.get(dds::package_id{dep.name, dep.version}); | |||
spdlog::info("Pull remote: {}", pk.to_string()); | |||
auto opt_pkg = catalog.get(pk); | |||
if (opt_pkg) { | |||
auto tsd = dds::get_package_sdist(*opt_pkg); | |||
repo.add_sdist(tsd.sdist, dds::if_exists::ignore); | |||
} else { | |||
spdlog::error("No remote listing for {}@{}", | |||
dep.name, | |||
dep.version.to_string()); | |||
spdlog::error("No remote listing for {}", pk.to_string()); | |||
failed = true; | |||
} | |||
} else { | |||
spdlog::info("Okay: {} {}", dep.name, dep.version.to_string()); | |||
spdlog::info("Okay: {}", pk.to_string()); | |||
} | |||
} | |||
}); | |||
@@ -621,9 +620,7 @@ struct cli_deps { | |||
repo_where.Get(), | |||
dds::repo_flags::read, | |||
[&](dds::repository repo) { | |||
return find_dependencies(repo, | |||
man.dependencies.begin(), | |||
man.dependencies.end()); | |||
return repo.solve(man.dependencies); | |||
}); | |||
auto tc = tc_filepath.get_toolchain(); |
@@ -10,6 +10,7 @@ | |||
#include <range/v3/range/conversion.hpp> | |||
#include <range/v3/view/transform.hpp> | |||
#include <spdlog/spdlog.h> | |||
#include <spdlog/fmt/ostr.h> | |||
#include <cctype> | |||
#include <map> | |||
@@ -29,49 +30,16 @@ dependency dependency::parse_depends_string(std::string_view str) { | |||
auto name = trim_view(std::string_view(str_begin, str_iter - str_begin)); | |||
auto version_str = trim_view(std::string_view(str_iter, str_end - str_iter)); | |||
semver::version version; | |||
try { | |||
version = semver::version::parse(version_str); | |||
} catch (const semver::invalid_version&) { | |||
throw std::runtime_error( | |||
fmt::format("Invalid version string '{}' in dependency declaration '{}' (Should be a " | |||
"semver string. See https://semver.org/ for info)", | |||
version_str, | |||
str)); | |||
auto rng = semver::range::parse_restricted(version_str); | |||
return dependency{std::string(name), {rng.low(), rng.high()}}; | |||
} catch (const semver::invalid_range&) { | |||
throw std::runtime_error(fmt::format( | |||
"Invalid version range string '{}' in dependency declaration '{}' (Should be a " | |||
"semver range string. See https://semver.org/ for info)", | |||
version_str, | |||
str)); | |||
} | |||
return dependency{std::string(name), version}; | |||
} | |||
std::vector<sdist> dds::find_dependencies(const repository& repo, const dependency& dep) { | |||
std::vector<sdist> acc; | |||
detail::do_find_deps(repo, dep, acc); | |||
return acc; | |||
} | |||
void detail::do_find_deps(const repository& repo, const dependency& dep, std::vector<sdist>& sd) { | |||
auto sdist_opt = repo.find(dep.name, dep.version); | |||
if (!sdist_opt) { | |||
throw std::runtime_error( | |||
fmt::format("Unable to find dependency to satisfy requirement: {} {}", | |||
dep.name, | |||
dep.version.to_string())); | |||
} | |||
const sdist& new_sd = *sdist_opt; | |||
for (const auto& inner_dep : new_sd.manifest.dependencies) { | |||
do_find_deps(repo, inner_dep, sd); | |||
} | |||
auto insert_point = std::partition_point(sd.begin(), sd.end(), [&](const sdist& cand) { | |||
return cand.path < new_sd.path; | |||
}); | |||
if (insert_point != sd.end() | |||
&& insert_point->manifest.pk_id.name == new_sd.manifest.pk_id.name) { | |||
if (insert_point->manifest.pk_id.version != new_sd.manifest.pk_id.version) { | |||
assert(false && "Version conflict resolution not implemented yet"); | |||
std::terminate(); | |||
} | |||
return; | |||
} | |||
sd.insert(insert_point, std::move(new_sd)); | |||
} | |||
using sdist_index_type = std::map<std::string, std::reference_wrapper<const sdist>>; |
@@ -2,6 +2,8 @@ | |||
#include <dds/build/plan/full.hpp> | |||
#include <pubgrub/interval.hpp> | |||
#include <semver/range.hpp> | |||
#include <semver/version.hpp> | |||
#include <string_view> | |||
@@ -18,30 +20,15 @@ enum class version_strength { | |||
major, | |||
}; | |||
using version_range_set = pubgrub::interval_set<semver::version>; | |||
struct dependency { | |||
std::string name; | |||
semver::version version; | |||
std::string name; | |||
version_range_set versions; | |||
static dependency parse_depends_string(std::string_view str); | |||
}; | |||
namespace detail { | |||
void do_find_deps(const repository&, const dependency& dep, std::vector<sdist>& acc); | |||
} // namespace detail | |||
std::vector<sdist> find_dependencies(const repository& repo, const dependency& dep); | |||
template <typename Iter, typename Snt> | |||
inline std::vector<sdist> find_dependencies(const repository& repo, Iter it, Snt stop) { | |||
std::vector<sdist> acc; | |||
while (it != stop) { | |||
detail::do_find_deps(repo, *it++, acc); | |||
} | |||
return acc; | |||
} | |||
build_plan create_deps_build_plan(const std::vector<sdist>& deps, build_env_ref env); | |||
void write_libman_index(path_ref where, const build_plan& plan, const build_env& env); |
@@ -1,11 +1,13 @@ | |||
#include "./repo.hpp" | |||
#include <dds/sdist.hpp> | |||
#include <dds/solve/solve.hpp> | |||
#include <dds/util/paths.hpp> | |||
#include <dds/util/string.hpp> | |||
#include <spdlog/spdlog.h> | |||
#include <range/v3/action/sort.hpp> | |||
#include <range/v3/range/conversion.hpp> | |||
#include <range/v3/view/filter.hpp> | |||
#include <range/v3/view/transform.hpp> | |||
@@ -96,10 +98,37 @@ void repository::add_sdist(const sdist& sd, if_exists ife_action) { | |||
spdlog::info("Source distribution '{}' successfully exported", sd.manifest.pk_id.to_string()); | |||
} | |||
const sdist* repository::find(std::string_view name, semver::version ver) const noexcept { | |||
auto found = _sdists.find(std::tie(name, ver)); | |||
const sdist* repository::find(const package_id& pkg) const noexcept { | |||
auto found = _sdists.find(pkg); | |||
if (found == _sdists.end()) { | |||
return nullptr; | |||
} | |||
return &*found; | |||
} | |||
std::vector<sdist> repository::solve(const std::vector<dependency>& deps) const { | |||
auto ids = dds::solve(deps, | |||
[&](std::string_view name) -> std::vector<package_id> { | |||
auto items = ranges::views::all(_sdists) // | |||
| ranges::views::filter([&](const sdist& sd) { | |||
return sd.manifest.pk_id.name == name; | |||
}) | |||
| ranges::views::transform( | |||
[](const sdist& sd) { return sd.manifest.pk_id; }) | |||
| ranges::to_vector; | |||
ranges::sort(items, std::less<>{}); | |||
return items; | |||
}, | |||
[&](const package_id& pkg_id) { | |||
auto found = find(pkg_id); | |||
assert(found); | |||
return found->manifest.dependencies; | |||
}); | |||
return ids // | |||
| ranges::views::transform([&](const package_id& pk_id) { | |||
auto found = find(pk_id); | |||
assert(found); | |||
return *found; | |||
}) // | |||
| ranges::to_vector; | |||
} |
@@ -80,7 +80,7 @@ public: | |||
void add_sdist(const sdist&, if_exists = if_exists::throw_exc); | |||
const sdist* find(std::string_view name, semver::version ver) const noexcept; | |||
const sdist* find(const package_id& pk) const noexcept; | |||
auto iter_sdists() const noexcept { | |||
class ret { | |||
@@ -95,6 +95,8 @@ public: | |||
} r{_sdists}; | |||
return r; | |||
} | |||
std::vector<sdist> solve(const std::vector<dependency>& deps) const; | |||
}; | |||
} // namespace dds |
@@ -30,15 +30,11 @@ inline constexpr struct sdist_compare_t { | |||
bool operator()(const sdist& lhs, const sdist& rhs) const { | |||
return lhs.manifest.pk_id < rhs.manifest.pk_id; | |||
} | |||
template <typename Name, typename Version> | |||
bool operator()(const sdist& lhs, const std::tuple<Name, Version>& rhs) const { | |||
auto&& [name, ver] = rhs; | |||
return lhs.manifest.pk_id < package_id{name, ver}; | |||
bool operator()(const sdist& lhs, const package_id& rhs) const { | |||
return lhs.manifest.pk_id < rhs; | |||
} | |||
template <typename Name, typename Version> | |||
bool operator()(const std::tuple<Name, Version>& lhs, const sdist& rhs) const { | |||
auto&& [name, ver] = lhs; | |||
return package_id{name, ver} < rhs.manifest.pk_id; | |||
bool operator()(const package_id& lhs, const sdist& rhs) const { | |||
return lhs < rhs.manifest.pk_id; | |||
} | |||
using is_transparent = int; | |||
} sdist_compare; |
@@ -0,0 +1,102 @@ | |||
#include "./solve.hpp" | |||
#include <pubgrub/solve.hpp> | |||
#include <range/v3/range/conversion.hpp> | |||
#include <range/v3/view/transform.hpp> | |||
using namespace dds; | |||
namespace { | |||
struct req_type { | |||
dependency dep; | |||
using req_ref = const req_type&; | |||
bool implied_by(req_ref other) const noexcept { | |||
return dep.versions.contains(other.dep.versions); | |||
} | |||
bool excludes(req_ref other) const noexcept { | |||
return dep.versions.disjoint(other.dep.versions); | |||
} | |||
std::optional<req_type> intersection(req_ref other) const noexcept { | |||
auto range = dep.versions.intersection(other.dep.versions); | |||
if (range.empty()) { | |||
return std::nullopt; | |||
} | |||
return req_type{dependency{dep.name, std::move(range)}}; | |||
} | |||
std::optional<req_type> union_(req_ref other) const noexcept { | |||
auto range = dep.versions.union_(other.dep.versions); | |||
if (range.empty()) { | |||
return std::nullopt; | |||
} | |||
return req_type{dependency{dep.name, std::move(range)}}; | |||
} | |||
std::optional<req_type> difference(req_ref other) const noexcept { | |||
auto range = dep.versions.difference(other.dep.versions); | |||
if (range.empty()) { | |||
return std::nullopt; | |||
} | |||
return req_type{dependency{dep.name, std::move(range)}}; | |||
} | |||
auto key() const noexcept { return dep.name; } | |||
friend bool operator==(req_ref lhs, req_ref rhs) noexcept { | |||
return lhs.dep.name == rhs.dep.name && lhs.dep.versions == rhs.dep.versions; | |||
} | |||
}; | |||
auto as_pkg_id(const req_type& req) { | |||
const version_range_set& versions = req.dep.versions; | |||
assert(versions.num_intervals() == 1); | |||
return package_id{req.dep.name, (*versions.iter_intervals().begin()).low}; | |||
} | |||
struct solver_provider { | |||
pkg_id_provider_fn& pkgs_for_name; | |||
deps_provider_fn& deps_for_pkg; | |||
mutable std::map<std::string, std::vector<package_id>> pkgs_by_name = {}; | |||
std::optional<req_type> best_candidate(const req_type& req) const { | |||
auto found = pkgs_by_name.find(req.dep.name); | |||
if (found == pkgs_by_name.end()) { | |||
found = pkgs_by_name.emplace(req.dep.name, pkgs_for_name(req.dep.name)).first; | |||
} | |||
auto& vec = found->second; | |||
auto cand = std::find_if(vec.cbegin(), vec.cend(), [&](const package_id& pk) { | |||
return req.dep.versions.contains(pk.version); | |||
}); | |||
if (cand == vec.cend()) { | |||
return std::nullopt; | |||
} | |||
return req_type{dependency{cand->name, {cand->version, cand->version.next_after()}}}; | |||
} | |||
std::vector<req_type> requirements_of(const req_type& req) const { | |||
auto pk_id = as_pkg_id(req); | |||
auto deps = deps_for_pkg(pk_id); | |||
return deps // | |||
| ranges::views::transform([](const dependency& dep) { return req_type{dep}; }) // | |||
| ranges::to_vector; | |||
} | |||
}; | |||
} // namespace | |||
std::vector<package_id> dds::solve(const std::vector<dependency>& deps, | |||
pkg_id_provider_fn pkgs_prov, | |||
deps_provider_fn deps_prov) { | |||
auto wrap_req | |||
= deps | ranges::v3::views::transform([](const dependency& dep) { return req_type{dep}; }); | |||
auto solution = pubgrub::solve(wrap_req, solver_provider{pkgs_prov, deps_prov}); | |||
return solution | ranges::views::transform(as_pkg_id) | ranges::to_vector; | |||
} |
@@ -0,0 +1,16 @@ | |||
#pragma once | |||
#include <dds/deps.hpp> | |||
#include <dds/package_id.hpp> | |||
#include <functional> | |||
namespace dds { | |||
using pkg_id_provider_fn = std::function<std::vector<package_id>(std::string_view)>; | |||
using deps_provider_fn = std::function<std::vector<dependency>(const package_id& pk)>; | |||
std::vector<package_id> | |||
solve(const std::vector<dependency>& deps, pkg_id_provider_fn, deps_provider_fn); | |||
} // namespace dds |
@@ -58,6 +58,7 @@ public: | |||
} | |||
inline bool operator!=(const pair_iterator& o) const noexcept { return _iter != o._iter; } | |||
inline bool operator==(const pair_iterator& o) const noexcept { return _iter == o._iter; } | |||
auto begin() const noexcept { return *this; } | |||
auto end() const noexcept { return pair_iterator(_end, _end, _key); } |
@@ -2,7 +2,8 @@ Compiler-ID: GNU | |||
C++-Version: C++17 | |||
C-Compiler: gcc-9 | |||
C++-Compiler: g++-9 | |||
Flags: -D SPDLOG_COMPILED_LIB -fconcepts -Werror=return-type | |||
# Range-v3 0.10.0 contains an accidental conversion warning | |||
Flags: -D SPDLOG_COMPILED_LIB -fconcepts -Werror=return-type -Wno-conversion | |||
Link-Flags: -static-libgcc -static-libstdc++ | |||
Debug: True | |||
Compiler-Launcher: ccache |