Files
cargoxx/src/resolver/brute_scan.cpp

82 lines
2.4 KiB
C++

module cargoxx.resolver;
import std;
import cargoxx.util;
namespace cargoxx::resolver {
namespace fs = std::filesystem;
namespace {
auto is_lib_filename(const fs::path& p) -> bool {
auto name = p.filename().string();
if (!name.starts_with("lib")) {
return false;
}
auto ext = p.extension().string();
if (ext == ".a") {
return true;
}
if (ext == ".so" || ext == ".dylib") {
return true;
}
// .so.<N>, .so.<N>.<M>, ... — common shared-lib versioning. Use a
// looser check: if the name contains ".so." or ".dylib." anywhere
// after the lib prefix, accept it.
return name.find(".so.") != std::string::npos ||
name.find(".dylib.") != std::string::npos;
}
} // namespace
auto brute_scan(const fs::path& store_path, const std::string& package_name)
-> util::Result<BruteCandidate> {
if (package_name.empty()) {
return std::unexpected(util::Error{
util::ErrorCode::ResolutionUnknownPackage,
"brute_scan: package name is empty",
"", std::nullopt, std::nullopt,
});
}
const auto lib_dir = store_path / "lib";
const auto include_dir = store_path / "include";
BruteCandidate out;
std::error_code ec;
if (fs::exists(lib_dir, ec) && !ec) {
for (const auto& entry : fs::directory_iterator{
lib_dir, fs::directory_options::skip_permission_denied, ec}) {
if (!entry.is_regular_file() && !entry.is_symlink()) {
continue;
}
if (!is_lib_filename(entry.path())) {
continue;
}
out.lib_files.push_back(entry.path().string());
}
std::ranges::sort(out.lib_files);
}
if (fs::exists(include_dir, ec) && !ec) {
// For include/, expose the top-level directory itself (e.g.
// `<store>/include`) — that's what `#include <pkg/foo.h>`
// expects. Adding every subdir would also work, but is noisier
// and provokes name collisions across deps.
out.include_dirs.push_back(include_dir.string());
}
if (out.lib_files.empty() && out.include_dirs.empty()) {
return std::unexpected(util::Error{
util::ErrorCode::ResolutionUnknownPackage,
std::format("no libs or headers under '{}'", store_path.string()),
"", store_path, std::nullopt,
});
}
return out;
}
} // namespace cargoxx::resolver