| #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() |