diff options
| author | Alexander Karatarakis <alkarata@microsoft.com> | 2016-11-06 20:12:54 -0800 |
|---|---|---|
| committer | Alexander Karatarakis <alkarata@microsoft.com> | 2016-11-06 22:39:15 -0800 |
| commit | e4cab414aee77b03140d0198ce8c0756c46b5c0a (patch) | |
| tree | 3391fc4fff70b9e901fb82556ff92cc9017c2021 /toolsrc/src/commands_portsdiff.cpp | |
| parent | a6821438bc63a35efc79b53588149271652ec5e3 (diff) | |
| download | vcpkg-e4cab414aee77b03140d0198ce8c0756c46b5c0a.tar.gz vcpkg-e4cab414aee77b03140d0198ce8c0756c46b5c0a.zip | |
Add new command: portsdiff
Diffstat (limited to 'toolsrc/src/commands_portsdiff.cpp')
| -rw-r--r-- | toolsrc/src/commands_portsdiff.cpp | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/toolsrc/src/commands_portsdiff.cpp b/toolsrc/src/commands_portsdiff.cpp new file mode 100644 index 000000000..e15db3567 --- /dev/null +++ b/toolsrc/src/commands_portsdiff.cpp @@ -0,0 +1,155 @@ +#include "vcpkg_Commands.h" +#include "vcpkg_System.h" +#include "vcpkg.h" +#include <map> +#include <iterator> +#include "vcpkg_Maps.h" +#include <iostream> +#include <iomanip> +#include <set> + +namespace vcpkg +{ + static void do_print_name_and_version(const std::vector<std::string>& ports_to_print, const std::map<std::string, std::string>& names_and_versions) + { + for (const std::string& name : ports_to_print) + { + const std::string& version = names_and_versions.at(name); + std::cout << std::left + << std::setw(20) << name << ' ' + << std::setw(16) << version << ' ' + << '\n'; + } + } + + static void do_print_name_and_previous_version_and_current_version(const std::vector<std::string>& ports_to_print, + const std::map<std::string, std::string>& previous_names_and_versions, + const std::map<std::string, std::string>& current_names_and_versions) + { + for (const std::string& name : ports_to_print) + { + if (name == "") + { + continue; + } + + const std::string& previous_version = previous_names_and_versions.at(name); + const std::string& current_version = current_names_and_versions.at(name); + std::cout << std::left + << std::setw(20) << name << ' ' + << std::setw(16) << previous_version << " -> " << current_version + << '\n'; + } + } + + static std::map<std::string, std::string> read_all_ports(const fs::path& ports_folder_path) + { + std::map<std::string, std::string> names_and_versions; + + for (auto it = fs::directory_iterator(ports_folder_path); it != fs::directory_iterator(); ++it) + { + const fs::path& path = it->path(); + + try + { + auto pghs = get_paragraphs(path / "CONTROL"); + if (pghs.empty()) + continue; + auto srcpgh = SourceParagraph(pghs[0]); + names_and_versions.emplace(srcpgh.name, srcpgh.version); + } + catch (std::runtime_error const&) + { + } + } + + return names_and_versions; + } + + static std::map<std::string, std::string> read_ports_from_commit(const vcpkg_paths& paths, const std::wstring& git_commit_id) + { + const fs::path dot_git_dir = paths.root / ".git"; + const std::wstring ports_dir_name_as_string = paths.ports.filename().native(); + const fs::path temp_checkout_path = paths.root / Strings::wformat(L"%s-%s", ports_dir_name_as_string, git_commit_id); + fs::create_directory(temp_checkout_path); + const std::wstring checkout_this_dir = Strings::wformat(LR"(.\%s)", ports_dir_name_as_string); // Must be relative to the root of the repository + + const std::wstring cmd = Strings::wformat(LR"(git --git-dir="%s" --work-tree="%s" checkout %s -f -q -- %s %s & git reset >NUL)", + dot_git_dir.native(), + temp_checkout_path.native(), + git_commit_id, + checkout_this_dir, + L".vcpkg-root"); + System::cmd_execute(cmd); + std::map<std::string, std::string> names_and_versions = read_all_ports(temp_checkout_path / ports_dir_name_as_string); + fs::remove_all(temp_checkout_path); + return names_and_versions; + } + + void portsdiff_command(const vcpkg_cmd_arguments& args, const vcpkg_paths& paths) + { + static const std::string example = Strings::format("The argument should be a branch/tag/hash to checkout.\n%s", create_example_string("portsdiff mybranchname")); + args.check_min_arg_count(1, example.c_str()); + args.check_max_arg_count(2, example.c_str()); + const std::wstring git_commit_id_for_previous_snapshot = Strings::utf8_to_utf16(args.command_arguments.at(0)); + const std::wstring git_commit_id_for_current_snapshot = args.command_arguments.size() < 2 ? L"HEAD" : Strings::utf8_to_utf16(args.command_arguments.at(1)); + + const std::map<std::string, std::string> current_names_and_versions = read_ports_from_commit(paths, git_commit_id_for_current_snapshot); + const std::map<std::string, std::string> previous_names_and_versions = read_ports_from_commit(paths, git_commit_id_for_previous_snapshot); + + // Already sorted, so set_difference can work on std::vector too + std::vector<std::string> current_ports = Maps::extract_keys(current_names_and_versions); + std::vector<std::string> previous_ports = Maps::extract_keys(previous_names_and_versions); + + std::vector<std::string> added_ports; + std::set_difference( + current_ports.cbegin(), current_ports.cend(), + previous_ports.cbegin(), previous_ports.cend(), + std::back_inserter(added_ports)); + + if (!added_ports.empty()) + { + System::println("\nThe following %d ports were added:\n", added_ports.size()); + do_print_name_and_version(added_ports, current_names_and_versions); + } + + std::vector<std::string> removed_ports; + std::set_difference( + previous_ports.cbegin(), previous_ports.cend(), + current_ports.cbegin(), current_ports.cend(), + std::back_inserter(removed_ports)); + + if (!removed_ports.empty()) + { + System::println("\nThe following %d ports were removed:\n", removed_ports.size()); + do_print_name_and_version(removed_ports, previous_names_and_versions); + } + + std::vector<std::string> potentially_updated_ports; + std::set_intersection( + current_ports.cbegin(), current_ports.cend(), + previous_ports.cbegin(), previous_ports.cend(), + std::back_inserter(potentially_updated_ports)); + + std::vector<std::string> updated_ports; + std::copy_if(potentially_updated_ports.cbegin(), potentially_updated_ports.cend(), std::back_inserter(updated_ports), + [&](const std::string& port) -> bool + { + return current_names_and_versions.at(port) != previous_names_and_versions.at(port); + } + ); + + if (!updated_ports.empty()) + { + System::println("\nThe following %d ports were updated:\n", updated_ports.size()); + do_print_name_and_previous_version_and_current_version(updated_ports, previous_names_and_versions, current_names_and_versions); + } + + if (added_ports.empty() && removed_ports.empty() && updated_ports.empty()) + { + System::println("There were no changes in the ports between the two commits."); + } + + exit(EXIT_SUCCESS); + } +} |
