From e3324589503f31945c14ad8f176c3ab43790e5aa Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 9 Sep 2024 13:45:03 -0700 Subject: [PATCH] search: fix use of cps_path This must be @prefix@ prefaced, and is used to describe how the prefix is calculated when the cps file is passed by path, not to calculate a prefix which is different than where the cps file is located. --- src/cps/loader.cpp | 6 ++-- src/cps/loader.hpp | 3 +- src/cps/search.cpp | 36 ++++++++++++++++-------- tests/cases/cps-config.toml | 8 +++++- tests/cps-files/lib/cps/cps-path-set.cps | 2 +- tests/runner.py | 3 +- 6 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/cps/loader.cpp b/src/cps/loader.cpp index 21fc014..c0a0ee0 100644 --- a/src/cps/loader.cpp +++ b/src/cps/loader.cpp @@ -1,5 +1,5 @@ // Copyright © 2023-2024 Dylan Baker -// Copyright © 2024 Bret Brown +// Copyright © 2024 Dylan Baker // SPDX-License-Identifier: MIT #include "cps/loader.hpp" @@ -293,8 +293,7 @@ namespace cps::loader { auto const name = CPS_TRY(get_required(root, "package", "name")); auto const cps_version = CPS_TRY(get_required(root, "package", "cps_version")); auto const components = CPS_TRY(get_required(root, "package", "components")); - auto const cps_path = - CPS_TRY(get_optional(root, "package", "cps_path")).value_or(filename.parent_path()); + auto const cps_path = CPS_TRY(get_optional(root, "package", "cps_path")); auto const default_components = CPS_TRY(get_optional>(root, "package", "default_components")); auto const platform = std::nullopt; // TODO: parse platform @@ -315,6 +314,7 @@ namespace cps::loader { .cps_version = std::move(cps_version), .components = std::move(components), .cps_path = std::move(cps_path), + .filename = filename, .default_components = std::move(default_components), .platform = std::move(platform), .require = std::move(require), // requires is a keyword diff --git a/src/cps/loader.hpp b/src/cps/loader.hpp index 3b1a094..41bce71 100644 --- a/src/cps/loader.hpp +++ b/src/cps/loader.hpp @@ -135,7 +135,8 @@ namespace cps::loader { // TODO: compat-version // TODO: configuration // TODO: configurations - std::string cps_path; + std::optional cps_path; + std::string filename; std::optional> default_components; std::optional platform; Requires require; // Requires is a keyword diff --git a/src/cps/search.cpp b/src/cps/search.cpp index 27e6830..9496cb0 100644 --- a/src/cps/search.cpp +++ b/src/cps/search.cpp @@ -309,13 +309,27 @@ namespace cps::search { } } - fs::path calculate_prefix(const fs::path & path) { + fs::path calculate_prefix(const std::optional & path, const fs::path & filename) { // TODO: Windows // TODO: /cps/ - std::vector split = utils::split(std::string{path}, "/"); - if (split.back() == "") { - split.pop_back(); + if (path) { + fs::path p{path.value()}; + if (p.stem() == "") { + p = p.parent_path(); + } + fs::path f = filename.parent_path(); + while (p != "@prefix@") { + utils::assert_fn( + p.stem() == f.stem(), + fmt::format("filepath and cps_path have non overlapping stems, prefix: {}, filename {}", + std::string{p}, std::string{f})); + p = p.parent_path(); + f = f.parent_path(); + } + return f; } + + std::vector split = utils::split(std::string{filename.parent_path()}, "/"); if (split.back() == "cps") { split.pop_back(); } @@ -326,6 +340,7 @@ namespace cps::search { if (split.back() == "lib") { split.pop_back(); } + fs::path p{"/"}; for (auto && s : split) { p /= s; @@ -398,20 +413,19 @@ namespace cps::search { result.version = root->data.package.version.value_or("unknown"); - const auto prefix_path = [&]() -> std::optional { - if (prefix_variable) { - return fs::path{prefix_variable.value()}; - } - return std::nullopt; - }(); + const auto prefix_path = + prefix_variable.has_value() ? std::optional{fs::path{prefix_variable.value()}} : std::nullopt; for (auto && node : flat) { + const auto prefix = + prefix_path.value_or(calculate_prefix(node->data.package.cps_path, node->data.package.filename)); + const auto && prefix_replacer = [&](const std::string & s) -> std::string { // TODO: Windows… auto && split = utils::split(s, "/"); if (split[0] == "@prefix@") { - auto p = prefix_path.value_or(calculate_prefix(node->data.package.cps_path)); + fs::path p = prefix; for (auto it = split.begin() + 1; it != split.end(); ++it) { p /= *it; } diff --git a/tests/cases/cps-config.toml b/tests/cases/cps-config.toml index cf1c78f..74f7d5a 100644 --- a/tests/cases/cps-config.toml +++ b/tests/cases/cps-config.toml @@ -76,7 +76,13 @@ expected = "-I/err" name = "prefix set" cps = "cps-path-set" args = ["flags", "--cflags-only-I", "--libs-only-l"] -expected = "-I/sentinel/err -l/sentinel/lib/libfoo.a" +expected = "-I{prefix}/err -l{prefix}/lib/libfoo.a" + +[[case]] +name = "prefix set (called by path)" +cps = "{prefix}/cps-path-set.cps" +args = ["flags", "--cflags-only-I", "--libs-only-l"] +expected = "-I{prefix}/err -l{prefix}/lib/libfoo.a" [[case]] name = "prefix calculated" diff --git a/tests/cps-files/lib/cps/cps-path-set.cps b/tests/cps-files/lib/cps/cps-path-set.cps index 8b14f72..5f4afee 100644 --- a/tests/cps-files/lib/cps/cps-path-set.cps +++ b/tests/cps-files/lib/cps/cps-path-set.cps @@ -1,7 +1,7 @@ { "name": "cps-path-set", "cps_version": "0.10.0", - "cps_path": "/sentinel/lib/cps/", + "cps_path": "@prefix@/lib/cps/", "version": "1.0.0", "components": { "default": { diff --git a/tests/runner.py b/tests/runner.py index d56f57f..a31158c 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -67,7 +67,8 @@ def unordered_compare(out, expected): return sorted(out_parts) == sorted(expected_parts) async def test(runner: str, case_: TestCase) -> Result: - cmd = [runner] + case_['args'] + [case_['cps']] + cmd = [runner] + case_['args'] + cmd.append(case_['cps'].replace('{prefix}', os.path.join(PREFIX, 'lib/cps'))) if 'mode' in case_: cmd.extend([f"--format={case_['mode']}"])