vcpkg/toolsrc/src/commands_remove.cpp

230 lines
8.9 KiB
C++
Raw Normal View History

2017-01-28 04:49:09 +08:00
#include "pch.h"
2017-04-28 09:08:52 +08:00
2016-09-19 11:50:08 +08:00
#include "vcpkg_Commands.h"
2017-01-27 06:25:36 +08:00
#include "vcpkg_Dependencies.h"
2017-04-28 09:08:52 +08:00
#include "vcpkg_Input.h"
#include "vcpkg_System.h"
#include "vcpkg_Util.h"
2017-04-28 09:08:52 +08:00
#include "vcpkglib.h"
2016-09-19 11:50:08 +08:00
namespace vcpkg::Commands::Remove
2016-09-19 11:50:08 +08:00
{
2017-04-13 12:37:55 +08:00
using Dependencies::RemovePlanAction;
2017-04-04 07:23:46 +08:00
using Dependencies::RemovePlanType;
2017-04-04 07:21:46 +08:00
using Dependencies::RequestType;
using Update::OutdatedPackage;
2017-01-27 06:25:36 +08:00
2017-04-04 07:29:11 +08:00
static void remove_package(const VcpkgPaths& paths, const PackageSpec& spec, StatusParagraphs* status_db)
{
auto& fs = paths.get_filesystem();
StatusParagraph& pkg = **status_db->find(spec.name(), spec.triplet());
pkg.want = Want::PURGE;
pkg.state = InstallState::HALF_INSTALLED;
write_update(paths, pkg);
auto maybe_lines = fs.read_lines(paths.listfile_path(pkg.package));
if (auto lines = maybe_lines.get())
{
std::vector<fs::path> dirs_touched;
for (auto&& suffix : *lines)
{
2017-04-28 09:08:52 +08:00
if (!suffix.empty() && suffix.back() == '\r') suffix.pop_back();
std::error_code ec;
auto target = paths.installed / suffix;
auto status = fs.status(target, ec);
if (ec)
{
2017-04-04 07:31:00 +08:00
System::println(System::Color::error, "failed: %s", ec.message());
continue;
}
if (fs::is_directory(status))
{
dirs_touched.push_back(target);
}
else if (fs::is_regular_file(status))
{
fs.remove(target, ec);
if (ec)
{
2017-04-04 07:31:00 +08:00
System::println(System::Color::error, "failed: %s: %s", target.u8string(), ec.message());
}
}
else if (!fs::status_known(status))
{
2017-04-04 07:31:00 +08:00
System::println(System::Color::warning, "Warning: unknown status: %s", target.u8string());
}
else
{
2017-04-04 07:31:00 +08:00
System::println(System::Color::warning, "Warning: %s: cannot handle file type", target.u8string());
}
}
auto b = dirs_touched.rbegin();
auto e = dirs_touched.rend();
for (; b != e; ++b)
{
if (fs.is_empty(*b))
{
std::error_code ec;
fs.remove(*b, ec);
if (ec)
{
2017-04-04 07:31:00 +08:00
System::println(System::Color::error, "failed: %s", ec.message());
}
}
}
fs.remove(paths.listfile_path(pkg.package));
}
pkg.state = InstallState::NOT_INSTALLED;
write_update(paths, pkg);
}
static void print_plan(const std::map<RemovePlanType, std::vector<const RemovePlanAction*>>& group_by_plan_type)
{
static constexpr std::array<RemovePlanType, 2> order = {RemovePlanType::NOT_INSTALLED, RemovePlanType::REMOVE};
for (const RemovePlanType plan_type : order)
{
auto it = group_by_plan_type.find(plan_type);
if (it == group_by_plan_type.cend())
{
continue;
}
std::vector<const RemovePlanAction*> cont = it->second;
std::sort(cont.begin(), cont.end(), &RemovePlanAction::compare_by_name);
2017-04-28 09:08:52 +08:00
const std::string as_string = Strings::join("\n", cont, [](const RemovePlanAction* p) {
return Dependencies::to_output_string(p->request_type, p->spec.to_string());
});
switch (plan_type)
{
2017-04-15 06:32:14 +08:00
case RemovePlanType::NOT_INSTALLED:
System::println("The following packages are not installed, so not removed:\n%s", as_string);
continue;
case RemovePlanType::REMOVE:
System::println("The following packages will be removed:\n%s", as_string);
continue;
2017-04-28 09:08:52 +08:00
default: Checks::unreachable(VCPKG_LINE_INFO);
}
}
}
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
2016-09-19 11:50:08 +08:00
{
2017-04-29 03:59:53 +08:00
static const std::string OPTION_PURGE = "--purge";
static const std::string OPTION_NO_PURGE = "--no-purge";
static const std::string OPTION_RECURSE = "--recurse";
static const std::string OPTION_DRY_RUN = "--dry-run";
static const std::string OPTION_OUTDATED = "--outdated";
2017-04-28 09:08:52 +08:00
static const std::string example =
Commands::Help::create_example_string("remove zlib zlib:x64-windows curl boost");
const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments(
{OPTION_PURGE, OPTION_NO_PURGE, OPTION_RECURSE, OPTION_DRY_RUN, OPTION_OUTDATED});
2017-03-30 09:30:32 +08:00
StatusParagraphs status_db = database_load_check(paths);
2017-04-04 06:02:45 +08:00
std::vector<PackageSpec> specs;
2017-03-30 09:30:32 +08:00
if (options.find(OPTION_OUTDATED) != options.cend())
{
2017-03-30 09:30:32 +08:00
args.check_exact_arg_count(0, example);
2017-04-28 09:08:52 +08:00
specs = Util::fmap(Update::find_outdated_packages(paths, status_db),
[](auto&& outdated) { return outdated.spec; });
if (specs.empty())
{
System::println(System::Color::success, "There are no oudated packages.");
Checks::exit_success(VCPKG_LINE_INFO);
}
2017-03-30 09:30:32 +08:00
}
else
{
args.check_min_arg_count(1, example);
2017-04-28 09:08:52 +08:00
specs = Util::fmap(args.command_arguments, [&](auto&& arg) {
return Input::check_and_get_package_spec(arg, default_triplet, example);
});
2017-03-30 09:30:32 +08:00
for (auto&& spec : specs)
Input::check_triplet(spec.triplet(), paths);
2017-03-30 09:30:32 +08:00
}
const bool alsoRemoveFolderFromPackages = options.find(OPTION_NO_PURGE) == options.end();
if (options.find(OPTION_PURGE) != options.end() && !alsoRemoveFolderFromPackages)
{
// User specified --purge and --no-purge
2017-04-04 07:31:00 +08:00
System::println(System::Color::error, "Error: cannot specify both --no-purge and --purge.");
System::print(example);
Checks::exit_fail(VCPKG_LINE_INFO);
}
2017-03-30 09:30:32 +08:00
const bool isRecursive = options.find(OPTION_RECURSE) != options.cend();
const bool dryRun = options.find(OPTION_DRY_RUN) != options.cend();
2016-09-19 11:50:08 +08:00
2017-04-13 12:37:55 +08:00
const std::vector<RemovePlanAction> remove_plan = Dependencies::create_remove_plan(specs, status_db);
Checks::check_exit(VCPKG_LINE_INFO, !remove_plan.empty(), "Remove plan cannot be empty");
2017-01-27 09:53:45 +08:00
std::map<RemovePlanType, std::vector<const RemovePlanAction*>> group_by_plan_type;
Util::group_by(remove_plan, &group_by_plan_type, [](const RemovePlanAction& p) { return p.plan_type; });
print_plan(group_by_plan_type);
2017-04-28 09:08:52 +08:00
const bool has_non_user_requested_packages =
Util::find_if(remove_plan, [](const RemovePlanAction& package) -> bool {
return package.request_type != RequestType::USER_REQUESTED;
}) != remove_plan.cend();
2017-03-30 09:30:32 +08:00
if (has_non_user_requested_packages)
{
2017-04-28 09:08:52 +08:00
System::println(System::Color::warning,
"Additional packages (*) need to be removed to complete this operation.");
2017-03-30 09:30:32 +08:00
if (!isRecursive)
{
2017-04-28 09:08:52 +08:00
System::println(System::Color::warning,
"If you are sure you want to remove them, run the command with the --recurse option");
2017-03-30 09:30:32 +08:00
Checks::exit_fail(VCPKG_LINE_INFO);
}
}
if (dryRun)
{
Checks::exit_success(VCPKG_LINE_INFO);
}
2017-04-13 12:37:55 +08:00
for (const RemovePlanAction& action : remove_plan)
2016-09-19 11:50:08 +08:00
{
2017-04-08 07:17:54 +08:00
const std::string display_name = action.spec.to_string();
2017-04-13 12:37:55 +08:00
switch (action.plan_type)
2016-09-19 11:50:08 +08:00
{
2017-04-04 07:23:46 +08:00
case RemovePlanType::NOT_INSTALLED:
2017-04-04 07:31:00 +08:00
System::println(System::Color::success, "Package %s is not installed", display_name);
break;
2017-04-04 07:23:46 +08:00
case RemovePlanType::REMOVE:
System::println("Removing package %s... ", display_name);
remove_package(paths, action.spec, &status_db);
2017-04-04 07:31:00 +08:00
System::println(System::Color::success, "Removing package %s... done", display_name);
break;
2017-04-04 07:23:46 +08:00
case RemovePlanType::UNKNOWN:
2017-04-28 09:08:52 +08:00
default: Checks::unreachable(VCPKG_LINE_INFO);
2016-09-19 11:50:08 +08:00
}
2017-01-31 04:34:36 +08:00
if (alsoRemoveFolderFromPackages)
{
System::println("Purging package %s... ", display_name);
Files::Filesystem& fs = paths.get_filesystem();
std::error_code ec;
fs.remove_all(paths.packages / action.spec.dir(), ec);
2017-04-04 07:31:00 +08:00
System::println(System::Color::success, "Purging package %s... done", display_name);
2017-01-31 04:34:36 +08:00
}
2016-09-19 11:50:08 +08:00
}
2017-01-31 04:34:36 +08:00
Checks::exit_success(VCPKG_LINE_INFO);
2016-09-19 11:50:08 +08:00
}
}