diff --git a/src/search.cpp b/src/search.cpp index daa6d27..3f0a3a9 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -69,9 +69,41 @@ namespace search { return out; } - const std::vector search_paths() { + /// @brief Build a combination of all prefixes, subdirs, and name-like paths + /// @param roots the prefix roots + /// @param name the name of the package to find + /// @return all of the search paths combined into concrete instances + std::vector expand_search_paths(const std::vector & roots, std::string_view name) { // TODO: Windows paths // TODO: MacOS paths + const std::vector segments{platform::libdir(), "share"}; + std::vector paths; + + for (auto && root : roots) { + for (auto && segment : segments) { + if (const fs::path subdir = root / segment / "cps"; fs::is_directory(subdir)) { + paths.emplace_back(subdir); + if (const fs::path namedir = subdir / name; fs::is_directory(namedir)) { + paths.emplace_back(namedir); + for (const fs::path & name_subdir : fs::directory_iterator(namedir)) { + if (fs::is_directory(name_subdir)) { + paths.emplace_back(name_subdir); + } + } + } + } + } + } + + return paths; + } + + /// @brief create concrete search paths for a specific package + /// @param name the name of the package + /// @return a vector of those paths + std::vector search_paths(std::string_view name) { + + // Build all of the roots to search std::vector roots; if (const char * env_c = std::getenv("CPS_PATH")) { auto && env = utils::split(env_c); @@ -79,12 +111,7 @@ namespace search { } roots.emplace_back("/usr"); - std::vector paths; - for (auto && root : roots) { - paths.emplace_back(root / platform::libdir() / "cps"); - paths.emplace_back(root / "share/cps"); - } - return paths; + return expand_search_paths(roots, name); } /// @brief Find all possible paths for a given CPS name @@ -97,19 +124,10 @@ namespace search { } // 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? - auto && paths = search_paths(); + auto && paths = search_paths(name); std::vector found{}; for (auto && dir : paths) { - // TODO: //cps// - // TODO: /share/cps// - // TODO: /share/cps/ - if (fs::is_directory(dir)) { - // TODO: const fs::path file = dir / fmt::format("{}.cps", name); if (fs::is_regular_file(file)) { found.push_back(file); @@ -262,18 +280,31 @@ namespace search { } } - fs::path calculate_prefix(const fs::path & path) { + fs::path calculate_prefix(const fs::path & path, std::string_view name) { // TODO: Windows - // TODO: /cps/ + // TODO: Mac + std::vector split = utils::split(std::string{path}, "/"); + // If the path ends in "/" then an empty string will be placed at + // the end of the split paths if (split.back() == "") { split.pop_back(); } + // If split ends in name, ex: /usr/lib/cps/name/ + if (split.back() == name) { + split.pop_back(); + } + // If split ends in name/*, ex: /usr/lib/cps/name/* + // Then drop both the */ and the name/ + if (*(split.end() - 2) == name) { + split.pop_back(); + split.pop_back(); + } if (split.back() == "cps") { split.pop_back(); } - // Match only share or libdir, but not potentially an odd situation - // like /opt/share/libdir/ + // Match only share or libdir, but not a potential odd situation + // like `/opt/share/libdir/` if (split.back() == "share" || split.back() == platform::libdir()) { split.pop_back(); } @@ -352,7 +383,7 @@ namespace search { // TODO: Windows… auto && split = utils::split(s, "/"); if (split[0] == "@prefix@") { - fs::path p = calculate_prefix(node->data.package.cps_path); + fs::path p = calculate_prefix(node->data.package.cps_path, node->data.package.name); for (auto it = split.begin() + 1; it != split.end(); ++it) { p /= *it; } diff --git a/tests/cases.toml b/tests/cases.toml index 4a9d0f5..c3e37ae 100644 --- a/tests/cases.toml +++ b/tests/cases.toml @@ -77,7 +77,19 @@ expected = "-I/sentinel/err -l/sentinel/lib/libfoo.a" [[case]] - name = "prefix calculated" + name = "prefix calculated (found in root)" + cps = "cps-path-not-set-root" + args = ["--cflags-only-I", "--libs-only-l"] + expected = "-I{prefix}/err -l{prefix}/lib/libfoo.a" + +[[case]] + name = "prefix calculated (found in root/name)" + cps = "cps-path-not-set-subdir" + args = ["--cflags-only-I", "--libs-only-l"] + expected = "-I{prefix}/err -l{prefix}/lib/libfoo.a" + +[[case]] + name = "prefix calculated (root/name/*/)" cps = "cps-path-not-set" args = ["--cflags-only-I", "--libs-only-l"] expected = "-I{prefix}/err -l{prefix}/lib/libfoo.a" diff --git a/tests/cases/lib/cps/cps-path-not-set-root.cps b/tests/cases/lib/cps/cps-path-not-set-root.cps new file mode 100644 index 0000000..a1b36cb --- /dev/null +++ b/tests/cases/lib/cps/cps-path-not-set-root.cps @@ -0,0 +1,13 @@ +{ + "Name": "cps-path-not-set-root", + "Cps-Version": "0.9.0", + "Version": "1.0.0", + "Components": { + "default": { + "Type": "archive", + "Includes": {"C": ["@prefix@/err"]}, + "Location": "@prefix@/lib/libfoo.a" + } + }, + "Default-Components": ["default"] +} \ No newline at end of file diff --git a/tests/cases/lib/cps/cps-path-not-set-subdir/cps-path-not-set-subdir.cps b/tests/cases/lib/cps/cps-path-not-set-subdir/cps-path-not-set-subdir.cps new file mode 100644 index 0000000..336884d --- /dev/null +++ b/tests/cases/lib/cps/cps-path-not-set-subdir/cps-path-not-set-subdir.cps @@ -0,0 +1,15 @@ +{ + "Name": "cps-path-not-set-subdir", + "Cps-Version": "0.9.0", + "Version": "1.0.0", + "Components": { + "default": { + "Type": "archive", + "Includes": {"C": ["@prefix@/err"]}, + "Location": "@prefix@/lib/libfoo.a" + } + }, + "Default-Components": ["default"] +} + + diff --git a/tests/cases/lib/cps/cps-path-not-set.cps b/tests/cases/lib/cps/cps-path-not-set/foo/cps-path-not-set.cps similarity index 100% rename from tests/cases/lib/cps/cps-path-not-set.cps rename to tests/cases/lib/cps/cps-path-not-set/foo/cps-path-not-set.cps diff --git a/tests/cases/lib/cps/diamond.cps b/tests/cases/lib/cps/diamond/diamond.cps similarity index 100% rename from tests/cases/lib/cps/diamond.cps rename to tests/cases/lib/cps/diamond/diamond.cps