From d47570b8d615abfaa1e31f612d65d89a05815ad9 Mon Sep 17 00:00:00 2001 From: ras0219 Date: Sat, 27 Jun 2020 09:50:01 -0700 Subject: [PATCH] [vcpkg-x-set-installed] Implement --dry-run (#12132) * [vcpkg-x-set-installed] Implement --dry-run * [vcpkg] Address code review comments Co-authored-by: Robert Schumacher --- toolsrc/src/vcpkg/commands.setinstalled.cpp | 39 +++++++++++++++------ toolsrc/src/vcpkg/dependencies.cpp | 32 ++++++++++++----- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/toolsrc/src/vcpkg/commands.setinstalled.cpp b/toolsrc/src/vcpkg/commands.setinstalled.cpp index 15a780340..5a473b4ee 100644 --- a/toolsrc/src/vcpkg/commands.setinstalled.cpp +++ b/toolsrc/src/vcpkg/commands.setinstalled.cpp @@ -13,11 +13,17 @@ namespace vcpkg::Commands::SetInstalled { + static constexpr StringLiteral OPTION_DRY_RUN = "--dry-run"; + + static constexpr CommandSwitch INSTALL_SWITCHES[] = { + {OPTION_DRY_RUN, "Do not actually build or install"}, + }; + const CommandStructure COMMAND_STRUCTURE = { create_example_string(R"(x-set-installed ...)"), - 1, + 0, SIZE_MAX, - {}, + {INSTALL_SWITCHES}, nullptr, }; @@ -39,6 +45,8 @@ namespace vcpkg::Commands::SetInstalled auto binaryprovider = create_binary_provider_from_configs(paths, args.binarysources).value_or_exit(VCPKG_LINE_INFO); + const bool dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN); + const Build::BuildPackageOptions install_plan_options = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, @@ -76,6 +84,7 @@ namespace vcpkg::Commands::SetInstalled // currently (or once) installed specifications auto status_db = database_load_check(paths); std::vector specs_to_remove; + std::set specs_installed; for (auto&& status_pgh : status_db) { if (!status_pgh->is_installed()) continue; @@ -86,25 +95,33 @@ namespace vcpkg::Commands::SetInstalled { specs_to_remove.push_back(status_pgh->package.spec); } + else + { + specs_installed.emplace(status_pgh->package.spec); + } } - auto remove_plan = Dependencies::create_remove_plan(specs_to_remove, status_db); + action_plan.remove_actions = Dependencies::create_remove_plan(specs_to_remove, status_db); - for (const auto& action : remove_plan) + for (const auto& action : action_plan.remove_actions) { - Remove::perform_remove_plan_action(paths, action, Remove::Purge::NO, &status_db); + // This should not technically be needed, however ensuring that all specs to be removed are not included in + // `specs_installed` acts as a sanity check + specs_installed.erase(action.spec); } - auto real_action_plan = Dependencies::create_feature_install_plan(provider, *cmake_vars, specs, status_db); + Util::erase_remove_if(action_plan.install_actions, [&](const Dependencies::InstallPlanAction& ipa) { + return Util::Sets::contains(specs_installed, ipa.spec); + }); - for (auto& action : real_action_plan.install_actions) + Dependencies::print_plan(action_plan, true, paths.ports); + + if (dry_run) { - action.build_options = install_plan_options; + Checks::exit_success(VCPKG_LINE_INFO); } - Dependencies::print_plan(real_action_plan, true); - - const auto summary = Install::perform(real_action_plan, + const auto summary = Install::perform(action_plan, Install::KeepGoing::NO, paths, status_db, diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp index 26cb3109b..53db3b6d7 100644 --- a/toolsrc/src/vcpkg/dependencies.cpp +++ b/toolsrc/src/vcpkg/dependencies.cpp @@ -948,7 +948,14 @@ namespace vcpkg::Dependencies void print_plan(const ActionPlan& action_plan, const bool is_recursive, const fs::path& default_ports_dir) { - std::vector remove_plans; + if (action_plan.remove_actions.empty() && action_plan.already_installed.empty() && + action_plan.install_actions.empty()) + { + System::print2("All requested packages are currently installed.\n"); + return; + } + + std::set remove_specs; std::vector rebuilt_plans; std::vector only_install_plans; std::vector new_plans; @@ -962,16 +969,16 @@ namespace vcpkg::Dependencies for (auto&& remove_action : action_plan.remove_actions) { - remove_plans.emplace_back(&remove_action); + remove_specs.emplace(remove_action.spec); } for (auto&& install_action : action_plan.install_actions) { // remove plans are guaranteed to come before install plans, so we know the plan will be contained // if at all. - auto it = Util::find_if(remove_plans, - [&](const RemovePlanAction* plan) { return plan->spec == install_action.spec; }); - if (it != remove_plans.end()) + auto it = remove_specs.find(install_action.spec); + if (it != remove_specs.end()) { + remove_specs.erase(it); rebuilt_plans.push_back(&install_action); } else @@ -988,7 +995,6 @@ namespace vcpkg::Dependencies } already_installed_plans = Util::fmap(action_plan.already_installed, [](auto&& action) { return &action; }); - std::sort(remove_plans.begin(), remove_plans.end(), &RemovePlanAction::compare_by_name); std::sort(rebuilt_plans.begin(), rebuilt_plans.end(), &InstallPlanAction::compare_by_name); std::sort(only_install_plans.begin(), only_install_plans.end(), &InstallPlanAction::compare_by_name); std::sort(new_plans.begin(), new_plans.end(), &InstallPlanAction::compare_by_name); @@ -1019,6 +1025,16 @@ namespace vcpkg::Dependencies '\n'); } + if (!remove_specs.empty()) + { + std::string msg = "The following packages will be removed:\n"; + for (auto spec : remove_specs) + { + Strings::append(msg, to_output_string(RequestType::USER_REQUESTED, spec.to_string()), '\n'); + } + System::print2(msg); + } + if (!rebuilt_plans.empty()) { System::print2("The following packages will be rebuilt:\n", actions_to_output_string(rebuilt_plans), '\n'); @@ -1039,8 +1055,8 @@ namespace vcpkg::Dependencies if (has_non_user_requested_packages) System::print2("Additional packages (*) will be modified to complete this operation.\n"); - - if (!remove_plans.empty() && !is_recursive) + bool have_removals = !remove_specs.empty() || !rebuilt_plans.empty(); + if (have_removals && !is_recursive) { System::print2(System::Color::warning, "If you are sure you want to rebuild the above packages, run the command with the "