@@ -0,0 +1,79 @@ | |||
{ | |||
"version": 1, | |||
"packages": { | |||
"range-v3": { | |||
"0.10.0": { | |||
"git": { | |||
"url": "https://github.com/ericniebler/range-v3.git", | |||
"ref": "0.10.0", | |||
"auto-lib": "Niebler/range-v3" | |||
}, | |||
"depends": {} | |||
} | |||
}, | |||
"spdlog": { | |||
"1.4.2": { | |||
"git": { | |||
"url": "https://github.com/gabime/spdlog.git", | |||
"ref": "v1.4.2", | |||
"auto-lib": "spdlog/spdlog" | |||
}, | |||
"depends": {} | |||
} | |||
}, | |||
"nlohmann-json": { | |||
"3.7.1": { | |||
"git": { | |||
"url": "https://github.com/vector-of-bool/json.git", | |||
"ref": "dds/3.7.1" | |||
}, | |||
"depends": {} | |||
} | |||
}, | |||
"ms-wil": { | |||
"2019.11.10": { | |||
"git": { | |||
"url": "https://github.com/vector-of-bool/wil.git", | |||
"ref": "dds/2019.11.10" | |||
}, | |||
"depends": {} | |||
} | |||
}, | |||
"neo-buffer": { | |||
"0.1.0": { | |||
"git": { | |||
"url": "https://github.com/vector-of-bool/neo-buffer.git", | |||
"ref": "develop" | |||
}, | |||
"depends": {} | |||
} | |||
}, | |||
"neo-sqlite3": { | |||
"0.2.2": { | |||
"git": { | |||
"url": "https://github.com/vector-of-bool/neo-sqlite3.git", | |||
"ref": "0.2.2" | |||
}, | |||
"depends": {} | |||
} | |||
}, | |||
"semver": { | |||
"0.2.1": { | |||
"git": { | |||
"url": "https://github.com/vector-of-bool/semver.git", | |||
"ref": "0.2.1" | |||
}, | |||
"depends": {} | |||
} | |||
}, | |||
"pubgrub": { | |||
"0.1.2": { | |||
"git": { | |||
"url": "https://github.com/vector-of-bool/pubgrub.git", | |||
"ref": "0.1.2" | |||
}, | |||
"depends": {} | |||
} | |||
} | |||
} | |||
} |
@@ -1,4 +1,3 @@ | |||
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 | |||
@@ -9,9 +9,14 @@ | |||
#include <libman/index.hpp> | |||
#include <libman/parse.hpp> | |||
#include <range/v3/algorithm/transform.hpp> | |||
#include <range/v3/range/conversion.hpp> | |||
#include <range/v3/view/transform.hpp> | |||
#include <spdlog/spdlog.h> | |||
#include <array> | |||
#include <map> | |||
#include <set> | |||
#include <stdexcept> | |||
using namespace dds; | |||
@@ -185,30 +190,111 @@ void prepare_test_driver(library_build_params& lib_params, | |||
} | |||
} | |||
void add_ureqs(usage_requirement_map& ureqs, | |||
const sdist& sd, | |||
const library& lib, | |||
const library_plan& lib_plan, | |||
build_env_ref env) { | |||
lm::library& reqs = ureqs.add(sd.manifest.namespace_, lib.manifest().name); | |||
reqs.include_paths.push_back(lib.public_include_dir()); | |||
reqs.name = lib.manifest().name; | |||
reqs.uses = lib.manifest().uses; | |||
reqs.links = lib.manifest().links; | |||
if (lib_plan.create_archive()) { | |||
reqs.linkable_path = lib_plan.create_archive()->calc_archive_file_path(env); | |||
} | |||
// TODO: preprocessor definitions | |||
} | |||
using sdist_index_type = std::map<std::string, std::reference_wrapper<const sdist>>; | |||
using sdist_names = std::set<std::string>; | |||
void add_sdist_to_build(build_plan& plan, | |||
const sdist& sd, | |||
const sdist_index_type& sd_idx, | |||
build_env_ref env, | |||
usage_requirement_map& ureqs, | |||
sdist_names& already_added) { | |||
if (already_added.find(sd.manifest.pkg_id.name) != already_added.end()) { | |||
// This one has already been added | |||
return; | |||
} | |||
spdlog::debug("Adding dependent build: {}", sd.manifest.pkg_id.name); | |||
// Ensure that ever dependency is loaded up first) | |||
for (const auto& dep : sd.manifest.dependencies) { | |||
auto other = sd_idx.find(dep.name); | |||
assert(other != sd_idx.end() | |||
&& "Failed to load a transitive dependency shortly after initializing them. What?"); | |||
add_sdist_to_build(plan, other->second, sd_idx, env, ureqs, already_added); | |||
} | |||
// Record that we have been processed | |||
already_added.insert(sd.manifest.pkg_id.name); | |||
// Finally, actually add the package: | |||
auto& pkg = plan.add_package(package_plan(sd.manifest.pkg_id.name, sd.manifest.namespace_)); | |||
auto libs = collect_libraries(sd.path); | |||
for (const auto& lib : libs) { | |||
shared_compile_file_rules comp_rules = lib.base_compile_rules(); | |||
library_build_params lib_params; | |||
lib_params.out_subdir = fs::path("deps") / sd.manifest.pkg_id.name; | |||
auto lib_plan = library_plan::create(lib, lib_params, ureqs); | |||
// Create usage requirements for this libary. | |||
add_ureqs(ureqs, sd, lib, lib_plan, env); | |||
// Add it to the plan: | |||
pkg.add_library(std::move(lib_plan)); | |||
} | |||
} | |||
void add_deps_to_build(build_plan& plan, | |||
usage_requirement_map& ureqs, | |||
const build_params& params, | |||
build_env_ref env) { | |||
auto sd_idx = params.dep_sdists // | |||
| ranges::views::transform([](const auto& sd) { | |||
return std::pair(sd.manifest.pkg_id.name, std::cref(sd)); | |||
}) // | |||
| ranges::to<sdist_index_type>(); | |||
sdist_names already_added; | |||
for (const sdist& sd : params.dep_sdists) { | |||
add_sdist_to_build(plan, sd, sd_idx, env, ureqs, already_added); | |||
} | |||
} | |||
} // namespace | |||
void dds::build(const build_params& params, const package_manifest& man) { | |||
fs::create_directories(params.out_root); | |||
auto db = database::open(params.out_root / ".dds.db"); | |||
dds::build_env env{params.toolchain, params.out_root, db}; | |||
// The build plan we will fill out: | |||
build_plan plan; | |||
// Collect libraries for the current project | |||
auto libs = collect_libraries(params.root); | |||
if (!libs.size()) { | |||
spdlog::warn("Nothing found to build!"); | |||
return; | |||
} | |||
build_plan plan; | |||
auto& pkg = plan.add_package(package_plan(man.pk_id.name, man.namespace_)); | |||
usage_requirement_map ureqs; | |||
usage_requirement_map ureqs | |||
= load_usage_requirements(params.root, params.out_root, params.lm_index); | |||
if (params.existing_lm_index) { | |||
ureqs = load_usage_requirements(params.root, params.out_root, *params.existing_lm_index); | |||
} else { | |||
add_deps_to_build(plan, ureqs, params, env); | |||
} | |||
// Initialize the build plan for this project. | |||
auto& pkg = plan.add_package(package_plan(man.pkg_id.name, man.namespace_)); | |||
// assert(false && "Not ready yet!"); | |||
library_build_params lib_params; | |||
lib_params.build_tests = params.build_tests; | |||
lib_params.build_apps = params.build_apps; | |||
lib_params.enable_warnings = params.enable_warnings; | |||
fs::create_directories(params.out_root); | |||
auto db = database::open(params.out_root / ".dds.db"); | |||
dds::build_env env{params.toolchain, params.out_root, db}; | |||
if (man.test_driver) { | |||
prepare_test_driver(lib_params, params, man, env); | |||
} |
@@ -1,7 +1,7 @@ | |||
#pragma once | |||
#include <dds/build/params.hpp> | |||
#include <dds/package_manifest.hpp> | |||
#include <dds/package/manifest.hpp> | |||
namespace dds { | |||
@@ -2,21 +2,24 @@ | |||
#include <dds/toolchain/toolchain.hpp> | |||
#include <dds/util/fs.hpp> | |||
#include <dds/sdist.hpp> | |||
#include <optional> | |||
namespace dds { | |||
struct build_params { | |||
fs::path root; | |||
fs::path out_root; | |||
fs::path lm_index; | |||
dds::toolchain toolchain; | |||
bool do_export = false; | |||
bool build_tests = false; | |||
bool enable_warnings = false; | |||
bool build_apps = false; | |||
bool build_deps = false; | |||
bool generate_compdb = true; | |||
int parallel_jobs = 0; | |||
fs::path root; | |||
fs::path out_root; | |||
std::optional<fs::path> existing_lm_index; | |||
dds::toolchain toolchain; | |||
std::vector<sdist> dep_sdists; | |||
bool do_export = false; | |||
bool build_tests = false; | |||
bool enable_warnings = false; | |||
bool build_apps = false; | |||
bool generate_compdb = true; | |||
int parallel_jobs = 0; | |||
}; | |||
} // namespace dds |
@@ -9,7 +9,8 @@ | |||
using namespace dds; | |||
fs::path create_archive_plan::calc_archive_file_path(const build_env& env) const noexcept { | |||
return env.output_root / fmt::format("{}{}{}", "lib", _name, env.toolchain.archive_suffix()); | |||
return env.output_root / _subdir | |||
/ fmt::format("{}{}{}", "lib", _name, env.toolchain.archive_suffix()); | |||
} | |||
void create_archive_plan::archive(const build_env& env) const { | |||
@@ -28,6 +29,7 @@ void create_archive_plan::archive(const build_env& env) const { | |||
} | |||
spdlog::info("[{}] Archive: {}", _name, out_relpath); | |||
fs::create_directories(ar.out_path.parent_path()); | |||
auto&& [dur_ms, ar_res] = timed<std::chrono::milliseconds>([&] { return run_proc(ar_cmd); }); | |||
spdlog::info("[{}] Archive: {} - {:n}ms", _name, out_relpath, dur_ms.count()); | |||
@@ -178,6 +178,10 @@ compile_file_full realize_plan(const compile_file_plan& plan, build_env_ref env) | |||
} | |||
bool should_compile(const compile_file_full& comp, build_env_ref env) { | |||
if (!fs::exists(comp.object_file_path)) { | |||
// The output file simply doesn't exist. We have to recompile, of course. | |||
return true; | |||
} | |||
database& db = env.db; | |||
auto rb_info = get_rebuild_info(db, comp.object_file_path); | |||
if (rb_info.previous_command.empty()) { | |||
@@ -205,11 +209,12 @@ bool dds::detail::compile_all(const ref_vector<const compile_file_plan>& compile | |||
auto each_realized = // | |||
compiles // | |||
| views::transform([&](auto&& plan) { return realize_plan(plan, env); }) // | |||
| views::filter([&](auto&& real) { return should_compile(real, env); }); | |||
| views::filter([&](auto&& real) { return should_compile(real, env); }) // | |||
| ranges::to_vector; | |||
const auto total = compiles.size(); | |||
const auto total = each_realized.size(); | |||
const auto max_digits = fmt::format("{}", total).size(); | |||
compile_counter counter{{0}, total, max_digits}; | |||
compile_counter counter{{1}, total, max_digits}; | |||
std::vector<deps_info> all_new_deps; | |||
std::mutex mut; |
@@ -2,7 +2,7 @@ | |||
#include <dds/build/plan/archive.hpp> | |||
#include <dds/build/plan/exe.hpp> | |||
#include <dds/library.hpp> | |||
#include <dds/library/library.hpp> | |||
#include <dds/usage_reqs.hpp> | |||
#include <dds/util/fs.hpp> | |||
@@ -12,6 +12,17 @@ | |||
namespace dds { | |||
struct library_build_params { | |||
fs::path out_subdir; | |||
bool build_tests = false; | |||
bool build_apps = false; | |||
bool enable_warnings = false; | |||
// Extras for compiling tests: | |||
std::vector<fs::path> test_include_dirs; | |||
std::vector<fs::path> test_link_files; | |||
}; | |||
class library_plan { | |||
std::string _name; | |||
fs::path _source_root; |
@@ -30,11 +30,12 @@ void migrate_repodb_1(sqlite3::database& db) { | |||
lm_name TEXT, | |||
lm_namespace TEXT, | |||
UNIQUE(name, version), | |||
CONSTRAINT has_remote_info CHECK( | |||
CONSTRAINT has_source_info CHECK( | |||
( | |||
git_url NOT NULL | |||
AND git_ref NOT NULL | |||
) | |||
= 1 | |||
), | |||
CONSTRAINT valid_lm_info CHECK( | |||
( | |||
@@ -92,6 +93,9 @@ void ensure_migrated(sqlite3::database& db) { | |||
} // namespace | |||
catalog catalog::open(const std::string& db_path) { | |||
if (db_path != ":memory:") { | |||
fs::create_directories(fs::weakly_canonical(db_path).parent_path()); | |||
} | |||
auto db = sqlite3::database::open(db_path); | |||
try { | |||
ensure_migrated(db); | |||
@@ -211,7 +215,7 @@ std::optional<package_info> catalog::get(const package_id& pk_id) const noexcept | |||
git_remote_listing{ | |||
*git_url, | |||
*git_ref, | |||
lm_name ? std::make_optional(lm::usage{*lm_name, *lm_namespace}) : std::nullopt, | |||
lm_name ? std::make_optional(lm::usage{*lm_namespace, *lm_name}) : std::nullopt, | |||
}, | |||
}; | |||
} | |||
@@ -341,9 +345,3 @@ 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); }); | |||
} |
@@ -2,7 +2,7 @@ | |||
#include <dds/catalog/git.hpp> | |||
#include <dds/deps.hpp> | |||
#include <dds/package_id.hpp> | |||
#include <dds/package/id.hpp> | |||
#include <dds/util/fs.hpp> | |||
#include <neo/sqlite3/database.hpp> | |||
@@ -50,8 +50,6 @@ 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 |
@@ -90,39 +90,3 @@ TEST_CASE_METHOD(catalog_test_case, "Parse JSON repo") { | |||
== 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")); | |||
} |
@@ -52,12 +52,12 @@ temporary_sdist do_pull_sdist(const package_info& listing, const git_remote_list | |||
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)) { | |||
if (!(tsd.sdist.manifest.pkg_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())); | |||
tsd.sdist.manifest.pkg_id.to_string())); | |||
} | |||
return tsd; | |||
} |
@@ -276,6 +276,8 @@ struct cli_catalog { | |||
return get.run(); | |||
} else if (add.cmd) { | |||
return add.run(); | |||
} else if (list.cmd) { | |||
return list.run(); | |||
} else { | |||
assert(false); | |||
std::terminate(); | |||
@@ -310,7 +312,7 @@ struct cli_repo { | |||
int run() { | |||
auto list_contents = [&](dds::repository repo) { | |||
auto same_name = [](auto&& a, auto&& b) { | |||
return a.manifest.pk_id.name == b.manifest.pk_id.name; | |||
return a.manifest.pkg_id.name == b.manifest.pkg_id.name; | |||
}; | |||
auto all = repo.iter_sdists(); | |||
@@ -319,13 +321,13 @@ struct cli_repo { | |||
| ranges::views::transform(ranges::to_vector) // | |||
| ranges::views::transform([](auto&& grp) { | |||
assert(grp.size() > 0); | |||
return std::pair(grp[0].manifest.pk_id.name, grp); | |||
return std::pair(grp[0].manifest.pkg_id.name, grp); | |||
}); | |||
for (const auto& [name, grp] : grp_by_name) { | |||
spdlog::info("{}:", name); | |||
for (const dds::sdist& sd : grp) { | |||
spdlog::info(" - {}", sd.manifest.pk_id.version.to_string()); | |||
spdlog::info(" - {}", sd.manifest.pkg_id.version.to_string()); | |||
} | |||
} | |||
@@ -478,21 +480,21 @@ struct cli_build { | |||
common_project_flags project{cmd}; | |||
args::Flag build_tests{cmd, "build_tests", "Build and run the tests", {"tests", 'T'}}; | |||
args::Flag build_apps{cmd, "build_apps", "Build applications", {"apps", 'A'}}; | |||
args::Flag export_{cmd, "export", "Generate a library export", {"export", 'E'}}; | |||
catalog_path_flag cat_path{cmd}; | |||
repo_path_flag repo_path{cmd}; | |||
args::Flag no_tests{cmd, "no-tests", "Do not build and run tests", {"no-tests"}}; | |||
args::Flag no_apps{cmd, "no-apps", "Do not compile and link applications", {"no-apps"}}; | |||
args::Flag no_warnings{cmd, "no-warings", "Disable build warnings", {"no-warnings"}}; | |||
toolchain_flag tc_filepath{cmd}; | |||
args::Flag enable_warnings{cmd, | |||
"enable_warnings", | |||
"Enable compiler warnings", | |||
{"warnings", 'W'}}; | |||
args::Flag export_{cmd, "export", "Generate a library export", {"export", 'E'}}; | |||
path_flag lm_index{cmd, | |||
"lm_index", | |||
"Path to a libman index (usually INDEX.lmi)", | |||
{"lm-index", 'I'}, | |||
dds::fs::path()}; | |||
path_flag | |||
lm_index{cmd, | |||
"lm_index", | |||
"Path to an existing libman index from which to load deps (usually INDEX.lmi)", | |||
{"lm-index", 'I'}}; | |||
args::ValueFlag<int> num_jobs{cmd, | |||
"jobs", | |||
@@ -512,159 +514,48 @@ struct cli_build { | |||
params.out_root = out.Get(); | |||
params.toolchain = tc_filepath.get_toolchain(); | |||
params.do_export = export_.Get(); | |||
params.build_tests = build_tests.Get(); | |||
params.build_apps = build_apps.Get(); | |||
params.enable_warnings = enable_warnings.Get(); | |||
params.build_tests = !no_tests.Get(); | |||
params.build_apps = !no_apps.Get(); | |||
params.enable_warnings = !no_warnings.Get(); | |||
params.parallel_jobs = num_jobs.Get(); | |||
params.lm_index = lm_index.Get(); | |||
dds::package_manifest man; | |||
const auto man_filepath = params.root / "package.dds"; | |||
if (exists(man_filepath)) { | |||
man = dds::package_manifest::load_from_file(man_filepath); | |||
} | |||
dds::build(params, man); | |||
return 0; | |||
} | |||
}; | |||
/* | |||
######## ######## ######## ###### | |||
## ## ## ## ## ## ## | |||
## ## ## ## ## ## | |||
## ## ###### ######## ###### | |||
## ## ## ## ## | |||
## ## ## ## ## ## | |||
######## ######## ## ###### | |||
*/ | |||
struct cli_deps { | |||
cli_base& base; | |||
args::Command cmd{base.cmd_group, "deps", "Obtain/inspect/build deps for the project"}; | |||
common_flags _flags{cmd}; | |||
common_project_flags project{cmd}; | |||
args::Group deps_group{cmd, "Subcommands"}; | |||
dds::package_manifest load_package_manifest() { | |||
return dds::package_manifest::load_from_file(project.root.Get() / "package.dds"); | |||
} | |||
struct { | |||
cli_deps& parent; | |||
args::Command cmd{parent.deps_group, "ls", "List project dependencies"}; | |||
common_flags _common{cmd}; | |||
int run() { | |||
const auto man = parent.load_package_manifest(); | |||
for (const auto& dep : man.dependencies) { | |||
std::cout << dep.name << " " << dep.versions << '\n'; | |||
} | |||
return 0; | |||
} | |||
} ls{*this}; | |||
struct { | |||
cli_deps& parent; | |||
args::Command cmd{parent.deps_group, | |||
"get", | |||
"Ensure we have local copies of the project dependencies"}; | |||
common_flags _common{cmd}; | |||
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 solved_deps = catalog.solve_requirements(man.dependencies); | |||
dds::repository::with_repository( // | |||
repo_where.Get(), | |||
if (lm_index) { | |||
params.existing_lm_index = lm_index.Get(); | |||
} else { | |||
// Download and build dependencies | |||
// Build the dependencies | |||
auto cat = cat_path.open(); | |||
params.dep_sdists = dds::repository::with_repository( // | |||
this->repo_path.Get(), | |||
dds::repo_flags::write_lock | dds::repo_flags::create_if_absent, | |||
[&](dds::repository repo) { | |||
for (const dds::package_id& pk : solved_deps) { | |||
// Download dependencies | |||
auto deps = repo.solve(man.dependencies, cat); | |||
for (const dds::package_id& pk : deps) { | |||
auto exists = !!repo.find(pk); | |||
if (!exists) { | |||
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 {}", pk.to_string()); | |||
failed = true; | |||
} | |||
} else { | |||
spdlog::info("Okay: {}", pk.to_string()); | |||
spdlog::info("Download dependency: {}", pk.to_string()); | |||
auto opt_pkg = cat.get(pk); | |||
assert(opt_pkg); | |||
auto tsd = dds::get_package_sdist(*opt_pkg); | |||
repo.add_sdist(tsd.sdist, dds::if_exists::throw_exc); | |||
} | |||
} | |||
return deps // | |||
| ranges::views::transform([&](auto& id) { | |||
auto ptr = repo.find(id); | |||
assert(ptr); | |||
return *ptr; | |||
}) | |||
| ranges::to_vector; | |||
}); | |||
if (failed) { | |||
return 1; | |||
} | |||
return 0; | |||
} | |||
} get{*this}; | |||
struct { | |||
cli_deps& parent; | |||
args::Command cmd{parent.deps_group, "build", "Build project dependencies"}; | |||
common_flags _common{cmd}; | |||
path_flag build_dir{cmd, | |||
"build_dir", | |||
"Directory where build results will be stored", | |||
{"deps-build-dir"}, | |||
dds::fs::current_path() / "_build/deps"}; | |||
path_flag lmi_path{cmd, | |||
"lmi_path", | |||
"Destination for the INDEX.lmi file", | |||
{"lmi-path"}, | |||
dds::fs::current_path() / "_build/INDEX.lmi"}; | |||
args::Flag no_lmi{cmd, | |||
"no_lmi", | |||
"If specified, will not generate an INDEX.lmi", | |||
{"skip-lmi"}}; | |||
repo_path_flag repo_where{cmd}; | |||
toolchain_flag tc_filepath{cmd}; | |||
int run() { | |||
auto man = parent.load_package_manifest(); | |||
auto deps = dds::repository::with_repository( // | |||
repo_where.Get(), | |||
dds::repo_flags::read, | |||
[&](dds::repository repo) { | |||
return repo.solve(man.dependencies); | |||
}); | |||
auto tc = tc_filepath.get_toolchain(); | |||
auto bdir = build_dir.Get(); | |||
dds::fs::create_directories(bdir); | |||
auto db = dds::database::open(bdir / ".dds.db"); | |||
dds::build_env env{std::move(tc), bdir, db}; | |||
auto plan = dds::create_deps_build_plan(deps, env); | |||
plan.compile_all(env, 6); | |||
plan.archive_all(env, 6); | |||
if (!no_lmi.Get()) { | |||
write_libman_index(lmi_path.Get(), plan, env); | |||
} | |||
return 0; | |||
} | |||
} build{*this}; | |||
int run() { | |||
if (ls.cmd) { | |||
return ls.run(); | |||
} else if (build.cmd) { | |||
return build.run(); | |||
} else if (get.cmd) { | |||
return get.run(); | |||
} | |||
std::terminate(); | |||
dds::build(params, man); | |||
return 0; | |||
} | |||
}; | |||
@@ -691,7 +582,6 @@ int main(int argc, char** argv) { | |||
cli_build build{cli}; | |||
cli_sdist sdist{cli}; | |||
cli_repo repo{cli}; | |||
cli_deps deps{cli}; | |||
cli_catalog catalog{cli}; | |||
try { | |||
parser.ParseCLI(argc, argv); | |||
@@ -716,8 +606,6 @@ int main(int argc, char** argv) { | |||
return sdist.run(); | |||
} else if (repo.cmd) { | |||
return repo.run(); | |||
} else if (deps.cmd) { | |||
return deps.run(); | |||
} else if (catalog.cmd) { | |||
return catalog.run(); | |||
} else { |
@@ -41,171 +41,3 @@ dependency dependency::parse_depends_string(std::string_view str) { | |||
str)); | |||
} | |||
} | |||
using sdist_index_type = std::map<std::string, std::reference_wrapper<const sdist>>; | |||
using sdist_names = std::set<std::string>; | |||
namespace { | |||
void resolve_ureqs_(shared_compile_file_rules& rules, | |||
const package_manifest& man, | |||
const sdist_index_type& sd_idx) { | |||
for (const dependency& dep : man.dependencies) { | |||
auto found = sd_idx.find(dep.name); | |||
if (found == sd_idx.end()) { | |||
throw std::runtime_error( | |||
fmt::format("Unable to resolve dependency '{}' (required by '{}')", | |||
dep.name, | |||
man.pk_id.to_string())); | |||
} | |||
resolve_ureqs_(rules, found->second.get().manifest, sd_idx); | |||
auto lib_src = found->second.get().path / "src"; | |||
auto lib_include = found->second.get().path / "include"; | |||
if (fs::exists(lib_include)) { | |||
rules.include_dirs().push_back(lib_include); | |||
} else { | |||
rules.include_dirs().push_back(lib_src); | |||
} | |||
} | |||
} | |||
void resolve_ureqs(shared_compile_file_rules rules, | |||
const sdist& sd, | |||
const library& lib, | |||
const library_plan& lib_plan, | |||
build_env_ref env, | |||
usage_requirement_map& ureqs) { | |||
// Add the transitive requirements for this library to our compile rules. | |||
for (auto&& use : lib.manifest().uses) { | |||
ureqs.apply(rules, use.namespace_, use.name); | |||
} | |||
// Create usage requirements for this libary. | |||
lm::library& reqs = ureqs.add(sd.manifest.namespace_, lib.manifest().name); | |||
reqs.include_paths.push_back(lib.public_include_dir()); | |||
reqs.name = lib.manifest().name; | |||
reqs.uses = lib.manifest().uses; | |||
reqs.links = lib.manifest().links; | |||
if (lib_plan.create_archive()) { | |||
reqs.linkable_path = lib_plan.create_archive()->calc_archive_file_path(env); | |||
} | |||
// TODO: preprocessor definitions | |||
} | |||
void add_sdist_to_dep_plan(build_plan& plan, | |||
const sdist& sd, | |||
build_env_ref env, | |||
const sdist_index_type& sd_idx, | |||
usage_requirement_map& ureqs, | |||
sdist_names& already_added) { | |||
if (already_added.find(sd.manifest.pk_id.name) != already_added.end()) { | |||
// We've already loaded this package into the plan. | |||
return; | |||
} | |||
spdlog::debug("Add to plan: {}", sd.manifest.pk_id.name); | |||
// First, load every dependency | |||
for (const auto& dep : sd.manifest.dependencies) { | |||
auto other = sd_idx.find(dep.name); | |||
assert(other != sd_idx.end() | |||
&& "Failed to load a transitive dependency shortly after initializing them. What?"); | |||
add_sdist_to_dep_plan(plan, other->second, env, sd_idx, ureqs, already_added); | |||
} | |||
// Record that we have been processed: | |||
already_added.insert(sd.manifest.pk_id.name); | |||
// Add the package: | |||
auto& pkg = plan.add_package(package_plan(sd.manifest.pk_id.name, sd.manifest.namespace_)); | |||
auto libs = collect_libraries(sd.path); | |||
for (const auto& lib : libs) { | |||
shared_compile_file_rules comp_rules = lib.base_compile_rules(); | |||
library_build_params params; | |||
auto lib_plan = library_plan::create(lib, params, ureqs); | |||
resolve_ureqs(comp_rules, sd, lib, lib_plan, env, ureqs); | |||
pkg.add_library(std::move(lib_plan)); | |||
} | |||
} | |||
} // namespace | |||
build_plan dds::create_deps_build_plan(const std::vector<sdist>& deps, build_env_ref env) { | |||
auto sd_idx = deps // | |||
| ranges::views::transform([](const auto& sd) { | |||
return std::pair(sd.manifest.pk_id.name, std::cref(sd)); | |||
}) // | |||
| ranges::to<sdist_index_type>(); | |||
build_plan plan; | |||
usage_requirement_map ureqs; | |||
sdist_names already_added; | |||
for (const sdist& sd : deps) { | |||
spdlog::info("Recording dependency: {}", sd.manifest.pk_id.name); | |||
add_sdist_to_dep_plan(plan, sd, env, sd_idx, ureqs, already_added); | |||
} | |||
return plan; | |||
} | |||
namespace { | |||
fs::path generate_lml(const library_plan& lib, path_ref libdir, const build_env& env) { | |||
auto fname = lib.name() + ".lml"; | |||
auto lml_path = libdir / fname; | |||
std::vector<lm::pair> kvs; | |||
kvs.emplace_back("Type", "Library"); | |||
kvs.emplace_back("Name", lib.name()); | |||
if (lib.create_archive()) { | |||
kvs.emplace_back("Path", | |||
fs::relative(lib.create_archive()->calc_archive_file_path(env), | |||
lml_path.parent_path()) | |||
.string()); | |||
} | |||
auto pub_inc_dir = lib.source_root() / "include"; | |||
auto src_dir = lib.source_root() / "src"; | |||
if (!fs::exists(pub_inc_dir)) { | |||
pub_inc_dir = src_dir; | |||
} | |||
kvs.emplace_back("Include-Path", pub_inc_dir.string()); | |||
// TODO: Uses, Preprocessor-Define, and Special-Uses | |||
fs::create_directories(lml_path.parent_path()); | |||
lm::write_pairs(lml_path, kvs); | |||
return lml_path; | |||
} | |||
fs::path generate_lmp(const package_plan& pkg, path_ref basedir, const build_env& env) { | |||
auto fname = pkg.name() + ".lmp"; | |||
auto lmp_path = basedir / fname; | |||
std::vector<lm::pair> kvs; | |||
kvs.emplace_back("Type", "Package"); | |||
kvs.emplace_back("Name", pkg.name()); | |||
kvs.emplace_back("Namespace", pkg.namespace_()); | |||
for (auto&& lib : pkg.libraries()) { | |||
auto lml = generate_lml(lib, basedir / pkg.name(), env); | |||
kvs.emplace_back("Library", fs::relative(lml, lmp_path.parent_path()).string()); | |||
} | |||
// TODO: `Requires` for transitive package imports | |||
fs::create_directories(lmp_path.parent_path()); | |||
lm::write_pairs(lmp_path, kvs); | |||
return lmp_path; | |||
} | |||
} // namespace | |||
void dds::write_libman_index(path_ref out_filepath, const build_plan& plan, const build_env& env) { | |||
fs::create_directories(out_filepath.parent_path()); | |||
auto lm_items_dir = out_filepath.parent_path() / "_libman"; | |||
std::vector<lm::pair> kvs; | |||
kvs.emplace_back("Type", "Index"); | |||
for (const package_plan& pkg : plan.packages()) { | |||
auto pkg_lmp = generate_lmp(pkg, lm_items_dir, env); | |||
kvs.emplace_back("Package", | |||
fmt::format("{}; {}", | |||
pkg.name(), | |||
fs::relative(pkg_lmp, out_filepath.parent_path()).string())); | |||
} | |||
lm::write_pairs(out_filepath, kvs); | |||
} |
@@ -10,16 +10,6 @@ | |||
namespace dds { | |||
struct sdist; | |||
class repository; | |||
enum class version_strength { | |||
exact, | |||
patch, | |||
minor, | |||
major, | |||
}; | |||
using version_range_set = pubgrub::interval_set<semver::version>; | |||
struct dependency { | |||
@@ -29,8 +19,4 @@ struct dependency { | |||
static dependency parse_depends_string(std::string_view str); | |||
}; | |||
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); | |||
} // namespace dds |
@@ -1,56 +0,0 @@ | |||
#pragma once | |||
#include <dds/build/plan/compile_file.hpp> | |||
#include <dds/build/source_dir.hpp> | |||
#include <dds/library_manifest.hpp> | |||
#include <dds/source.hpp> | |||
#include <string> | |||
namespace dds { | |||
struct library_ident { | |||
std::string namespace_; | |||
std::string name; | |||
}; | |||
class library { | |||
fs::path _path; | |||
source_list _sources; | |||
library_manifest _man; | |||
library(path_ref dir, source_list&& src, library_manifest&& man) | |||
: _path(dir) | |||
, _sources(std::move(src)) | |||
, _man(std::move(man)) {} | |||
public: | |||
static library from_directory(path_ref); | |||
auto& manifest() const noexcept { return _man; } | |||
source_directory src_dir() const noexcept { return source_directory{path() / "src"}; } | |||
source_directory include_dir() const noexcept { return source_directory{path() / "include"}; } | |||
path_ref path() const noexcept { return _path; } | |||
fs::path public_include_dir() const noexcept; | |||
fs::path private_include_dir() const noexcept; | |||
const source_list& all_sources() const noexcept { return _sources; } | |||
shared_compile_file_rules base_compile_rules() const noexcept; | |||
}; | |||
struct library_build_params { | |||
fs::path out_subdir; | |||
bool build_tests = false; | |||
bool build_apps = false; | |||
bool enable_warnings = false; | |||
// Extras for compiling tests: | |||
std::vector<fs::path> test_include_dirs; | |||
std::vector<fs::path> test_link_files; | |||
}; | |||
std::vector<library> collect_libraries(path_ref where); | |||
} // namespace dds |
@@ -1,4 +1,4 @@ | |||
#include <dds/library.hpp> | |||
#include <dds/library/library.hpp> | |||
#include <dds/build/plan/compile_file.hpp> | |||
#include <dds/build/source_dir.hpp> |
@@ -0,0 +1,92 @@ | |||
#pragma once | |||
#include <dds/build/plan/compile_file.hpp> | |||
#include <dds/build/source_dir.hpp> | |||
#include <dds/library/manifest.hpp> | |||
#include <dds/source.hpp> | |||
#include <string> | |||
namespace dds { | |||
/** | |||
* Represents a library that exists on the filesystem | |||
*/ | |||
class library { | |||
// The path containing the source directories for this library | |||
fs::path _path; | |||
// The sources that are part of this library | |||
source_list _sources; | |||
// The library manifest associated with this library (may be generated) | |||
library_manifest _man; | |||
// Private constructor. Use named constructor `from_directory`, which will build | |||
// the construct arguments approperiately | |||
library(path_ref dir, source_list&& src, library_manifest&& man) | |||
: _path(dir) | |||
, _sources(std::move(src)) | |||
, _man(std::move(man)) {} | |||
public: | |||
/** | |||
* Create a library object that refers to the library contained at the given | |||
* directory path. This will load the sources and manifest properly and | |||
* return the resulting library object. | |||
*/ | |||
static library from_directory(path_ref); | |||
/** | |||
* Obtain the manifest for this library | |||
*/ | |||
const library_manifest& manifest() const noexcept { return _man; } | |||
/** | |||
* The `src/` directory for this library. | |||
*/ | |||
source_directory src_dir() const noexcept { return source_directory{path() / "src"}; } | |||
/** | |||
* The `include/` directory for this library | |||
*/ | |||
source_directory include_dir() const noexcept { return source_directory{path() / "include"}; } | |||
/** | |||
* The root path for this library (parent of `src/` and `include/`, if present) | |||
*/ | |||
path_ref path() const noexcept { return _path; } | |||
/** | |||
* The directory that should be considered the "public" include directory. | |||
* Dependees that want to use this library should add this to their #include | |||
* search path. | |||
*/ | |||
fs::path public_include_dir() const noexcept; | |||
/** | |||
* The directory that contains the "private" heders for this libary. This | |||
* directory should be added to the search path of the library when it is | |||
* being built, but NOT to the search path of the dependees. | |||
*/ | |||
fs::path private_include_dir() const noexcept; | |||
/** | |||
* Get the sources that this library contains | |||
*/ | |||
const source_list& all_sources() const noexcept { return _sources; } | |||
/** | |||
* Generate a compile rules object that should be used when compiling | |||
* this library. | |||
*/ | |||
shared_compile_file_rules base_compile_rules() const noexcept; | |||
}; | |||
/** | |||
* Given the root source directory of a project/package/sdist, collect all of | |||
* the libraries that it contains. There may be a library directly in `where`, | |||
* but there might also be libraries in `where/libs`. This function will find | |||
* them all. | |||
*/ | |||
std::vector<library> collect_libraries(path_ref where); | |||
} // namespace dds |
@@ -1,4 +1,4 @@ | |||
#include "./library_manifest.hpp" | |||
#include "./manifest.hpp" | |||
#include <dds/util/algo.hpp> | |||
#include <range/v3/view/transform.hpp> |
@@ -0,0 +1,30 @@ | |||
#pragma once | |||
#include <dds/util/fs.hpp> | |||
#include <libman/library.hpp> | |||
#include <vector> | |||
namespace dds { | |||
/** | |||
* Represents the contents of a `library.dds`. This is somewhat a stripped-down | |||
* version of lm::library, to only represent exactly the parts that we want to | |||
* offer via `library.dds`. | |||
*/ | |||
struct library_manifest { | |||
/// The name of the library | |||
std::string name; | |||
/// The libraries that the owning library "uses" | |||
std::vector<lm::usage> uses; | |||
/// The libraries that the owning library must be linked with | |||
std::vector<lm::usage> links; | |||
/** | |||
* Load the library manifest from an existing file | |||
*/ | |||
static library_manifest load_from_file(const fs::path&); | |||
}; | |||
} // namespace dds |
@@ -1,19 +0,0 @@ | |||
#pragma once | |||
#include <dds/util/fs.hpp> | |||
#include <libman/library.hpp> | |||
#include <vector> | |||
namespace dds { | |||
struct library_manifest { | |||
std::string name; | |||
std::vector<lm::usage> uses; | |||
std::vector<lm::usage> links; | |||
static library_manifest load_from_file(const fs::path&); | |||
}; | |||
} // namespace dds |
@@ -1,4 +1,4 @@ | |||
#include <dds/package_id.hpp> | |||
#include <dds/package/id.hpp> | |||
#include <spdlog/fmt/fmt.h> | |||
@@ -0,0 +1,48 @@ | |||
#pragma once | |||
#include <semver/version.hpp> | |||
#include <string> | |||
#include <string_view> | |||
#include <tuple> | |||
namespace dds { | |||
/** | |||
* Represents a unique package ID. We store this as a simple name-version pair. | |||
* | |||
* In text, this is represented with an `@` symbol in between. The `parse` and | |||
* `to_string` method convert between this textual representation, and supports | |||
* full round-trips. | |||
*/ | |||
struct package_id { | |||
/// The name of the package | |||
std::string name; | |||
/// The version of the package | |||
semver::version version; | |||
/// Default-initialize a package_id with a blank name and a default version | |||
package_id() = default; | |||
/// Construct a package ID from a name-version pair | |||
package_id(std::string_view s, semver::version v); | |||
/** | |||
* Parse the given string into a package_id object. | |||
*/ | |||
static package_id parse(std::string_view); | |||
/** | |||
* Convert this package_id into its corresponding textual representation. | |||
* The returned string can be passed back to `parse()` for a round-trip | |||
*/ | |||
std::string to_string() const noexcept; | |||
friend bool operator<(const package_id& lhs, const package_id& rhs) noexcept { | |||
return std::tie(lhs.name, lhs.version) < std::tie(rhs.name, rhs.version); | |||
} | |||
friend bool operator==(const package_id& lhs, const package_id& rhs) noexcept { | |||
return std::tie(lhs.name, lhs.version) == std::tie(rhs.name, rhs.version); | |||
} | |||
}; | |||
} // namespace dds |
@@ -1,4 +1,4 @@ | |||
#include <dds/package_id.hpp> | |||
#include <dds/package/id.hpp> | |||
#include <catch2/catch.hpp> | |||
@@ -1,4 +1,4 @@ | |||
#include "./package_manifest.hpp" | |||
#include "./manifest.hpp" | |||
#include <dds/util/string.hpp> | |||
#include <libman/parse.hpp> | |||
@@ -18,14 +18,14 @@ package_manifest package_manifest::load_from_file(const fs::path& fpath) { | |||
std::optional<std::string> opt_test_driver; | |||
lm::read(fmt::format("Reading package manifest '{}'", fpath.string()), | |||
kvs, | |||
lm::read_required("Name", ret.pk_id.name), | |||
lm::read_required("Name", ret.pkg_id.name), | |||
lm::read_opt("Namespace", ret.namespace_), | |||
lm::read_required("Version", version_str), | |||
lm::read_accumulate("Depends", depends_strs), | |||
lm::read_opt("Test-Driver", opt_test_driver), | |||
lm::reject_unknown()); | |||
if (ret.pk_id.name.empty()) { | |||
if (ret.pkg_id.name.empty()) { | |||
throw std::runtime_error( | |||
fmt::format("'Name' field in [{}] may not be an empty string", fpath.string())); | |||
} | |||
@@ -45,10 +45,10 @@ package_manifest package_manifest::load_from_file(const fs::path& fpath) { | |||
} | |||
if (ret.namespace_.empty()) { | |||
ret.namespace_ = ret.pk_id.name; | |||
ret.namespace_ = ret.pkg_id.name; | |||
} | |||
ret.pk_id.version = semver::version::parse(version_str); | |||
ret.pkg_id.version = semver::version::parse(version_str); | |||
ret.dependencies = depends_strs // | |||
| ranges::views::transform(dependency::parse_depends_string) // |
@@ -0,0 +1,40 @@ | |||
#pragma once | |||
#include <dds/deps.hpp> | |||
#include <dds/package/id.hpp> | |||
#include <dds/util/fs.hpp> | |||
#include <optional> | |||
#include <string> | |||
#include <vector> | |||
namespace dds { | |||
/** | |||
* Possible values for Test-Driver in a package.dds | |||
*/ | |||
enum class test_lib { | |||
catch_, | |||
catch_main, | |||
}; | |||
/** | |||
* Struct representing the contents of a `packaeg.dds` file. | |||
*/ | |||
struct package_manifest { | |||
/// The package ID, as determined by `Name` and `Version` together | |||
package_id pkg_id; | |||
/// The declared `Namespace` of the package. This directly corresponds with the libman Namespace | |||
std::string namespace_; | |||
/// The `Test-Driver` that this package declares, or `nullopt` if absent. | |||
std::optional<test_lib> test_driver; | |||
/// The dependencies declared with the `Depends` fields, if any. | |||
std::vector<dependency> dependencies; | |||
/** | |||
* Load a package manifest from a file on disk. | |||
*/ | |||
static package_manifest load_from_file(path_ref); | |||
}; | |||
} // namespace dds |
@@ -1,31 +0,0 @@ | |||
#pragma once | |||
#include <semver/version.hpp> | |||
#include <string> | |||
#include <string_view> | |||
#include <tuple> | |||
namespace dds { | |||
struct package_id { | |||
std::string name; | |||
semver::version version; | |||
package_id() = default; | |||
package_id(std::string_view s, semver::version v); | |||
static package_id parse(std::string_view); | |||
std::string to_string() const noexcept; | |||
auto tie() const noexcept { return std::tie(name, version); } | |||
friend bool operator<(const package_id& lhs, const package_id& rhs) noexcept { | |||
return lhs.tie() < rhs.tie(); | |||
} | |||
friend bool operator==(const package_id& lhs, const package_id& rhs) noexcept { | |||
return lhs.tie() == rhs.tie(); | |||
} | |||
}; | |||
} // namespace dds |
@@ -1,27 +0,0 @@ | |||
#pragma once | |||
#include <dds/deps.hpp> | |||
#include <dds/package_id.hpp> | |||
#include <dds/util/fs.hpp> | |||
#include <semver/version.hpp> | |||
#include <optional> | |||
#include <string> | |||
#include <vector> | |||
namespace dds { | |||
enum class test_lib { | |||
catch_, | |||
catch_main, | |||
}; | |||
struct package_manifest { | |||
package_id pk_id; | |||
std::string namespace_; | |||
std::optional<test_lib> test_driver; | |||
std::vector<dependency> dependencies; | |||
static package_manifest load_from_file(path_ref); | |||
}; | |||
} // namespace dds |
@@ -1,5 +1,6 @@ | |||
#include "./repo.hpp" | |||
#include <dds/catalog/catalog.hpp> | |||
#include <dds/sdist.hpp> | |||
#include <dds/solve/solve.hpp> | |||
#include <dds/util/paths.hpp> | |||
@@ -8,7 +9,9 @@ | |||
#include <spdlog/spdlog.h> | |||
#include <range/v3/action/sort.hpp> | |||
#include <range/v3/action/unique.hpp> | |||
#include <range/v3/range/conversion.hpp> | |||
#include <range/v3/view/concat.hpp> | |||
#include <range/v3/view/filter.hpp> | |||
#include <range/v3/view/transform.hpp> | |||
@@ -71,7 +74,7 @@ void repository::add_sdist(const sdist& sd, if_exists ife_action) { | |||
"repository, we'll hard-exit immediately."); | |||
std::terminate(); | |||
} | |||
auto sd_dest = _root / sd.manifest.pk_id.to_string(); | |||
auto sd_dest = _root / sd.manifest.pkg_id.to_string(); | |||
if (fs::exists(sd_dest)) { | |||
auto msg = fmt::format("Source distribution '{}' is already available in the local repo", | |||
sd.path.string()); | |||
@@ -95,7 +98,8 @@ void repository::add_sdist(const sdist& sd, if_exists ife_action) { | |||
fs::remove_all(sd_dest); | |||
} | |||
fs::rename(tmp_copy, sd_dest); | |||
spdlog::info("Source distribution '{}' successfully exported", sd.manifest.pk_id.to_string()); | |||
_sdists.insert(sdist::from_directory(sd_dest)); | |||
spdlog::info("Source distribution '{}' successfully exported", sd.manifest.pkg_id.to_string()); | |||
} | |||
const sdist* repository::find(const package_id& pkg) const noexcept { | |||
@@ -106,29 +110,27 @@ const sdist* repository::find(const package_id& pkg) const noexcept { | |||
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); | |||
std::vector<package_id> repository::solve(const std::vector<dependency>& deps, | |||
const catalog& ctlg) const { | |||
return dds::solve(deps, | |||
[&](std::string_view name) -> std::vector<package_id> { | |||
auto mine = ranges::views::all(_sdists) // | |||
| ranges::views::filter([&](const sdist& sd) { | |||
return sd.manifest.pkg_id.name == name; | |||
}) | |||
| ranges::views::transform( | |||
[](const sdist& sd) { return sd.manifest.pkg_id; }); | |||
auto avail = ctlg.by_name(name); | |||
auto all = ranges::views::concat(mine, avail) | ranges::to_vector; | |||
ranges::sort(all, std::less<>{}); | |||
ranges::unique(all, std::less<>{}); | |||
return all; | |||
}, | |||
[&](const package_id& pkg_id) { | |||
auto found = find(pkg_id); | |||
if (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; | |||
} | |||
return ctlg.dependencies_of(pkg_id); | |||
}); | |||
} |
@@ -2,6 +2,7 @@ | |||
#include <dds/sdist.hpp> | |||
#include <dds/util/flock.hpp> | |||
#include <dds/catalog/catalog.hpp> | |||
#include <dds/util/fs.hpp> | |||
#include <functional> | |||
@@ -96,7 +97,7 @@ public: | |||
return r; | |||
} | |||
std::vector<sdist> solve(const std::vector<dependency>& deps) const; | |||
std::vector<package_id> solve(const std::vector<dependency>& deps, const catalog&) const; | |||
}; | |||
} // namespace dds |
@@ -93,7 +93,7 @@ sdist dds::create_sdist_in_dir(path_ref out, const sdist_params& params) { | |||
sdist_export_file(out, params.project_dir, man_path); | |||
auto pkg_man = package_manifest::load_from_file(man_path); | |||
spdlog::info("Generated export as {}", pkg_man.pk_id.to_string()); | |||
spdlog::info("Generated export as {}", pkg_man.pkg_id.to_string()); | |||
return sdist::from_directory(out); | |||
} |
@@ -2,7 +2,7 @@ | |||
#include <tuple> | |||
#include <dds/package_manifest.hpp> | |||
#include <dds/package/manifest.hpp> | |||
#include <dds/util/fs.hpp> | |||
namespace dds { | |||
@@ -28,13 +28,13 @@ struct sdist { | |||
inline constexpr struct sdist_compare_t { | |||
bool operator()(const sdist& lhs, const sdist& rhs) const { | |||
return lhs.manifest.pk_id < rhs.manifest.pk_id; | |||
return lhs.manifest.pkg_id < rhs.manifest.pkg_id; | |||
} | |||
bool operator()(const sdist& lhs, const package_id& rhs) const { | |||
return lhs.manifest.pk_id < rhs; | |||
return lhs.manifest.pkg_id < rhs; | |||
} | |||
bool operator()(const package_id& lhs, const sdist& rhs) const { | |||
return lhs < rhs.manifest.pk_id; | |||
return lhs < rhs.manifest.pkg_id; | |||
} | |||
using is_transparent = int; | |||
} sdist_compare; |
@@ -1,7 +1,7 @@ | |||
#pragma once | |||
#include <dds/deps.hpp> | |||
#include <dds/package_id.hpp> | |||
#include <dds/package/id.hpp> | |||
#include <functional> | |||
@@ -69,17 +69,6 @@ class DDS: | |||
def project_dir_arg(self) -> str: | |||
return f'--project-dir={self.source_root}' | |||
def deps_ls(self) -> subprocess.CompletedProcess: | |||
return self.run(['deps', 'ls']) | |||
def deps_get(self) -> subprocess.CompletedProcess: | |||
return self.run([ | |||
'deps', | |||
'get', | |||
f'--catalog={self.catalog_path}', | |||
self.repo_dir_arg, | |||
]) | |||
def deps_build(self, *, | |||
toolchain: str = None) -> subprocess.CompletedProcess: | |||
return self.run([ | |||
@@ -101,12 +90,13 @@ class DDS: | |||
return self.run([ | |||
'build', | |||
f'--out={self.build_dir}', | |||
['--tests'] if tests else [], | |||
['--apps'] if apps else [], | |||
['--warnings'] if warnings else [], | |||
['--export'] if export else [], | |||
f'--toolchain={toolchain or self.default_builtin_toolchain}', | |||
f'--lm-index={self.lmi_path}', | |||
f'--catalog={self.catalog_path}', | |||
f'--repo-dir={self.repo_dir}', | |||
['--no-tests'] if not tests else [], | |||
['--no-apps'] if not apps else [], | |||
['--no-warnings'] if not warnings else [], | |||
['--export'] if export else [], | |||
self.project_dir_arg, | |||
]) | |||
@@ -9,28 +9,17 @@ dds_conf = dds_fixture_conf( | |||
) | |||
@dds_conf | |||
def test_ls(dds: DDS): | |||
dds.run(['deps', 'ls']) | |||
@dds_conf | |||
def test_deps_build(dds: DDS): | |||
dds.catalog_import(dds.source_root / 'catalog.json') | |||
assert not dds.repo_dir.exists() | |||
dds.deps_get() | |||
assert dds.repo_dir.exists(), '`deps get` did not generate a repo directory' | |||
assert not dds.lmi_path.exists() | |||
dds.deps_build() | |||
assert dds.lmi_path.exists(), '`deps build` did not generate the build dir' | |||
dds.build() | |||
assert dds.repo_dir.exists(), '`Building` did not generate a repo directory' | |||
@dds_fixture_conf_1('use-remote') | |||
def test_use_nlohmann_json_remote(dds: DDS): | |||
dds.catalog_import(dds.source_root / 'catalog.json') | |||
dds.deps_get() | |||
dds.deps_build() | |||
dds.build(apps=True) | |||
app_exe = dds.build_dir / f'app{dds.exe_suffix}' |
@@ -5,9 +5,7 @@ from dds_ci import proc | |||
def test_get_build_use_spdlog(dds: DDS): | |||
dds.catalog_import(dds.source_root / 'catalog.json') | |||
dds.deps_get() | |||
tc_fname = 'gcc.tc.dds' if 'gcc' in dds.default_builtin_toolchain else 'msvc.tc.dds' | |||
tc = str(dds.test_dir / tc_fname) | |||
dds.deps_build(toolchain=tc) | |||
dds.build(toolchain=tc, apps=True) | |||
proc.check_run((dds.build_dir / 'use-spdlog').with_suffix(dds.exe_suffix)) |
@@ -98,8 +98,8 @@ def main(argv: Sequence[str]) -> int: | |||
else: | |||
assert False, 'impossible' | |||
ci_repo_dir = paths.BUILD_DIR / '_ci-repo' | |||
if not opts.skip_deps: | |||
ci_repo_dir = paths.BUILD_DIR / '_ci-repo' | |||
if ci_repo_dir.exists(): | |||
shutil.rmtree(ci_repo_dir) | |||
self_deps_get(paths.PREBUILT_DDS, ci_repo_dir) | |||
@@ -112,10 +112,18 @@ def main(argv: Sequence[str]) -> int: | |||
dds_flags=['--warnings', '--tests', '--apps']) | |||
print('Main build PASSED!') | |||
cat_path = paths.BUILD_DIR / 'catalog.db' | |||
proc.check_run([ | |||
paths.CUR_BUILT_DDS, | |||
'catalog', | |||
'import', | |||
('--catalog', cat_path), | |||
('--json', paths.PROJECT_ROOT / 'catalog.json'), | |||
]) | |||
self_build( | |||
paths.CUR_BUILT_DDS, | |||
toolchain=opts.toolchain, | |||
dds_flags=['--warnings', '--tests', '--apps']) | |||
dds_flags=[f'--repo-dir={ci_repo_dir}', f'--catalog={cat_path}']) | |||
print('Bootstrap test PASSED!') | |||
return pytest.main([ |