From 6877b083c6b5e4d969af3abdbcce6e1fd35eebae Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 11 Sep 2024 10:24:09 -0700 Subject: [PATCH 1/6] tests/runner.py: add missing type annotations --- tests/runner.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/runner.py b/tests/runner.py index a31158c..3a7e4f8 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -58,7 +58,8 @@ class Result: expected: str command: list[str] -def unordered_compare(out, expected): + +def unordered_compare(out: str, expected: str) -> bool: if out == expected: return True @@ -66,6 +67,7 @@ def unordered_compare(out, expected): expected_parts = expected.split() return sorted(out_parts) == sorted(expected_parts) + async def test(runner: str, case_: TestCase) -> Result: cmd = [runner] + case_['args'] cmd.append(case_['cps'].replace('{prefix}', os.path.join(PREFIX, 'lib/cps'))) From 5af3d7fc3bfda71de02f2f23f0e2e93828186542 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 23 Aug 2024 11:02:14 -0700 Subject: [PATCH 2/6] tests/runner.py: print all of the error message to stderr This was missed for the ` result:` key --- tests/runner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 3a7e4f8..7bdff50 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -122,13 +122,13 @@ async def main() -> None: for r in results: if r.status is not Status.PASS: print(f'{r.name}:', file=sys.stderr) - print(' result:', 'timeout' if r.status is Status.TIMEOUT else 'fail') + print(' result:', 'timeout' if r.status is Status.TIMEOUT else 'fail', file=sys.stderr) print(' returncode:', r.returncode, file=sys.stderr) print(' stdout: ', r.stdout, file=sys.stderr) print(' expected:', r.expected, file=sys.stderr) print(' stderr:', r.stderr, file=sys.stderr) print(' command:', ' '.join(r.command), file=sys.stderr) - print('\n') + print('\n', file=sys.stderr) encountered_failure = True From a46a0caaf662bfae68bccb2f7084648a10195b83 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 11 Sep 2024 13:28:07 -0700 Subject: [PATCH 3/6] meson: move test into sub meson file It matches the cmake, and cleans up the root a bit. --- meson.build | 28 +--------------------------- tests/meson.build | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 27 deletions(-) create mode 100644 tests/meson.build diff --git a/meson.build b/meson.build index 3c4faae..89318c9 100644 --- a/meson.build +++ b/meson.build @@ -33,30 +33,4 @@ cps_config = executable( implicit_include_directories : false, ) -build_tests = get_option('tests') - -python_interpreter = find_program('python', version : '>=3.11', required : build_tests, disabler : true) -foreach t : [['cps integration tests', 'cps-config.toml'], ['pkg-config compatibility', 'pkg-config-compat.toml']] - test( - t[0], - python_interpreter, - args: [files('tests/runner.py'), cps_config, 'tests/cases/' + t[1]], - protocol : 'tap', - env : {'CPS_PREFIX_PATH' : meson.current_source_dir() / 'tests' / 'cps-files' }, - ) -endforeach - -dep_gtest = dependency('gtest_main', required : build_tests, disabler : true, allow_fallback : true) - -foreach t : ['loader', 'version', 'utils'] - test( - t, - executable( - f'@t@_test', - f'tests/@t@.cpp', - dependencies : [dep_cps, dep_gtest, dep_fmt, dep_expected], - implicit_include_directories : false, - ), - protocol : 'gtest', - ) -endforeach +subdir('tests') diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..25adba2 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: MIT +# Copyright © 2024 Dylan Baker + +build_tests = get_option('tests') + +python_interpreter = find_program('python', version : '>=3.11', required : build_tests, disabler : true) +foreach t : [['cps integration tests', 'cps-config.toml'], ['pkg-config compatibility', 'pkg-config-compat.toml']] + test( + t[0], + python_interpreter, + args: [files('runner.py'), cps_config, meson.current_source_dir() / 'cases' / t[1]], + protocol : 'tap', + env : {'CPS_PREFIX_PATH' : meson.current_source_dir() / 'cps-files' }, + ) +endforeach + +dep_gtest = dependency('gtest_main', required : build_tests, disabler : true, allow_fallback : true) + +foreach t : ['loader', 'version', 'utils'] + test( + t, + executable( + f'@t@_test', + f'@t@.cpp', + dependencies : [dep_cps, dep_gtest, dep_fmt, dep_expected], + implicit_include_directories : false, + ), + protocol : 'gtest', + ) +endforeach From 82d4a38d612b1bcb6cd07464040b2f5b1c08de5d Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 11 Sep 2024 13:37:44 -0700 Subject: [PATCH 4/6] env: store cps_prefix_path as an array --- src/cps/env.cpp | 8 +++++--- src/cps/env.hpp | 3 ++- src/cps/search.cpp | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cps/env.cpp b/src/cps/env.cpp index 8fe4b71..71c9f41 100644 --- a/src/cps/env.cpp +++ b/src/cps/env.cpp @@ -2,11 +2,12 @@ // Copyright © 2024 Tyler Weaver // SPDX-License-Identifier: MIT -#include "cps/env.hpp" - #include #include +#include "cps/env.hpp" +#include "cps/utils.hpp" + namespace cps { Env get_env() { @@ -15,7 +16,8 @@ namespace cps { env.cps_path = std::string(env_c); } if (const char * env_c = std::getenv("CPS_PREFIX_PATH")) { - env.cps_prefix_path = std::string(env_c); + // TODO: Windows + env.cps_prefix_path = utils::split(env_c, ":"); } if (std::getenv("PKG_CONFIG_DEBUG_SPEW") || std::getenv("CPS_CONFIG_DEBUG_SPEW")) { env.debug_spew = true; diff --git a/src/cps/env.hpp b/src/cps/env.hpp index 9b12160..d2f3d57 100644 --- a/src/cps/env.hpp +++ b/src/cps/env.hpp @@ -6,12 +6,13 @@ #include #include +#include namespace cps { struct Env { std::optional cps_path = std::nullopt; - std::optional cps_prefix_path = std::nullopt; + std::optional> cps_prefix_path = std::nullopt; bool debug_spew = false; }; diff --git a/src/cps/search.cpp b/src/cps/search.cpp index 9496cb0..e9fb915 100644 --- a/src/cps/search.cpp +++ b/src/cps/search.cpp @@ -110,7 +110,7 @@ namespace cps::search { } if (env.cps_prefix_path) { - auto && prefixes = utils::split(env.cps_prefix_path.value()); + auto && prefixes = env.cps_prefix_path.value(); for (auto && p : prefixes) { auto && paths = expand_prefix(p); cached_paths.reserve(cached_paths.size() + paths.size()); From 21562be057377b72e8200a1fa18942eee0b2eb93 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Thu, 25 Jul 2024 09:46:35 -0700 Subject: [PATCH 5/6] platform: configure the libdir and datadir from the build system Our build systems know what the libdir and datadir that will be used is, and we should honor that. The actual code changes here aren't too complicated, but the test system actually needs a good deal of enhancement to be able to test this correctly. --- CMakeLists.txt | 1 + src/cps/config.hpp.in | 2 + src/cps/meson.build | 2 + src/cps/platform.cpp | 5 +- src/cps/search.cpp | 41 +++++------ tests/CMakeLists.txt | 20 +++++- tests/cases/cps-config.toml | 18 ----- tests/cases/cps-prefix-calculation.toml | 17 +++++ ...th-not-set.cps => cps-path-not-set.cps.in} | 2 +- .../{cps-path-set.cps => cps-path-set.cps.in} | 4 +- tests/cps-files/lib/cps/meson.build | 16 +++++ tests/meson.build | 21 +++++- tests/runner.py | 71 ++++++++++++++----- 13 files changed, 158 insertions(+), 62 deletions(-) create mode 100644 tests/cases/cps-prefix-calculation.toml rename tests/cps-files/lib/cps/{cps-path-not-set.cps => cps-path-not-set.cps.in} (86%) rename tests/cps-files/lib/cps/{cps-path-set.cps => cps-path-set.cps.in} (77%) create mode 100644 tests/cps-files/lib/cps/meson.build diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c64580..db32732 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ project( LANGUAGES CXX VERSION ${VERSION_STRIPPED} ) +include(GNUInstallDirs) add_subdirectory(src) diff --git a/src/cps/config.hpp.in b/src/cps/config.hpp.in index 6a96f53..df0b403 100644 --- a/src/cps/config.hpp.in +++ b/src/cps/config.hpp.in @@ -1,3 +1,5 @@ #pragma once #define CPS_CONFIG_VERSION "${CMAKE_PROJECT_VERSION}" +#define CPS_CONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}" +#define CPS_CONFIG_DATADIR "${CMAKE_INSTALL_DATADIR}" diff --git a/src/cps/meson.build b/src/cps/meson.build index d3e3e31..74a7769 100644 --- a/src/cps/meson.build +++ b/src/cps/meson.build @@ -3,6 +3,8 @@ conf = configuration_data() conf.set_quoted('CPS_CONFIG_VERSION', meson.project_version()) +conf.set_quoted('CPS_CONFIG_LIBDIR', get_option('libdir')) +conf.set_quoted('CPS_CONFIG_DATADIR', get_option('datadir')) conf_h = configure_file( configuration : conf, diff --git a/src/cps/platform.cpp b/src/cps/platform.cpp index ec72f15..1e85bd2 100644 --- a/src/cps/platform.cpp +++ b/src/cps/platform.cpp @@ -2,11 +2,12 @@ // Copyright © 2024 Dylan Baker #include "cps/platform.hpp" +#include "cps/config.hpp" namespace cps::platform { - fs::path libdir() { return "lib"; } + fs::path libdir() { return CPS_CONFIG_LIBDIR; } - fs::path datadir() { return "share"; } + fs::path datadir() { return CPS_CONFIG_DATADIR; } } // namespace cps::platform diff --git a/src/cps/search.cpp b/src/cps/search.cpp index e9fb915..a4ad449 100644 --- a/src/cps/search.cpp +++ b/src/cps/search.cpp @@ -309,7 +309,8 @@ namespace cps::search { } } - fs::path calculate_prefix(const std::optional & path, const fs::path & filename) { + tl::expected calculate_prefix(const std::optional & path, + const fs::path & filename) { // TODO: Windows // TODO: /cps/ if (path) { @@ -319,31 +320,31 @@ namespace cps::search { } 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})); + if (p.stem() != f.stem()) { + return tl::unexpected( + 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(); - } - if (split.back() == "share") { - split.pop_back(); - } - // TODO: this needs to be generic - if (split.back() == "lib") { - split.pop_back(); + fs::path p = filename.parent_path(); + if (p.stem() == "cps") { + p = p.parent_path(); } - fs::path p{"/"}; - for (auto && s : split) { - p /= s; + fs::path dir = platform::datadir(); + while (dir.stem() == p.stem()) { + dir = dir.parent_path(); + p = p.parent_path(); + } + dir = platform::libdir(); + while (dir.stem() == p.stem()) { + dir = dir.parent_path(); + p = p.parent_path(); } return p; } @@ -418,8 +419,8 @@ namespace cps::search { 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 = prefix_path.value_or( + CPS_TRY(calculate_prefix(node->data.package.cps_path, node->data.package.filename))); const auto && prefix_replacer = [&](const std::string & s) -> std::string { // TODO: Windows… diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b68a3de..ae5562c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,6 +32,24 @@ foreach (test_name test_case IN ZIP_LISTS test_names test_cases) COMMAND ${CMAKE_COMMAND} -E env CPS_PREFIX_PATH=${CMAKE_CURRENT_SOURCE_DIR}/cps-files ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/runner.py - $ ${test_case} + $ ${test_case} --libdir "${CMAKE_INSTALL_LIBDIR}" ) endforeach () + +set(infiles + "cps-files/lib/cps/cps-path-not-set.cps" + "cps-files/lib/cps/cps-path-set.cps") +set(libdir ${CMAKE_INSTALL_LIBDIR}) +set(prefix "@prefix@") # Work around for not having the inverse of @ONLY +foreach(infile ${infiles}) + configure_file("${infile}.in" "${infile}") +endforeach() + +add_test( + NAME "prefix calculation tests" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMAND + ${CMAKE_COMMAND} -E env CPS_PREFIX_PATH=${CMAKE_CURRENT_BINARY_DIR}/cps-files + ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/runner.py + $ ${CMAKE_CURRENT_SOURCE_DIR}/cases/cps-prefix-calculation.toml --libdir "${CMAKE_INSTALL_LIBDIR}" --prefix ${PROJECT_BINARY_DIR} +) diff --git a/tests/cases/cps-config.toml b/tests/cases/cps-config.toml index 74f7d5a..390f951 100644 --- a/tests/cases/cps-config.toml +++ b/tests/cases/cps-config.toml @@ -72,24 +72,6 @@ cps = "multiple-components" args = ["flags", "--cflags-only-I", "--component", "requires-external"] expected = "-I/err" -[[case]] -name = "prefix set" -cps = "cps-path-set" -args = ["flags", "--cflags-only-I", "--libs-only-l"] -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" -cps = "cps-path-not-set" -args = ["flags", "--cflags-only-I", "--libs-only-l"] -expected = "-I{prefix}/err -l{prefix}/lib/libfoo.a" - [[case]] name = "component diamond" cps = "diamond" diff --git a/tests/cases/cps-prefix-calculation.toml b/tests/cases/cps-prefix-calculation.toml new file mode 100644 index 0000000..c85b5eb --- /dev/null +++ b/tests/cases/cps-prefix-calculation.toml @@ -0,0 +1,17 @@ +[[case]] +name = "prefix set" +cps = "cps-path-set" +args = ["flags", "--cflags-only-I", "--libs-only-l", "--print-errors"] +expected = "-I{prefix}/err -l{prefix}/{libdir}/libfoo.a" + +[[case]] +name = "prefix set (called by path)" +cps = "{prefix}/cps-path-set.cps" +args = ["flags", "--cflags-only-I", "--libs-only-l", "--print-errors"] +expected = "-I{prefix}/err -l{prefix}/{libdir}/libfoo.a" + +[[case]] +name = "prefix calculated" +cps = "cps-path-not-set" +args = ["flags", "--cflags-only-I", "--libs-only-l"] +expected = "-I{prefix}/err -l{prefix}/{libdir}/libfoo.a" diff --git a/tests/cps-files/lib/cps/cps-path-not-set.cps b/tests/cps-files/lib/cps/cps-path-not-set.cps.in similarity index 86% rename from tests/cps-files/lib/cps/cps-path-not-set.cps rename to tests/cps-files/lib/cps/cps-path-not-set.cps.in index 8ac0202..cb3b4a1 100644 --- a/tests/cps-files/lib/cps/cps-path-not-set.cps +++ b/tests/cps-files/lib/cps/cps-path-not-set.cps.in @@ -10,7 +10,7 @@ "@prefix@/err" ] }, - "location": "@prefix@/lib/libfoo.a" + "location": "@prefix@/${libdir}/libfoo.a" } }, "default_components": [ diff --git a/tests/cps-files/lib/cps/cps-path-set.cps b/tests/cps-files/lib/cps/cps-path-set.cps.in similarity index 77% rename from tests/cps-files/lib/cps/cps-path-set.cps rename to tests/cps-files/lib/cps/cps-path-set.cps.in index 5f4afee..59ccebc 100644 --- a/tests/cps-files/lib/cps/cps-path-set.cps +++ b/tests/cps-files/lib/cps/cps-path-set.cps.in @@ -1,7 +1,7 @@ { "name": "cps-path-set", "cps_version": "0.10.0", - "cps_path": "@prefix@/lib/cps/", + "cps_path": "@prefix@/${libdir}/cps/", "version": "1.0.0", "components": { "default": { @@ -11,7 +11,7 @@ "@prefix@/err" ] }, - "location": "@prefix@/lib/libfoo.a" + "location": "@prefix@/${libdir}/libfoo.a" } }, "default_components": [ diff --git a/tests/cps-files/lib/cps/meson.build b/tests/cps-files/lib/cps/meson.build new file mode 100644 index 0000000..390e0ce --- /dev/null +++ b/tests/cps-files/lib/cps/meson.build @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: MIT +# Copyright © 2024 Dylan Baker + +conf = configuration_data() +conf.set('libdir', get_option('libdir')) +# Should be required, but: https://github.com/mesonbuild/meson/issues/13665 +conf.set('prefix', '@prefix@') + +foreach infile : ['cps-path-set.cps.in', 'cps-path-not-set.cps.in'] + configure_file( + configuration : conf, + input : infile, + output : '@BASENAME@', + format : 'cmake', + ) +endforeach diff --git a/tests/meson.build b/tests/meson.build index 25adba2..63b2d7a 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,18 +1,37 @@ # SPDX-License-Identifier: MIT # Copyright © 2024 Dylan Baker +subdir('cps-files/lib/cps') + build_tests = get_option('tests') python_interpreter = find_program('python', version : '>=3.11', required : build_tests, disabler : true) +runner_args = [ + files('runner.py'), + cps_config, + '--libdir', get_option('libdir'), +] + foreach t : [['cps integration tests', 'cps-config.toml'], ['pkg-config compatibility', 'pkg-config-compat.toml']] test( t[0], python_interpreter, - args: [files('runner.py'), cps_config, meson.current_source_dir() / 'cases' / t[1]], + args: [runner_args, meson.current_source_dir() / 'cases' / t[1]], protocol : 'tap', env : {'CPS_PREFIX_PATH' : meson.current_source_dir() / 'cps-files' }, ) endforeach +test( + 'prefix calculation tests', + python_interpreter, + args: [ + runner_args, + '--prefix', meson.project_build_root(), + meson.current_source_dir() / 'cases' / 'cps-prefix-calculation.toml', + ], + protocol : 'tap', + env : {'CPS_PREFIX_PATH' : meson.current_build_dir() / 'cps-files' }, +) dep_gtest = dependency('gtest_main', required : build_tests, disabler : true, allow_fallback : true) diff --git a/tests/runner.py b/tests/runner.py index 7bdff50..5e2f9e4 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -6,10 +6,13 @@ import argparse import asyncio +import contextlib import dataclasses import enum import os +import shutil import sys +import tempfile import tomllib import typing @@ -19,6 +22,8 @@ class Arguments(typing.Protocol): runner: str cases: str + libdir: str + prefix: str | None class TestCase(typing.TypedDict): @@ -35,7 +40,6 @@ class TestDescription(typing.TypedDict): SOURCE_DIR = os.path.normpath(os.path.dirname(os.path.dirname(__file__))) -PREFIX = os.path.join(SOURCE_DIR, 'tests/cps-files') _PRINT_LOCK = asyncio.Lock() @@ -68,13 +72,15 @@ def unordered_compare(out: str, expected: str) -> bool: return sorted(out_parts) == sorted(expected_parts) -async def test(runner: str, case_: TestCase) -> Result: - cmd = [runner] + case_['args'] - cmd.append(case_['cps'].replace('{prefix}', os.path.join(PREFIX, 'lib/cps'))) +async def test(args: Arguments, case_: TestCase) -> Result: + prefix = args.prefix or SOURCE_DIR + + cmd = [args.runner] + case_['args'] + cmd.append(case_['cps'].replace('{prefix}', os.path.join(prefix, args.libdir, 'cps'))) if 'mode' in case_: cmd.extend([f"--format={case_['mode']}"]) - expected = case_['expected'].format(prefix=PREFIX) + expected = case_['expected'].format(prefix=prefix, libdir=args.libdir) try: async with asyncio.timeout(5): @@ -102,20 +108,12 @@ async def test(runner: str, case_: TestCase) -> Result: return Result(case_['name'], result, out, err, returncode, expected, cmd) -async def main() -> None: - parser = argparse.ArgumentParser() - parser.add_argument('runner', help="The compiled cps-config binary") - parser.add_argument('cases', help="A toml file containing case descriptions") - args: Arguments = parser.parse_args() - - with open(os.path.join(SOURCE_DIR, args.cases), 'rb') as f: - tests = typing.cast('TestDescription', tomllib.load(f)) - +async def run_tests(args: Arguments, tests: TestDescription) -> bool: print(f'1..{len(tests["case"])}') results = typing.cast( 'list[Result]', - await asyncio.gather(*[test(args.runner, c) for c in tests['case']])) + await asyncio.gather(*[test(args, c) for c in tests['case']])) encountered_failure: bool = False @@ -132,8 +130,47 @@ async def main() -> None: encountered_failure = True - if encountered_failure: - exit(1) + return encountered_failure + + +async def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument('runner', help="The compiled cps-config binary") + parser.add_argument('cases', help="A toml file containing case descriptions") + parser.add_argument('--libdir', default='lib', help="the build system configured libdir") + parser.add_argument('--prefix', default=None, help="The prefix tests are realtive to") + args: Arguments = parser.parse_args() + + with open(os.path.join(SOURCE_DIR, args.cases), 'rb') as f: + tests = typing.cast('TestDescription', tomllib.load(f)) + + with contextlib.ExitStack() as stack: + # If the libdir is not "lib" (which tests assume), create a symlink to + # the expected libdir + if args.libdir != 'lib' or args.prefix: + prefix = str(os.environ['CPS_PREFIX_PATH']) + tmpdir = tempfile.mkdtemp() + stack.callback(shutil.rmtree, tmpdir) + os.environ['CPS_PREFIX_PATH'] = tmpdir + + # Also override the prefix, which is used to calculate @prefix@ + args.prefix = tmpdir + + # Handle libdir with multiple paths, like lib/x86_64-linux-gnu + root, libdir = os.path.split(args.libdir) + if root: + tmpdir = os.path.join(tmpdir, root) + os.makedirs(tmpdir, exist_ok=True) + + source = os.path.join(prefix, 'lib') + dest = os.path.join(tmpdir, libdir) + os.symlink(source, dest) + stack.callback(os.unlink, dest) + + failed = await run_tests(args, tests) + + sys.exit(1 if failed else 0) + if __name__ == "__main__": asyncio.run(main()) From b51954dc7c88372f861ba2911e7270d39337d2dc Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 23 Aug 2024 11:55:47 -0700 Subject: [PATCH 6/6] search: Be smarter about removing datadir and libdir to calculate a prefix There are two corrections here: 1) only remove one, either the datadir or the libdir 2) only remove the directory if the whole directory can be removed, for example: the prefix is `/usr/lib/foo/x86_64-linux-gnu`, and the libdir is `lib/x86_64-linux-gnu`, we don't want to take off just the `x86_64-linux-gnu`, we want to leave the whole thing since we couldn't remove the entire libdir. --- src/cps/search.cpp | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/cps/search.cpp b/src/cps/search.cpp index a4ad449..43a78d5 100644 --- a/src/cps/search.cpp +++ b/src/cps/search.cpp @@ -332,21 +332,31 @@ namespace cps::search { } fs::path p = filename.parent_path(); + + const auto reducer = [&p](fs::path dir) -> std::optional { + fs::path np = p; + + // remove a trailing slash + if (dir.stem() == "") { + dir = dir.parent_path(); + } + + while (dir.stem() == np.stem()) { + dir = dir.parent_path(); + np = np.parent_path(); + } + + // If our new path has changed and we have consumed the entire + // directory, then return that, otherwise this was not + // successful. + return np != p && dir == dir.root_path() ? std::optional{np} : std::nullopt; + }; + if (p.stem() == "cps") { p = p.parent_path(); } - fs::path dir = platform::datadir(); - while (dir.stem() == p.stem()) { - dir = dir.parent_path(); - p = p.parent_path(); - } - dir = platform::libdir(); - while (dir.stem() == p.stem()) { - dir = dir.parent_path(); - p = p.parent_path(); - } - return p; + return reducer(platform::libdir()).value_or(reducer(platform::datadir()).value_or(p)); } /// @brief Calculate the required components in the graph