| @@ -50,6 +50,17 @@ std::string error_url_suffix(dds::errc ec) noexcept { | |||
| return "invalid-pkg-filesystem.html"; | |||
| case errc::unknown_test_driver: | |||
| return "unknown-test-driver.html"; | |||
| case errc::invalid_pkg_name: | |||
| case errc::invalid_pkg_id: | |||
| return "invalid-pkg-ident.html"; | |||
| case errc::sdist_exists: | |||
| return "sdist-exists.html"; | |||
| case errc::dependency_resolve_failure: | |||
| return "dep-res-failure.html"; | |||
| case errc::dup_lib_name: | |||
| return "dup-lib-name.html"; | |||
| case errc::unknown_usage_name: | |||
| return "unknown-usage.html"; | |||
| case errc::none: | |||
| break; | |||
| } | |||
| @@ -173,6 +184,37 @@ reference on these prescriptions. | |||
| return R"( | |||
| `dds` has a pre-defined set of built-in test drivers, and the one specified is | |||
| not recognized. Check the documentation for more information. | |||
| )"; | |||
| case errc::invalid_pkg_id: | |||
| return R"(Package IDs must follow a strict format of <name>@<version>.)"; | |||
| case errc::invalid_pkg_name: | |||
| return R"(Package names allow a limited set of characters and must not be empty.)"; | |||
| case errc::sdist_exists: | |||
| return R"( | |||
| By default, `dds` will not overwrite source distributions that already exist | |||
| (either in the repository or a filesystem path). Such an action could | |||
| potentially destroy important data. | |||
| )"; | |||
| case errc::dependency_resolve_failure: | |||
| return R"( | |||
| The dependency resolution algorithm failed to resolve the requirements of the | |||
| project. The algorithm's explanation should give enough information to infer | |||
| why there is no possible solution. You may need to reconsider your dependency | |||
| versions to avoid conflicts. | |||
| )"; | |||
| case errc::dup_lib_name: | |||
| return R"( | |||
| `dds` cannot build code correctly when there is more than one library that has | |||
| claimed the same name. It is possible that the duplicate name appears in a | |||
| dependency and is not an issue in your own project. Consult the output to see | |||
| which packages are claiming the library name. | |||
| )"; | |||
| case errc::unknown_usage_name: | |||
| return R"( | |||
| A `Uses` or `Links` field for a library specifies a library of an unknown name. | |||
| Check your spelling, and check that the package containing the library is | |||
| available, either from the `package.dds` or from the `INDEX.lmi` that was used | |||
| for the build. | |||
| )"; | |||
| case errc::none: | |||
| break; | |||
| @@ -226,8 +268,22 @@ std::string_view dds::default_error_string(dds::errc ec) noexcept { | |||
| case errc::invalid_pkg_filesystem: | |||
| return "The filesystem structure of the package/library is invalid. <- (Seeing this text " | |||
| "is a `dds` bug. Please report it.)"; | |||
| case errc::invalid_pkg_id: | |||
| return "A package identifier is invalid <- (Seeing this text is a `dds` bug. Please " | |||
| "report it.)"; | |||
| case errc::invalid_pkg_name: | |||
| return "A package name is invalid <- (Seeing this text is a `dds` bug. Please report it.)"; | |||
| case errc::sdist_exists: | |||
| return "The source ditsribution already exists at the destination <- (Seeing this text is " | |||
| "a `dds` bug. Please report it.)"; | |||
| case errc::unknown_test_driver: | |||
| return "The specified Test-Driver is not known to `dds`"; | |||
| case errc::dependency_resolve_failure: | |||
| return "`dds` was unable to find a solution for the package dependencies given."; | |||
| case errc::dup_lib_name: | |||
| return "More than one library has claimed the same name."; | |||
| case errc::unknown_usage_name: | |||
| return "A `Uses` or `Links` field names a library that isn't recognized."; | |||
| case errc::none: | |||
| break; | |||
| } | |||
| @@ -24,13 +24,19 @@ enum class errc { | |||
| git_clone_failure, | |||
| sdist_ident_mismatch, | |||
| sdist_exists, | |||
| corrupted_build_db, | |||
| invalid_version_range_string, | |||
| invalid_version_string, | |||
| invalid_pkg_id, | |||
| invalid_pkg_name, | |||
| invalid_config_key, | |||
| unknown_test_driver, | |||
| dependency_resolve_failure, | |||
| dup_lib_name, | |||
| unknown_usage_name, | |||
| invalid_lib_filesystem, | |||
| invalid_pkg_filesystem, | |||
| @@ -1,5 +1,7 @@ | |||
| #include <dds/package/id.hpp> | |||
| #include <dds/error/errors.hpp> | |||
| #include <spdlog/fmt/fmt.h> | |||
| #include <tuple> | |||
| @@ -9,7 +11,7 @@ using namespace dds; | |||
| package_id package_id::parse(std::string_view s) { | |||
| auto at_pos = s.find('@'); | |||
| if (at_pos == s.npos) { | |||
| throw std::runtime_error(fmt::format("Invalid package ID string '{}'", s)); | |||
| throw_user_error<errc::invalid_pkg_id>("Invalid package ID '{}'", s); | |||
| } | |||
| auto name = s.substr(0, at_pos); | |||
| @@ -22,8 +24,8 @@ package_id::package_id(std::string_view n, semver::version v) | |||
| : name(n) | |||
| , version(std::move(v)) { | |||
| if (name.find('@') != name.npos) { | |||
| throw std::runtime_error( | |||
| fmt::format("Invalid package name '{}' (The '@' character is not allowed)")); | |||
| throw_user_error<errc::invalid_pkg_name>( | |||
| "Invalid package name '{}' (The '@' character is not allowed)"); | |||
| } | |||
| } | |||
| @@ -28,12 +28,13 @@ package_manifest package_manifest::load_from_file(const fs::path& fpath) { | |||
| lm_reject_dym{{"Name", "Namespace", "Version", "Depends", "Test-Driver"}}); | |||
| if (ret.pkg_id.name.empty()) { | |||
| throw std::runtime_error( | |||
| fmt::format("'Name' field in [{}] may not be an empty string", fpath.string())); | |||
| throw_user_error<errc::invalid_pkg_name>("'Name' field in [{}] may not be an empty string", | |||
| fpath.string()); | |||
| } | |||
| if (version_str.empty()) { | |||
| throw std::runtime_error( | |||
| fmt::format("'Version' field in [{}] may not be an empty string", fpath.string())); | |||
| 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; | |||
| @@ -1,6 +1,7 @@ | |||
| #include "./repo.hpp" | |||
| #include <dds/catalog/catalog.hpp> | |||
| #include <dds/error/errors.hpp> | |||
| #include <dds/solve/solve.hpp> | |||
| #include <dds/source/dist.hpp> | |||
| #include <dds/util/paths.hpp> | |||
| @@ -79,7 +80,7 @@ void repository::add_sdist(const sdist& sd, if_exists ife_action) { | |||
| auto msg = fmt::format("Source distribution '{}' is already available in the local repo", | |||
| sd.path.string()); | |||
| if (ife_action == if_exists::throw_exc) { | |||
| throw std::runtime_error(msg); | |||
| throw_user_error<errc::sdist_exists>(msg); | |||
| } else if (ife_action == if_exists::ignore) { | |||
| spdlog::warn(msg); | |||
| return; | |||
| @@ -1,5 +1,7 @@ | |||
| #include "./solve.hpp" | |||
| #include <dds/error/errors.hpp> | |||
| #include <pubgrub/solve.hpp> | |||
| #include <range/v3/range/conversion.hpp> | |||
| @@ -156,6 +158,6 @@ std::vector<package_id> dds::solve(const std::vector<dependency>& deps, | |||
| } catch (const solve_fail_exc& failure) { | |||
| spdlog::error("Dependency resolution has failed! Explanation:"); | |||
| pubgrub::generate_explaination(failure, explainer()); | |||
| throw; | |||
| throw_user_error<errc::dependency_resolve_failure>(); | |||
| } | |||
| } | |||
| @@ -65,8 +65,8 @@ sdist dds::create_sdist(const sdist_params& params) { | |||
| auto dest = fs::absolute(params.dest_path); | |||
| if (fs::exists(dest)) { | |||
| if (!params.force) { | |||
| throw std::runtime_error( | |||
| fmt::format("Destination path '{}' already exists", dest.string())); | |||
| throw_user_error<errc::sdist_exists>("Destination path '{}' already exists", | |||
| dest.string()); | |||
| } | |||
| } | |||
| @@ -1,6 +1,7 @@ | |||
| #include "./usage_reqs.hpp" | |||
| #include <dds/build/plan/compile_file.hpp> | |||
| #include <dds/error/errors.hpp> | |||
| #include <dds/util/algo.hpp> | |||
| #include <spdlog/fmt/fmt.h> | |||
| @@ -21,8 +22,9 @@ lm::library& usage_requirement_map::add(std::string ns, std::string name) { | |||
| auto pair = std::pair(library_key{ns, name}, lm::library{}); | |||
| auto [inserted, did_insert] = _reqs.try_emplace(library_key{ns, name}, lm::library()); | |||
| if (!did_insert) { | |||
| throw std::runtime_error( | |||
| fmt::format("More than one library is registered as {}/{}", ns, name)); | |||
| throw_user_error<errc::dup_lib_name>("More than one library is registered as `{}/{}'", | |||
| ns, | |||
| name); | |||
| } | |||
| return inserted->second; | |||
| } | |||
| @@ -40,8 +42,9 @@ usage_requirement_map usage_requirement_map::from_lm_index(const lm::index& idx) | |||
| std::vector<fs::path> usage_requirement_map::link_paths(const lm::usage& key) const { | |||
| auto req = get(key); | |||
| if (!req) { | |||
| throw std::runtime_error( | |||
| fmt::format("Unable to find linking requirement '{}/{}'", key.namespace_, key.name)); | |||
| throw_user_error<errc::unknown_usage_name>("Unable to find linking requirement '{}/{}'", | |||
| key.namespace_, | |||
| key.name); | |||
| } | |||
| std::vector<fs::path> ret; | |||
| if (req->linkable_path) { | |||
| @@ -60,10 +63,10 @@ std::vector<fs::path> usage_requirement_map::include_paths(const lm::usage& usag | |||
| std::vector<fs::path> ret; | |||
| auto lib = get(usage.namespace_, usage.name); | |||
| if (!lib) { | |||
| throw std::runtime_error( | |||
| fmt::format("Cannot find non-existent usage requirements for '{}/{}'", | |||
| usage.namespace_, | |||
| usage.name)); | |||
| throw_user_error< | |||
| errc::unknown_usage_name>("Cannot find non-existent usage requirements for '{}/{}'", | |||
| usage.namespace_, | |||
| usage.name); | |||
| } | |||
| extend(ret, lib->include_paths); | |||
| for (const auto& transitive : lib->uses) { | |||