Skip to content

Commit

Permalink
search: provide better error messages for why a package wasn't selected
Browse files Browse the repository at this point in the history
This provides messages that better explain why a cps file could not be
found, whether there isn't one named in that path, or if there's a
version mismatch, or dependency that is missing.
  • Loading branch information
dcbaker committed Oct 3, 2024
1 parent 2c84240 commit df2064f
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 3 deletions.
19 changes: 18 additions & 1 deletion src/cps/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "cps/version.hpp"

#include <fmt/core.h>
#include <fmt/ranges.h>
#include <tl/expected.hpp>

#include <algorithm>
Expand All @@ -27,6 +28,8 @@ namespace cps::search {

namespace {

using version::to_string;

/// @brief A CPS file, along with the components in that CPS file to
/// load
class Dependency {
Expand Down Expand Up @@ -222,10 +225,12 @@ namespace cps::search {
tl::expected<std::shared_ptr<Node>, std::string>
build_node(std::string_view name, const loader::Requirement & requirements, NodeFactory factory, Env env) {
const std::vector<fs::path> paths = CPS_TRY(find_paths(name, env));
std::vector<std::string> errors{};
for (auto && path : paths) {

auto maybe_node = factory.get(name, path);
if (!maybe_node) {
errors.emplace_back(fmt::format("No CPS file for {} in path {}", name, path.string()));
continue;
}
auto node = maybe_node.value();
Expand All @@ -242,26 +247,38 @@ namespace cps::search {
// > If not provided, the CPS will not satisfy any request for
// > a specific version of the package.
if (!p.version) {
errors.emplace_back(
fmt::format("Tried {}, which does not specify a version, but the user requires version {}",
path.string(), requirements.version.value()));
continue;
}
if (version::compare(p.version.value(), version::Operator::lt, requirements.version.value(),
p.version_schema)) {
errors.emplace_back(fmt::format(
"{} has a version of {}, which is less than the required {}, using the schema {}",
path.string(), p.version.value(), requirements.version.value(),
to_string(p.version_schema)));
continue;
}
}

if (!std::all_of(requirements.components.begin(), requirements.components.end(),
[p](const std::string & c) { return p.components.find(c) != p.components.end(); })) {
// TODO: more fine grained error message
errors.emplace_back(fmt::format("{} does not implement all of the required components '{}'",
path.string(), fmt::join(requirements.components, ", ")));
continue;
}

std::vector<std::shared_ptr<Node>> found;
found.reserve(p.require.size());
for (auto && [n, r] : p.require) {
auto && child = build_node(n, r, factory, env);

if (child) {
found.emplace_back(child.value());
} else {
errors.emplace_back(child.error());
break;
}
}
Expand All @@ -273,7 +290,7 @@ namespace cps::search {
return node;
}

return tl::unexpected(fmt::format("Could not find a dependency to satisfy {}", name));
return tl::unexpected(fmt::format("{}:\n {}", name, fmt::join(errors, "\n ")));
}

tl::expected<std::shared_ptr<Node>, std::string> build_node(std::string_view name,
Expand Down
3 changes: 2 additions & 1 deletion tests/cases/cps-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ expected = "-I/something -I/opt/include"
name = "Requires version, but version not set"
cps = "needs-version"
args = ["flags", "--modversion", "--print-errors", "--errors-to-stdout"]
expected = "Could not find a dependency to satisfy needs-version"
expected = "Tried /.*/cps-files/lib/cps/multiple-components.cps, which does not specify a version, but the user requires version 1.0"
re = true
returncode = 1

[[case]]
Expand Down
3 changes: 2 additions & 1 deletion tests/cases/pkg-config-compat.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,6 @@ expected = "-I/usr/local/include -I/opt/include"
name = "Requires version, but version not set"
cps = "needs-version"
args = ["pkg-config", "--modversion", "--print-errors", "--errors-to-stdout"]
expected = "Could not find a dependency to satisfy needs-version"
expected = "Tried /.*/cps-files/lib/cps/multiple-components.cps, which does not specify a version, but the user requires version 1.0"
returncode = 1
re = true
15 changes: 15 additions & 0 deletions tests/cps-files/lib/cps/has-compat-version.cps
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "has-compat-version",
"cps_version": "0.12.0",
"version": "1.0.700344",
"compat_version": "1.0.0",
"components": {
"default": {
"type": "archive",
"location": "/usr/lib/libfoo.a"
}
},
"default_components": [
"default"
]
}

0 comments on commit df2064f

Please sign in to comment.