Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement name-like search paths #31

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/cps/loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ namespace cps::loader {

auto const name = CPS_TRY(get_required<std::string>(root, "package", "name"));
auto const cps_version = CPS_TRY(get_required<std::string>(root, "package", "cps_version"));
auto const compat_version = CPS_TRY(get_optional<std::string>(root, "package", "compat_version"));
auto const components = CPS_TRY(get_required<Components>(root, "package", "components"));
auto const cps_path = CPS_TRY(get_optional<std::string>(root, "package", "cps_path"));
auto const default_components =
Expand All @@ -330,6 +331,7 @@ namespace cps::loader {
.name = std::move(name),
.cps_version = std::move(cps_version),
.components = std::move(components),
.compat_version = std::move(compat_version),
.cps_path = std::move(cps_path),
.filename = filename.string(),
.default_components = std::move(default_components),
Expand Down
2 changes: 1 addition & 1 deletion src/cps/loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ namespace cps::loader {
std::string name;
std::string cps_version;
std::unordered_map<std::string, Component> components;
// TODO: compat-version
std::optional<std::string> compat_version;
// TODO: configuration
// TODO: configurations
std::optional<std::string> cps_path;
Expand Down
67 changes: 53 additions & 14 deletions src/cps/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <tl/expected.hpp>

#include <algorithm>
#include <cctype>
#include <deque>
#include <filesystem>
#include <fstream>
Expand Down Expand Up @@ -139,19 +140,46 @@ namespace cps::search {
return std::vector<fs::path>{name};
}

// If the given name is not all lower, we need to search that as well.
std::vector<std::string> names{std::string{name}};
std::string lc{name};
std::transform(lc.begin(), lc.end(), lc.begin(), [](const unsigned char ch) { return std::tolower(ch); });
if (name != lc) {
names.push_back(lc);
}

// TODO: Need something like pkgconf's --personality option
// TODO: we likely either need to return all possible files, or load
// a file
// TODO: what to do about finding multiple versions of the same
// dependency?

// Each prefix must be searched for (assuming Name is the term):
//
// - Name/*.cps
// - name/*.cps
// - Name.cps
// - name.cps
//
// TODO: should we allow symlinks?
auto && paths = search_paths(env);
std::vector<fs::path> found{};
for (auto && path : paths) {
if (fs::is_directory(path)) {
// TODO: <name-like>
const fs::path file = path / fmt::format("{}.cps", name);
if (fs::is_regular_file(file)) {
found.push_back(file);
for (auto && cname : names) {
for (auto && path : paths) {
if (fs::is_directory(path)) {
const fs::path namelike = path / cname;
if (fs::is_directory(namelike)) {
for (auto && trial : fs::directory_iterator(namelike)) {
auto && tpath = trial.path();
if (fs::is_regular_file(tpath) && tpath.extension() == ".cps") {
found.push_back(tpath);
}
}
}
const fs::path file = path / fmt::format("{}.cps", cname);
if (fs::is_regular_file(file)) {
found.push_back(file);
}
}
}
}
Expand Down Expand Up @@ -239,7 +267,7 @@ namespace cps::search {
const loader::Package & p = node->data.package;

// If this package doesn't meet the requirements then reject it and continue on.
// The conditions it could fail to meet are:
// The conditions it couldIf we fail to meet are:
// 1. the provided version (or Compat-Version) is < the required version
// 2. This package lacks required components
if (requirements.version) {
Expand All @@ -248,14 +276,25 @@ 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()));
if (!(p.version || p.compat_version)) {
errors.emplace_back(fmt::format("Tried {}, which does not specify a version or compat_version, "
"but the user requires version {}",
path.string(), requirements.version.value()));
continue;
}
auto && v = version::compare(p.version.value(), version::Operator::lt, requirements.version.value(),
p.version_schema);
// From the CPS spec, version 0.12.0, for package::compat_version
//
// > Specifies the oldest version of the package with which
// > this version is compatible. This information is used when
// > a consumer requests a specific version. If the version
// > requested is equal to or newer than the compat_version,
// > the package may be used.
//
// > If not specified, the package is not compatible with
// > previous versions (i.e. compat_version is implicitly
// > equal to version).
auto && v = version::compare(p.compat_version.value_or(p.version.value()), version::Operator::lt,
requirements.version.value(), p.version_schema);
if (!v) {
errors.emplace_back(fmt::format("{}: {}", path.string(), v.error()));
continue;
Expand All @@ -264,7 +303,7 @@ namespace cps::search {
if (v.value()) {
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(),
path.string(), p.compat_version.value_or(p.version.value()), requirements.version.value(),
to_string(p.version_schema)));
continue;
}
Expand Down
26 changes: 25 additions & 1 deletion tests/cases/cps-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ 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 = "Tried /.*/cps/multiple-components.cps, which does not specify a version, but the user requires version 1.0"
expected = "Tried /.*/cps/multiple-components.cps, which does not specify a version or compat_version, but the user requires version 1.0"
re = true
returncode = 1

Expand Down Expand Up @@ -121,3 +121,27 @@ name = "Star components override by name"
cps = "full"
args = ["flags", "--component", "star_values_override", "--cflags", "--print-errors"]
expected = "-fvectorize -I/usr/local/include -I/opt/include -DBAR=2 -DFOO=1 -DOTHER"

[[case]]
name = "Sets compat_version"
cps = "needs-compat-version"
args = ["flags", "--libs", "--print-errors"]
expected = "-l/usr/lib/libfoo.a"

[[case]]
name = "name-like search in directory"
cps = "dir"
args = ["flags", "--cflags", "--libs", "--print-errors"]
expected = "-I/usr/include/dir -l/usr/lib/libdir.so"

[[case]]
name = "name-like search in directory different case"
cps = "DiR"
args = ["flags", "--cflags", "--libs", "--print-errors"]
expected = "-I/usr/include/dir -l/usr/lib/libdir.so"

[[case]]
name = "name-like search with different case"
cps = "MiNimAl"
args = ["flags", "--cflags", "--print-errors"]
expected = "-fopenmp -I/usr/local/include -I/opt/include -DFOO=1 -DBAR=2 -DOTHER"
2 changes: 1 addition & 1 deletion tests/cases/pkg-config-compat.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +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 = "Tried /.*/cps/multiple-components.cps, which does not specify a version, but the user requires version 1.0"
expected = "Tried /.*/cps/multiple-components.cps, which does not specify a version or compat_version, but the user requires version 1.0"
returncode = 1
re = true
17 changes: 17 additions & 0 deletions tests/cps-files/lib/cps/dir/dir-1.2.cps
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "dir",
"cps_version": "0.12.0",
"version": "1.2.0",
"components": {
"default": {
"type": "archive",
"includes": {
"c": ["/usr/include/dir"]
},
"location": "/usr/lib/libdir.so"
}
},
"default_components": [
"default"
]
}
19 changes: 19 additions & 0 deletions tests/cps-files/lib/cps/needs-compat-version.cps
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "needs-components2",
"cps_version": "0.12.0",
"requires": {
"has-compat-version": {
"components": ["default"],
"version": "1.0.0"
}
},
"components": {
"default": {
"type": "interface",
"requires": ["has-compat-version"]
}
},
"default_components": [
"default"
]
}
Loading