From ea21bce031d679e23c27814dc6e129f4e2b1fc00 Mon Sep 17 00:00:00 2001 From: Klaus Aehlig Date: Tue, 10 May 2022 16:45:57 +0200 Subject: Ensure we also correctly handle tree conflicts between files Not only trees, but also regular files can disallow paths reaching into them. If we have a file at a/b then another file at a/b/c is a staging conflict as well. Make our tool recognize this. --- src/buildtool/build_engine/target_map/utils.cpp | 38 +++++++++++++++---------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'src/buildtool/build_engine/target_map/utils.cpp') diff --git a/src/buildtool/build_engine/target_map/utils.cpp b/src/buildtool/build_engine/target_map/utils.cpp index bdd5dd11..4dcafa4f 100644 --- a/src/buildtool/build_engine/target_map/utils.cpp +++ b/src/buildtool/build_engine/target_map/utils.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "src/utils/cpp/path.hpp" @@ -91,23 +92,30 @@ auto BuildMaps::Target::Utils::artifacts_tree(const ExpressionPtr& map) auto BuildMaps::Target::Utils::tree_conflict(const ExpressionPtr& map) -> std::optional { - std::vector trees{}; - for (auto const& [path, artifact] : map->Map()) { - if (artifact->Artifact().IsTree()) { - trees.emplace_back(ToNormalPath(std::filesystem::path{path})); + // Work around the fact that std::hash is missing + // in some libraries + struct PathHash { + auto operator()(std::filesystem::path const& p) const noexcept + -> std::size_t { + return std::filesystem::hash_value(p); } - } - if (trees.empty()) { - return std::nullopt; - } + }; + std::unordered_set blocked{}; + blocked.reserve(map->Map().size()); + for (auto const& [path, artifact] : map->Map()) { - auto p = ToNormalPath(std::filesystem::path{path}); - for (auto const& treepath : trees) { - if (not artifact->Artifact().IsTree()) { - if (std::mismatch(treepath.begin(), treepath.end(), p.begin()) - .first == treepath.end()) { - return path; - } + if (path == "." and map->Map().size() > 1) { + return "."; + } + auto p = std::filesystem::path{path}; + auto insert_result = blocked.insert(p); + if (not insert_result.second) { + return p.string(); // duplicate path + } + for (p = p.parent_path(); not p.empty(); p = p.parent_path()) { + if (blocked.contains(p)) { + // Another artifact at a parent path position + return p.string(); } } } -- cgit v1.2.3