#include <dds/util/string.hpp> | #include <dds/util/string.hpp> | ||||
#include <json5/parse_data.hpp> | #include <json5/parse_data.hpp> | ||||
#include <semester/decomp.hpp> | |||||
#include <semester/walk.hpp> | |||||
#include <spdlog/fmt/fmt.h> | #include <spdlog/fmt/fmt.h> | ||||
auto data = json5::parse_data(content); | auto data = json5::parse_data(content); | ||||
dependency_manifest depman; | dependency_manifest depman; | ||||
using namespace semester::decompose_ops; | |||||
auto res = semester::decompose( | |||||
using namespace semester::walk_ops; | |||||
auto res = walk.try_walk( // | |||||
data, | data, | ||||
try_seq{ | |||||
require_type<json5::data::mapping_type>{ | |||||
"The root of a dependency manifest must be an object (mapping)"}, | |||||
mapping{ | |||||
if_key{"$schema", just_accept}, | |||||
if_key{"depends", | |||||
require_type<json5::data::mapping_type>{ | |||||
"`depends` must be a mapping between package names and version ranges"}, | |||||
mapping{[&](auto pkg_name, const json5::data& range_str_) { | |||||
if (!range_str_.is_string()) { | |||||
throw_user_error<errc::invalid_pkg_manifest>( | |||||
"Issue in dependency manifest: Dependency for '{}' must be a " | |||||
"range string", | |||||
pkg_name); | |||||
} | |||||
try { | |||||
auto rng = semver::range::parse_restricted(range_str_.as_string()); | |||||
dependency dep{std::string(pkg_name), {rng.low(), rng.high()}}; | |||||
depman.dependencies.push_back(std::move(dep)); | |||||
} catch (const semver::invalid_range&) { | |||||
throw_user_error<errc::invalid_version_range_string>( | |||||
"Invalid version range string '{}' in dependency declaration " | |||||
"for '{}'", | |||||
range_str_.as_string(), | |||||
pkg_name); | |||||
} | |||||
return semester::dc_accept; | |||||
}}}, | |||||
[&](auto key, auto&&) { | |||||
return semester::dc_reject_t{ | |||||
fmt::format("Unknown key `{}` in dependency manifest", key)}; | |||||
}}, | |||||
require_type<json5::data::mapping_type>{ | |||||
"The root of a dependency manifest must be a JSON object"}, | |||||
mapping{ | |||||
required_key{ | |||||
"depends", | |||||
"A 'depends' key is required", | |||||
require_type<json5::data::array_type>{"'depends' must be an array of strings"}, | |||||
for_each{ | |||||
require_type<std::string>{"Each dependency should be a string"}, | |||||
put_into(std::back_inserter(depman.dependencies), | |||||
[](const std::string& str) { | |||||
return dependency::parse_depends_string(str); | |||||
}), | |||||
}, | |||||
}, | |||||
}); | }); | ||||
auto rej = std::get_if<semester::dc_reject_t>(&res); | |||||
if (rej) { | |||||
throw_user_error<errc::invalid_pkg_manifest>(rej->message); | |||||
} | |||||
res.throw_if_rejected<user_error<errc::invalid_pkg_manifest>>(); | |||||
return depman; | return depman; | ||||
} | } |
{ | { | ||||
depends: { | |||||
'neo-sqlite3': '+0.3.0', | |||||
}, | |||||
depends: [ | |||||
'neo-fun+0.3.0' | |||||
], | |||||
} | } |
assert not dds.deps_build_dir.is_dir() | assert not dds.deps_build_dir.is_dir() | ||||
dds.catalog_import(dds.source_root / 'catalog.json') | dds.catalog_import(dds.source_root / 'catalog.json') | ||||
dds.build_deps(['-d', 'deps.json5']) | dds.build_deps(['-d', 'deps.json5']) | ||||
assert (dds.deps_build_dir / 'neo-sqlite3@0.3.0').is_dir() | |||||
assert (dds.deps_build_dir / 'neo-fun@0.3.0').is_dir() | |||||
assert (dds.scratch_dir / 'INDEX.lmi').is_file() | assert (dds.scratch_dir / 'INDEX.lmi').is_file() | ||||
assert (dds.deps_build_dir / '_libman/neo-sqlite3.lmp').is_file() | |||||
assert (dds.deps_build_dir / '_libman/neo/sqlite3.lml').is_file() | |||||
assert (dds.deps_build_dir / '_libman/neo-fun.lmp').is_file() | |||||
assert (dds.deps_build_dir / '_libman/neo/fun.lml').is_file() | |||||
def test_build_deps_from_cmd(dds: DDS): | def test_build_deps_from_cmd(dds: DDS): | ||||
assert not dds.deps_build_dir.is_dir() | assert not dds.deps_build_dir.is_dir() | ||||
dds.catalog_import(dds.source_root / 'catalog.json') | dds.catalog_import(dds.source_root / 'catalog.json') | ||||
dds.build_deps(['neo-sqlite3=0.3.0']) | |||||
assert (dds.deps_build_dir / 'neo-sqlite3@0.3.0').is_dir() | |||||
dds.build_deps(['neo-fun=0.3.0']) | |||||
assert (dds.deps_build_dir / 'neo-fun@0.3.0').is_dir() | |||||
assert (dds.scratch_dir / 'INDEX.lmi').is_file() | assert (dds.scratch_dir / 'INDEX.lmi').is_file() | ||||
assert (dds.deps_build_dir / '_libman/neo-sqlite3.lmp').is_file() | |||||
assert (dds.deps_build_dir / '_libman/neo/sqlite3.lml').is_file() | |||||
assert (dds.deps_build_dir / '_libman/neo-fun.lmp').is_file() | |||||
assert (dds.deps_build_dir / '_libman/neo/fun.lml').is_file() | |||||
def test_multiple_deps(dds: DDS): | def test_multiple_deps(dds: DDS): | ||||
assert not dds.deps_build_dir.is_dir() | assert not dds.deps_build_dir.is_dir() | ||||
dds.catalog_import(dds.source_root / 'catalog.json') | dds.catalog_import(dds.source_root / 'catalog.json') | ||||
dds.build_deps(['neo-sqlite3^0.2.0', 'neo-sqlite3~0.3.0']) | |||||
assert (dds.deps_build_dir / 'neo-sqlite3@0.3.0').is_dir() | |||||
dds.build_deps(['neo-fun^0.2.0', 'neo-fun~0.3.0']) | |||||
assert (dds.deps_build_dir / 'neo-fun@0.3.0').is_dir() | |||||
assert (dds.scratch_dir / 'INDEX.lmi').is_file() | assert (dds.scratch_dir / 'INDEX.lmi').is_file() | ||||
assert (dds.deps_build_dir / '_libman/neo-sqlite3.lmp').is_file() | |||||
assert (dds.deps_build_dir / '_libman/neo/sqlite3.lml').is_file() | |||||
assert (dds.deps_build_dir / '_libman/neo-fun.lmp').is_file() | |||||
assert (dds.deps_build_dir / '_libman/neo/fun.lml').is_file() |