| #include <dds/dym.hpp> | #include <dds/dym.hpp> | ||||
| #include <dds/error/errors.hpp> | #include <dds/error/errors.hpp> | ||||
| #include <dds/util/algo.hpp> | #include <dds/util/algo.hpp> | ||||
| #include <libman/parse.hpp> | |||||
| #include <json5/parse_data.hpp> | #include <json5/parse_data.hpp> | ||||
| #include <range/v3/view/transform.hpp> | #include <range/v3/view/transform.hpp> | ||||
| using namespace dds; | using namespace dds; | ||||
| library_manifest library_manifest::load_from_dds_file(path_ref fpath) { | |||||
| spdlog::warn( | |||||
| "Using deprecated library.dds parsing (on file {}). This will be removed soon. Migrate!", | |||||
| fpath.string()); | |||||
| auto kvs = lm::parse_file(fpath); | |||||
| library_manifest ret; | |||||
| ret.name = fpath.parent_path().filename().string(); | |||||
| std::vector<std::string> uses_strings; | |||||
| std::vector<std::string> links_strings; | |||||
| lm::read(fmt::format("Reading library manifest {}", fpath.string()), | |||||
| kvs, | |||||
| lm::read_accumulate("Uses", uses_strings), | |||||
| lm::read_accumulate("Links", links_strings), | |||||
| lm::read_required("Name", ret.name), | |||||
| lm_reject_dym{{"Uses", "Links", "Name"}}); | |||||
| extend(ret.uses, ranges::views::transform(uses_strings, lm::split_usage_string)); | |||||
| extend(ret.links, ranges::views::transform(links_strings, lm::split_usage_string)); | |||||
| return ret; | |||||
| } | |||||
| library_manifest library_manifest::load_from_file(path_ref fpath) { | library_manifest library_manifest::load_from_file(path_ref fpath) { | ||||
| auto content = slurp_file(fpath); | auto content = slurp_file(fpath); | ||||
| auto data = json5::parse_data(content); | auto data = json5::parse_data(content); | ||||
| if (rej) { | if (rej) { | ||||
| throw_user_error<errc::invalid_lib_manifest>(rej->message); | throw_user_error<errc::invalid_lib_manifest>(rej->message); | ||||
| } | } | ||||
| // using namespace json_read::ops; | |||||
| // json_read::decompose( // | |||||
| // data.as_object(), | |||||
| // object(key("name", require_string(put_into{lib.name}, "`name` must be a string")), | |||||
| // key("uses", | |||||
| // array_each{require_string( | |||||
| // [&](auto&& uses) { | |||||
| // lib.uses.push_back(lm::split_usage_string(uses.as_string())); | |||||
| // return json_read::accept_t{}; | |||||
| // }, | |||||
| // "All `uses` items must be strings")}), | |||||
| // key("links", | |||||
| // array_each{require_string( | |||||
| // [&](auto&& links) { | |||||
| // lib.links.push_back(lm::split_usage_string(links.as_string())); | |||||
| // return json_read::accept_t{}; | |||||
| // }, | |||||
| // "All `links` items must be strings")}))); | |||||
| if (lib.name.empty()) { | if (lib.name.empty()) { | ||||
| throw_user_error<errc::invalid_lib_manifest>( | throw_user_error<errc::invalid_lib_manifest>( | ||||
| } | } | ||||
| } | } | ||||
| auto dds_file = dirpath / "library.dds"; | |||||
| if (fs::is_regular_file(dds_file)) { | |||||
| return dds_file; | |||||
| } | |||||
| return std::nullopt; | return std::nullopt; | ||||
| } | } | ||||
| return std::nullopt; | return std::nullopt; | ||||
| } | } | ||||
| if (found->extension() == ".dds") { | |||||
| return load_from_dds_file(*found); | |||||
| } else { | |||||
| return load_from_file(*found); | |||||
| } | |||||
| return load_from_file(*found); | |||||
| } | } |
| * Load the library manifest from an existing file | * Load the library manifest from an existing file | ||||
| */ | */ | ||||
| static library_manifest load_from_file(path_ref); | static library_manifest load_from_file(path_ref); | ||||
| static library_manifest load_from_dds_file(path_ref); | |||||
| /** | /** | ||||
| * Find a library manifest within a directory. This will search for a few | * Find a library manifest within a directory. This will search for a few |
| man.name = lib_dir.filename().string(); | man.name = lib_dir.filename().string(); | ||||
| auto found = library_manifest::find_in_directory(lib_dir); | auto found = library_manifest::find_in_directory(lib_dir); | ||||
| if (found) { | if (found) { | ||||
| if (found->extension() == ".dds") { | |||||
| man = library_manifest::load_from_dds_file(*found); | |||||
| } else { | |||||
| man = library_manifest::load_from_file(*found); | |||||
| } | |||||
| man = library_manifest::load_from_file(*found); | |||||
| } | } | ||||
| auto lib = library_root(lib_dir, std::move(sources), std::move(man)); | auto lib = library_root(lib_dir, std::move(sources), std::move(man)); |
| #include <dds/dym.hpp> | #include <dds/dym.hpp> | ||||
| #include <dds/error/errors.hpp> | #include <dds/error/errors.hpp> | ||||
| #include <dds/util/string.hpp> | #include <dds/util/string.hpp> | ||||
| #include <libman/parse.hpp> | |||||
| #include <range/v3/view/split.hpp> | #include <range/v3/view/split.hpp> | ||||
| #include <range/v3/view/split_when.hpp> | #include <range/v3/view/split_when.hpp> | ||||
| using namespace dds; | using namespace dds; | ||||
| package_manifest package_manifest::load_from_dds_file(const fs::path& fpath) { | |||||
| spdlog::warn( | |||||
| "Using deprecated package.dds parsing (on file {}). This will be removed soon. Migrate!", | |||||
| fpath.string()); | |||||
| auto kvs = lm::parse_file(fpath); | |||||
| package_manifest ret; | |||||
| std::string version_str; | |||||
| std::vector<std::string> depends_strs; | |||||
| std::optional<std::string> opt_test_driver; | |||||
| lm::read(fmt::format("Reading package manifest '{}'", fpath.string()), | |||||
| kvs, | |||||
| 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_dym{{"Name", "Namespace", "Version", "Depends", "Test-Driver"}}); | |||||
| if (ret.pkg_id.name.empty()) { | |||||
| throw_user_error<errc::invalid_pkg_name>("'Name' field in [{}] may not be an empty string", | |||||
| fpath.string()); | |||||
| } | |||||
| if (version_str.empty()) { | |||||
| throw_user_error< | |||||
| errc::invalid_version_string>("'Version' field in [{}] may not be an empty string", | |||||
| fpath.string()); | |||||
| } | |||||
| if (opt_test_driver) { | |||||
| auto& test_driver_str = *opt_test_driver; | |||||
| if (test_driver_str == "Catch-Main") { | |||||
| ret.test_driver = test_lib::catch_main; | |||||
| } else if (test_driver_str == "Catch") { | |||||
| ret.test_driver = test_lib::catch_; | |||||
| } else { | |||||
| auto dym = *did_you_mean(test_driver_str, {"Catch-Main", "Catch"}); | |||||
| throw_user_error< | |||||
| errc::unknown_test_driver>("Unknown 'test_driver' '{}' (Did you mean '{}'?)", | |||||
| test_driver_str, | |||||
| dym); | |||||
| } | |||||
| } | |||||
| if (ret.namespace_.empty()) { | |||||
| ret.namespace_ = ret.pkg_id.name; | |||||
| } | |||||
| ret.pkg_id.version = semver::version::parse(version_str); | |||||
| ret.dependencies = depends_strs // | |||||
| | ranges::views::transform(dependency::parse_depends_string) // | |||||
| | ranges::to_vector; | |||||
| return ret; | |||||
| } | |||||
| package_manifest package_manifest::load_from_file(const fs::path& fpath) { | package_manifest package_manifest::load_from_file(const fs::path& fpath) { | ||||
| auto content = slurp_file(fpath); | auto content = slurp_file(fpath); | ||||
| auto data = json5::parse_data(content); | auto data = json5::parse_data(content); | ||||
| } | } | ||||
| } | } | ||||
| auto dds_fname = dirpath / "package.dds"; | |||||
| if (fs::is_regular_file(dds_fname)) { | |||||
| return dds_fname; | |||||
| } | |||||
| return std::nullopt; | return std::nullopt; | ||||
| } | } | ||||
| if (!found.has_value()) { | if (!found.has_value()) { | ||||
| return std::nullopt; | return std::nullopt; | ||||
| } | } | ||||
| if (found->extension() == ".dds") { | |||||
| return load_from_dds_file(*found); | |||||
| } else { | |||||
| return load_from_file(*found); | |||||
| } | |||||
| return load_from_file(*found); | |||||
| } | } |
| * Load a package manifest from a file on disk. | * Load a package manifest from a file on disk. | ||||
| */ | */ | ||||
| static package_manifest load_from_file(path_ref); | static package_manifest load_from_file(path_ref); | ||||
| static package_manifest load_from_dds_file(path_ref); | |||||
| /** | /** | ||||
| * Find a package manifest contained within a directory. This will search | * Find a package manifest contained within a directory. This will search |
| params.project_dir.string()); | params.project_dir.string()); | ||||
| } | } | ||||
| auto pkg_man = man_path->extension() == ".dds" ? package_manifest::load_from_dds_file(*man_path) | |||||
| : package_manifest::load_from_file(*man_path); | |||||
| auto pkg_man = package_manifest::load_from_file(*man_path); | |||||
| sdist_export_file(out, params.project_dir, *man_path); | sdist_export_file(out, params.project_dir, *man_path); | ||||
| spdlog::info("Generated export as {}", pkg_man.pkg_id.to_string()); | spdlog::info("Generated export as {}", pkg_man.pkg_id.to_string()); | ||||
| return sdist::from_directory(out); | return sdist::from_directory(out); |
| scope.enter_context( | scope.enter_context( | ||||
| dds.set_contents( | dds.set_contents( | ||||
| 'library.dds', | |||||
| b'Name: TestLibrary', | |||||
| 'library.json5', | |||||
| b'''{ | |||||
| name: 'TestLibrary', | |||||
| }''', | |||||
| )) | )) | ||||
| scope.enter_context( | scope.enter_context( | ||||
| dds.set_contents( | dds.set_contents( | ||||
| 'package.dds', | |||||
| b''' | |||||
| Name: TestProject | |||||
| Version: 0.0.0 | |||||
| ''', | |||||
| 'package.json5', | |||||
| b'''{ | |||||
| name: 'TestProject', | |||||
| version: '0.0.0', | |||||
| namespace: 'test', | |||||
| }''', | |||||
| )) | )) | ||||
| dds.build(tests=True, apps=False, warnings=False) | dds.build(tests=True, apps=False, warnings=False) |
| 'version': 1, | 'version': 1, | ||||
| 'packages': { | 'packages': { | ||||
| 'neo-sqlite3': { | 'neo-sqlite3': { | ||||
| '0.2.2': { | |||||
| 'depends': {}, | |||||
| '0.3.0': { | |||||
| 'git': { | 'git': { | ||||
| 'url': | 'url': | ||||
| 'https://github.com/vector-of-bool/neo-sqlite3.git', | 'https://github.com/vector-of-bool/neo-sqlite3.git', | ||||
| 'ref': | 'ref': | ||||
| '0.2.2', | |||||
| '0.3.0', | |||||
| }, | }, | ||||
| }, | }, | ||||
| }, | }, | ||||
| dds.catalog_import(json_path) | dds.catalog_import(json_path) | ||||
| dds.catalog_get('neo-sqlite3@0.2.2') | |||||
| assert (dds.source_root / 'neo-sqlite3@0.2.2').is_dir() | |||||
| assert (dds.source_root / 'neo-sqlite3@0.2.2/package.dds').is_file() | |||||
| dds.catalog_get('neo-sqlite3@0.3.0') | |||||
| assert (dds.source_root / 'neo-sqlite3@0.3.0').is_dir() | |||||
| assert (dds.source_root / 'neo-sqlite3@0.3.0/package.jsonc').is_file() |
| "url": "https://github.com/vector-of-bool/neo-sqlite3.git", | "url": "https://github.com/vector-of-bool/neo-sqlite3.git", | ||||
| "ref": "0.1.0" | "ref": "0.1.0" | ||||
| }, | }, | ||||
| "depends": {} | |||||
| }, | }, | ||||
| "0.2.2": { | "0.2.2": { | ||||
| "git": { | "git": { | ||||
| "url": "https://github.com/vector-of-bool/neo-sqlite3.git", | "url": "https://github.com/vector-of-bool/neo-sqlite3.git", | ||||
| "ref": "0.2.2" | "ref": "0.2.2" | ||||
| }, | }, | ||||
| "depends": {} | |||||
| }, | |||||
| "0.3.0": { | |||||
| "git": { | |||||
| "url": "https://github.com/vector-of-bool/neo-sqlite3.git", | |||||
| "ref": "0.3.0" | |||||
| }, | |||||
| } | } | ||||
| } | } | ||||
| } | } |
| { | { | ||||
| depends: { | depends: { | ||||
| 'neo-sqlite3': '+0.2.2', | |||||
| 'neo-sqlite3': '+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.2.2').is_dir() | |||||
| assert (dds.deps_build_dir / 'neo-sqlite3@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.lmp').is_file() | ||||
| assert (dds.deps_build_dir / '_libman/neo/sqlite3.lml').is_file() | assert (dds.deps_build_dir / '_libman/neo/sqlite3.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.2.2']) | |||||
| assert (dds.deps_build_dir / 'neo-sqlite3@0.2.2').is_dir() | |||||
| dds.build_deps(['neo-sqlite3=0.3.0']) | |||||
| assert (dds.deps_build_dir / 'neo-sqlite3@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.lmp').is_file() | ||||
| assert (dds.deps_build_dir / '_libman/neo/sqlite3.lml').is_file() | assert (dds.deps_build_dir / '_libman/neo/sqlite3.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.2', 'neo-sqlite3~0.2.0']) | |||||
| assert (dds.deps_build_dir / 'neo-sqlite3@0.2.2').is_dir() | |||||
| 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() | |||||
| 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.lmp').is_file() | ||||
| assert (dds.deps_build_dir / '_libman/neo/sqlite3.lml').is_file() | assert (dds.deps_build_dir / '_libman/neo/sqlite3.lml').is_file() |
| { | { | ||||
| "version": 1, | "version": 1, | ||||
| "packages": { | "packages": { | ||||
| "neo-buffer": { | |||||
| "0.1.0": { | |||||
| "neo-fun": { | |||||
| "0.3.2": { | |||||
| "git": { | "git": { | ||||
| "url": "https://github.com/vector-of-bool/neo-buffer.git", | |||||
| "ref": "0.1.0" | |||||
| }, | |||||
| "depends": {} | |||||
| "url": "https://github.com/vector-of-bool/neo-fun.git", | |||||
| "ref": "0.3.2" | |||||
| } | |||||
| } | } | ||||
| }, | }, | ||||
| "range-v3": { | "range-v3": { | ||||
| "url": "https://github.com/ericniebler/range-v3.git", | "url": "https://github.com/ericniebler/range-v3.git", | ||||
| "ref": "0.9.1", | "ref": "0.9.1", | ||||
| "auto-lib": "Niebler/range-v3" | "auto-lib": "Niebler/range-v3" | ||||
| }, | |||||
| "depends": {} | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } |
| "namespace": "test", | "namespace": "test", | ||||
| version: '0.0.0', | version: '0.0.0', | ||||
| depends: { | depends: { | ||||
| 'neo-buffer': '0.1.0', | |||||
| 'neo-fun': '0.3.2', | |||||
| 'range-v3': '0.9.1', | 'range-v3': '0.9.1', | ||||
| } | } | ||||
| } | } |