diff --git a/toolsrc/include/vcpkg/base/strings.h b/toolsrc/include/vcpkg/base/strings.h index 4b39b0a28..04e85107e 100644 --- a/toolsrc/include/vcpkg/base/strings.h +++ b/toolsrc/include/vcpkg/base/strings.h @@ -56,12 +56,10 @@ namespace vcpkg::Strings bool case_insensitive_ascii_starts_with(const std::string& s, const std::string& pattern); bool ends_with(const std::string& s, StringLiteral pattern); - template - std::string join(const char* delimiter, const Container& v, Transformer transformer) + template + std::string join(const char* delimiter, InputIterator begin, InputIterator end, + Transformer transformer) { - const auto begin = v.begin(); - const auto end = v.end(); - if (begin == end) { return std::string(); @@ -77,6 +75,24 @@ namespace vcpkg::Strings return output; } + + template + std::string join(const char* delimiter, const Container& v, Transformer transformer) + { + const auto begin = v.begin(); + const auto end = v.end(); + + return join(delimiter, begin, end, transformer); + } + + template + std::string join(const char* delimiter, InputIterator begin, InputIterator end) + { + using Element = decltype(*begin); + return join(delimiter, begin, end, + [](const Element& x) -> const Element& { return x; }); + } + template std::string join(const char* delimiter, const Container& v) { diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 434876871..7fc8b294b 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -19,6 +19,8 @@ namespace vcpkg::Install { using namespace Dependencies; + using file_pack = std::pair; + InstallDir InstallDir::from_destination_root(const fs::path& destination_root, const std::string& destination_subdirectory, const fs::path& listfile) @@ -139,18 +141,12 @@ namespace vcpkg::Install fs.write_lines(listfile, output); } - static void remove_first_n_chars(std::vector* strings, const size_t n) + static std::vector extract_files_in_triplet( + const std::vector& pgh_and_files, + const Triplet& triplet, + const size_t remove_chars = 0) { - for (std::string& s : *strings) - { - s.erase(0, n); - } - }; - - static std::vector extract_files_in_triplet( - const std::vector& pgh_and_files, const Triplet& triplet) - { - std::vector output; + std::vector output; for (const StatusParagraphAndAssociatedFiles& t : pgh_and_files) { if (t.pgh.package.spec.triplet() != triplet) @@ -158,10 +154,16 @@ namespace vcpkg::Install continue; } - Util::Vectors::concatenate(&output, t.files); + const std::string name = t.pgh.package.displayname(); + + for (const std::string &file : t.files) + { + output.emplace_back(file_pack{std::string(file, remove_chars), name}); + } } - std::sort(output.begin(), output.end()); + std::sort(output.begin(), output.end(), + [](const file_pack &lhs, const file_pack &rhs) { return lhs.first < rhs.first; }); return output; } @@ -171,22 +173,21 @@ namespace vcpkg::Install const std::vector package_file_paths = fs.get_files_recursive(package_dir); const size_t package_remove_char_count = package_dir.generic_string().size() + 1; // +1 for the slash auto package_files = Util::fmap(package_file_paths, [package_remove_char_count](const fs::path& path) { - std::string as_string = path.generic_string(); - as_string.erase(0, package_remove_char_count); - return std::move(as_string); + return std::move(std::string(path.generic_string(), package_remove_char_count)); }); return SortedVector(std::move(package_files)); } - static SortedVector build_list_of_installed_files( - const std::vector& pgh_and_files, const Triplet& triplet) + static SortedVector build_list_of_installed_files( + const std::vector& pgh_and_files, + const Triplet& triplet) { - std::vector installed_files = extract_files_in_triplet(pgh_and_files, triplet); const size_t installed_remove_char_count = triplet.canonical_name().size() + 1; // +1 for the slash - remove_first_n_chars(&installed_files, installed_remove_char_count); + std::vector installed_files = + extract_files_in_triplet(pgh_and_files, triplet, installed_remove_char_count); - return SortedVector(std::move(installed_files)); + return SortedVector(std::move(installed_files)); } InstallResult install_package(const VcpkgPaths& paths, const BinaryControlFile& bcf, StatusParagraphs* status_db) @@ -197,25 +198,57 @@ namespace vcpkg::Install const SortedVector package_files = build_list_of_package_files(paths.get_filesystem(), package_dir); - const SortedVector installed_files = build_list_of_installed_files(pgh_and_files, triplet); + const SortedVector installed_files = + build_list_of_installed_files(pgh_and_files, triplet); - std::vector intersection; - std::set_intersection(package_files.begin(), - package_files.end(), - installed_files.begin(), + struct intersection_compare + { + bool operator()(const std::string &lhs, const file_pack &rhs) { return lhs < rhs.first; } + bool operator()(const file_pack &lhs, const std::string &rhs) { return lhs.first < rhs; } + }; + + std::vector intersection; + + std::set_intersection(installed_files.begin(), installed_files.end(), - std::back_inserter(intersection)); + package_files.begin(), + package_files.end(), + std::back_inserter(intersection), + intersection_compare()); + + std::sort(intersection.begin(), intersection.end(), + [](const file_pack &lhs, const file_pack &rhs) + { + return lhs.second < rhs.second; + }); if (!intersection.empty()) { const fs::path triplet_install_path = paths.installed / triplet.canonical_name(); System::println(System::Color::error, - "The following files are already installed in %s and are in conflict with %s", + "The following files are already installed in %s by and are in conflict with %s\n", triplet_install_path.generic_string(), bcf.core_paragraph.spec); - System::print("\n "); - System::println(Strings::join("\n ", intersection)); - System::println(); + + auto i = intersection.begin(); + while (i != intersection.end()) { + System::println("%s:", i->second); + auto next = std::find_if(i, intersection.end(), + [i](const auto &val) + { + return i->second != val.second; + }); + + System::println(Strings::join("\n ", i, next, + [](const file_pack &file) + { + return file.first; + })); + System::println(); + + i = next; + } + return InstallResult::FILE_CONFLICTS; }