diff options
| author | nicole mazzuca <mazzucan@outlook.com> | 2020-04-17 15:49:59 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-17 15:49:59 -0700 |
| commit | 556325a1f7b6049d91565257c00db2f0bf1eadc5 (patch) | |
| tree | 82485596a6285844862b431e6930c306b33cd484 /toolsrc/src | |
| parent | 71377f69e255414ccf3569a8a772fc89ee9f89ff (diff) | |
| download | vcpkg-556325a1f7b6049d91565257c00db2f0bf1eadc5.tar.gz vcpkg-556325a1f7b6049d91565257c00db2f0bf1eadc5.zip | |
[vcpkg] Add x-set-installed command (#10817)
This command takes a list of ports, and causes the final state of the
installed directory to be as-if one ran the install on an empty
installed directory (removing any unnecessary packages).
This is especially useful with the new `--x-install-root` option, which
allows one to set the `installed` directory for vcpkg to use.
Additionally, as a drive-by, we do some `stdfs` clean-up and add a
`.is_feature()` member function to BinaryParagraph (as opposed to
checking for `.feature().empty()`, which is far less clear to read).
This feature is experimental.
Diffstat (limited to 'toolsrc/src')
| -rw-r--r-- | toolsrc/src/vcpkg.cpp | 28 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/base/files.cpp | 41 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/binarycaching.cpp | 2 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/binaryparagraph.cpp | 6 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/build.cpp | 2 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/commands.cpp | 1 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/commands.setinstalled.cpp | 111 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/dependencies.cpp | 2 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/portfileprovider.cpp | 2 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/remove.cpp | 3 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/statusparagraphs.cpp | 15 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/vcpkgcmdarguments.cpp | 6 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/vcpkglib.cpp | 4 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/vcpkgpaths.cpp | 17 |
14 files changed, 206 insertions, 34 deletions
diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp index c2ee42200..4e6109c38 100644 --- a/toolsrc/src/vcpkg.cpp +++ b/toolsrc/src/vcpkg.cpp @@ -62,6 +62,8 @@ static void invalid_command(const std::string& cmd) static void inner(const VcpkgCmdArguments& args) { + auto& fs = Files::get_real_filesystem(); + Metrics::g_metrics.lock()->track_property("command", args.command); if (args.command.empty()) { @@ -88,26 +90,26 @@ static void inner(const VcpkgCmdArguments& args) } fs::path vcpkg_root_dir; - if (args.vcpkg_root_dir != nullptr) + if (args.vcpkg_root_dir) { - vcpkg_root_dir = fs::stdfs::absolute(fs::u8path(*args.vcpkg_root_dir)); + vcpkg_root_dir = fs.absolute(VCPKG_LINE_INFO, fs::u8path(*args.vcpkg_root_dir)); } else { const auto vcpkg_root_dir_env = System::get_environment_variable("VCPKG_ROOT"); if (const auto v = vcpkg_root_dir_env.get()) { - vcpkg_root_dir = fs::stdfs::absolute(*v); + vcpkg_root_dir = fs.absolute(VCPKG_LINE_INFO, *v); } else { - const fs::path current_path = fs::stdfs::current_path(); - vcpkg_root_dir = Files::get_real_filesystem().find_file_recursively_up(current_path, ".vcpkg-root"); + const fs::path current_path = fs.current_path(VCPKG_LINE_INFO); + vcpkg_root_dir = fs.find_file_recursively_up(current_path, ".vcpkg-root"); if (vcpkg_root_dir.empty()) { - vcpkg_root_dir = Files::get_real_filesystem().find_file_recursively_up( - fs::stdfs::absolute(System::get_exe_path_of_current_process()), ".vcpkg-root"); + vcpkg_root_dir = fs.find_file_recursively_up( + fs.absolute(VCPKG_LINE_INFO, System::get_exe_path_of_current_process()), ".vcpkg-root"); } } } @@ -116,17 +118,23 @@ static void inner(const VcpkgCmdArguments& args) Debug::print("Using vcpkg-root: ", vcpkg_root_dir.u8string(), '\n'); + Optional<fs::path> install_root_dir; + if (args.install_root_dir) { + install_root_dir = Files::get_real_filesystem().canonical(VCPKG_LINE_INFO, fs::u8path(*args.install_root_dir)); + Debug::print("Using install-root: ", install_root_dir.value_or_exit(VCPKG_LINE_INFO).u8string(), '\n'); + } + Optional<fs::path> vcpkg_scripts_root_dir = nullopt; - if (nullptr != args.scripts_root_dir) + if (args.scripts_root_dir) { - vcpkg_scripts_root_dir = fs::stdfs::canonical(fs::u8path(*args.scripts_root_dir)); + vcpkg_scripts_root_dir = Files::get_real_filesystem().canonical(VCPKG_LINE_INFO, fs::u8path(*args.scripts_root_dir)); Debug::print("Using scripts-root: ", vcpkg_scripts_root_dir.value_or_exit(VCPKG_LINE_INFO).u8string(), '\n'); } auto default_vs_path = System::get_environment_variable("VCPKG_VISUAL_STUDIO_PATH").value_or(""); const Expected<VcpkgPaths> expected_paths = - VcpkgPaths::create(vcpkg_root_dir, vcpkg_scripts_root_dir, default_vs_path, args.overlay_triplets.get()); + VcpkgPaths::create(vcpkg_root_dir, install_root_dir, vcpkg_scripts_root_dir, default_vs_path, args.overlay_triplets.get()); Checks::check_exit(VCPKG_LINE_INFO, !expected_paths.error(), "Error: Invalid vcpkg root directory %s: %s", diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 0bd1cb893..71cc7275a 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -272,6 +272,14 @@ namespace vcpkg::Files this->remove_all(path, ec, failure_point); } + fs::path Filesystem::absolute(LineInfo li, const fs::path& path) const + { + std::error_code ec; + const auto result = this->absolute(path, ec); + if (ec) Checks::exit_with_message(li, "Error getting absolute path of %s: %s", path.string(), ec.message()); + return result; + } + fs::path Filesystem::canonical(LineInfo li, const fs::path& path) const { std::error_code ec; @@ -286,6 +294,14 @@ namespace vcpkg::Files std::error_code ec; return this->canonical(path, ec); } + fs::path Filesystem::current_path(LineInfo li) const + { + std::error_code ec; + const auto result = this->current_path(ec); + + if (ec) Checks::exit_with_message(li, "Error getting current path: %s", ec.message()); + return result; + } struct RealFilesystem final : Filesystem { @@ -699,11 +715,36 @@ namespace vcpkg::Files } } + virtual fs::path absolute(const fs::path& path, std::error_code& ec) const override + { +#if USE_STD_FILESYSTEM + return fs::stdfs::absolute(path, ec); +#else // ^^^ USE_STD_FILESYSTEM / !USE_STD_FILESYSTEM vvv +#if _WIN32 + // absolute was called system_complete in experimental filesystem + return fs::stdfs::system_complete(path, ec); +#else // ^^^ _WIN32 / !_WIN32 vvv + if (path.is_absolute()) { + auto current_path = this->current_path(ec); + if (ec) return fs::path(); + return std::move(current_path) / path; + } else { + return path; + } +#endif +#endif + } + virtual fs::path canonical(const fs::path& path, std::error_code& ec) const override { return fs::stdfs::canonical(path, ec); } + virtual fs::path current_path(std::error_code& ec) const override + { + return fs::stdfs::current_path(ec); + } + virtual std::vector<fs::path> find_from_PATH(const std::string& name) const override { #if defined(_WIN32) diff --git a/toolsrc/src/vcpkg/binarycaching.cpp b/toolsrc/src/vcpkg/binarycaching.cpp index 0750366ff..c8e77d938 100644 --- a/toolsrc/src/vcpkg/binarycaching.cpp +++ b/toolsrc/src/vcpkg/binarycaching.cpp @@ -171,7 +171,7 @@ namespace {
fs.copy_file(log_file.path(),
tmp_log_path_destination / log_file.path().filename(),
- fs::stdfs::copy_options::none,
+ fs::copy_options::none,
ec);
}
}
diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index f142c307d..45638e1f5 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -62,7 +62,7 @@ namespace vcpkg // for compatibility with previous vcpkg versions, we discard all irrelevant information return dep.name; }); - if (this->feature.empty()) + if (!this->is_feature()) { this->default_features = parse_default_features_list(parser.optional_field(Fields::DEFAULTFEATURES)) .value_or_exit(VCPKG_LINE_INFO); @@ -109,7 +109,7 @@ namespace vcpkg std::string BinaryParagraph::displayname() const { - if (this->feature.empty() || this->feature == "core") + if (!this->is_feature() || this->feature == "core") return Strings::format("%s:%s", this->spec.name(), this->spec.triplet()); return Strings::format("%s[%s]:%s", this->spec.name(), this->feature, this->spec.triplet()); } @@ -126,7 +126,7 @@ namespace vcpkg out_str.append("Package: ").append(pgh.spec.name()).push_back('\n'); if (!pgh.version.empty()) out_str.append("Version: ").append(pgh.version).push_back('\n'); - else if (!pgh.feature.empty()) + else if (pgh.is_feature()) out_str.append("Feature: ").append(pgh.feature).push_back('\n'); if (!pgh.depends.empty()) { diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index fe17c490a..b3168075d 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -890,7 +890,7 @@ namespace vcpkg::Build ExtendedBuildResult result = do_build_package_and_clean_buildtrees(paths, action);
fs.create_directories(abi_package_dir, ec);
- fs.copy_file(abi_file, abi_file_in_package, fs::stdfs::copy_options::none, ec);
+ fs.copy_file(abi_file, abi_file_in_package, fs::copy_options::none, ec);
Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string());
if (binary_caching_enabled && result.code == BuildResult::SUCCEEDED)
diff --git a/toolsrc/src/vcpkg/commands.cpp b/toolsrc/src/vcpkg/commands.cpp index 1f424a559..0db6ddb8f 100644 --- a/toolsrc/src/vcpkg/commands.cpp +++ b/toolsrc/src/vcpkg/commands.cpp @@ -17,6 +17,7 @@ namespace vcpkg::Commands { static std::vector<PackageNameAndFunction<CommandTypeA>> t = { {"install", &Install::perform_and_exit}, + {"x-set-installed", &SetInstalled::perform_and_exit}, {"ci", &CI::perform_and_exit}, {"remove", &Remove::perform_and_exit}, {"upgrade", &Upgrade::perform_and_exit}, diff --git a/toolsrc/src/vcpkg/commands.setinstalled.cpp b/toolsrc/src/vcpkg/commands.setinstalled.cpp new file mode 100644 index 000000000..344892fe8 --- /dev/null +++ b/toolsrc/src/vcpkg/commands.setinstalled.cpp @@ -0,0 +1,111 @@ +#include "pch.h" + +#include <vcpkg/base/system.print.h> +#include <vcpkg/commands.h> +#include <vcpkg/globalstate.h> +#include <vcpkg/help.h> +#include <vcpkg/input.h> +#include <vcpkg/install.h> +#include <vcpkg/remove.h> +#include <vcpkg/portfileprovider.h> +#include <vcpkg/vcpkglib.h> + +namespace vcpkg::Commands::SetInstalled +{ + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string(R"(x-set-installed <package>...)"), + 1, + SIZE_MAX, + {}, + nullptr, + }; + + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet) + { + // input sanitization + const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); + + const std::vector<FullPackageSpec> specs = Util::fmap(args.command_arguments, [&](auto&& arg) { + return Input::check_and_get_full_package_spec( + std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text); + }); + + for (auto&& spec : specs) + { + Input::check_triplet(spec.package_spec.triplet(), paths); + } + + const Build::BuildPackageOptions install_plan_options = { + Build::UseHeadVersion::NO, + Build::AllowDownloads::YES, + Build::OnlyDownloads::NO, + Build::CleanBuildtrees::YES, + Build::CleanPackages::YES, + Build::CleanDownloads::YES, + Build::DownloadTool::BUILT_IN, + GlobalState::g_binary_caching ? Build::BinaryCaching::YES : Build::BinaryCaching::NO, + Build::FailOnTombstone::NO, + }; + + + PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports.get()); + auto cmake_vars = CMakeVars::make_triplet_cmake_var_provider(paths); + + // We have a set of user-requested specs. + // We need to know all the specs which are required to fulfill dependencies for those specs. + // Therefore, we see what we would install into an empty installed tree, so we can use the existing code. + auto action_plan = Dependencies::create_feature_install_plan(provider, *cmake_vars, specs, {}); + + for (auto&& action : action_plan.install_actions) + { + action.build_options = install_plan_options; + } + + cmake_vars->load_tag_vars(action_plan, provider); + Build::compute_all_abis(paths, action_plan, *cmake_vars, {}); + + std::set<std::string> all_abis; + + for (const auto& action : action_plan.install_actions) { + all_abis.insert(action.package_abi.value_or_exit(VCPKG_LINE_INFO)); + } + + // currently (or once) installed specifications + auto status_db = database_load_check(paths); + std::vector<PackageSpec> specs_to_remove; + for (auto&& status_pgh : status_db) + { + if (!status_pgh->is_installed()) continue; + if (status_pgh->package.is_feature()) continue; + + const auto& abi = status_pgh->package.abi; + if (abi.empty() || !Util::Sets::contains(all_abis, abi)) + { + specs_to_remove.push_back(status_pgh->package.spec); + } + } + + auto remove_plan = Dependencies::create_remove_plan(specs_to_remove, status_db); + + for (const auto& action : remove_plan) + { + Remove::perform_remove_plan_action(paths, action, Remove::Purge::NO, &status_db); + } + + auto real_action_plan = Dependencies::create_feature_install_plan(provider, *cmake_vars, specs, status_db); + + for (auto& action : real_action_plan.install_actions) + { + action.build_options = install_plan_options; + } + + Dependencies::print_plan(real_action_plan, true); + + const auto summary = Install::perform(real_action_plan, Install::KeepGoing::NO, paths, status_db, *cmake_vars); + + System::print2("\nTotal elapsed time: ", summary.total_elapsed_time, "\n\n"); + + Checks::exit_success(VCPKG_LINE_INFO); + } + +} diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp index 07aad4d22..120f84aef 100644 --- a/toolsrc/src/vcpkg/dependencies.cpp +++ b/toolsrc/src/vcpkg/dependencies.cpp @@ -560,7 +560,7 @@ namespace vcpkg::Dependencies ? RequestType::USER_REQUESTED : RequestType::AUTO_SELECTED; - auto maybe_ipv = status_db.find_all_installed(spec); + auto maybe_ipv = status_db.get_installed_package_view(spec); if (auto p_ipv = maybe_ipv.get()) { diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index e43fa862a..0b0ef4aaf 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -34,7 +34,7 @@ namespace vcpkg::PortFileProvider { if (!overlay_path.empty()) { - auto overlay = fs::stdfs::canonical(fs::u8path(overlay_path)); + auto overlay = fs.canonical(VCPKG_LINE_INFO, fs::u8path(overlay_path)); Checks::check_exit(VCPKG_LINE_INFO, filesystem.exists(overlay), diff --git a/toolsrc/src/vcpkg/remove.cpp b/toolsrc/src/vcpkg/remove.cpp index e1a03b808..bb25cd21d 100644 --- a/toolsrc/src/vcpkg/remove.cpp +++ b/toolsrc/src/vcpkg/remove.cpp @@ -21,7 +21,7 @@ namespace vcpkg::Remove void remove_package(const VcpkgPaths& paths, const PackageSpec& spec, StatusParagraphs* status_db) { auto& fs = paths.get_filesystem(); - auto maybe_ipv = status_db->find_all_installed(spec); + auto maybe_ipv = status_db->get_installed_package_view(spec); Checks::check_exit( VCPKG_LINE_INFO, maybe_ipv.has_value(), "unable to remove package %s: already removed", spec); @@ -72,6 +72,7 @@ namespace vcpkg::Remove fs.remove(target, ec); if (ec) { + // TODO: this is racy; should we ignore this error? #if defined(_WIN32) fs::stdfs::permissions(target, fs::perms::owner_all | fs::perms::group_all, ec); fs.remove(target, ec); diff --git a/toolsrc/src/vcpkg/statusparagraphs.cpp b/toolsrc/src/vcpkg/statusparagraphs.cpp index 2621c43e3..91058a473 100644 --- a/toolsrc/src/vcpkg/statusparagraphs.cpp +++ b/toolsrc/src/vcpkg/statusparagraphs.cpp @@ -18,16 +18,16 @@ namespace vcpkg { if (p->package.spec.name() == name && p->package.spec.triplet() == triplet) { - if (p->package.feature.empty()) - spghs.emplace(spghs.begin(), &p); - else + if (p->package.is_feature()) spghs.emplace_back(&p); + else + spghs.emplace(spghs.begin(), &p); } } return spghs; } - Optional<InstalledPackageView> StatusParagraphs::find_all_installed(const PackageSpec& spec) const + Optional<InstalledPackageView> StatusParagraphs::get_installed_package_view(const PackageSpec& spec) const { InstalledPackageView ipv; for (auto&& p : *this) @@ -35,13 +35,12 @@ namespace vcpkg if (p->package.spec.name() == spec.name() && p->package.spec.triplet() == spec.triplet() && p->is_installed()) { - if (p->package.feature.empty()) - { + if (p->package.is_feature()) { + ipv.features.emplace_back(p.get()); + } else { Checks::check_exit(VCPKG_LINE_INFO, ipv.core == nullptr); ipv.core = p.get(); } - else - ipv.features.emplace_back(p.get()); } } if (ipv.core != nullptr) diff --git a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp index 46e4c86ea..d8deae566 100644 --- a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp +++ b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp @@ -152,6 +152,12 @@ namespace vcpkg arg.substr(sizeof("--x-scripts-root=") - 1), "--x-scripts-root", args.scripts_root_dir); continue; } + if (Strings::starts_with(arg, "--x-install-root=")) + { + parse_cojoined_value( + arg.substr(sizeof("--x-install-root=") - 1), "--x-install-root=", args.install_root_dir); + continue; + } if (arg == "--triplet") { ++arg_begin; diff --git a/toolsrc/src/vcpkg/vcpkglib.cpp b/toolsrc/src/vcpkg/vcpkglib.cpp index 2a52111a6..366e2aa85 100644 --- a/toolsrc/src/vcpkg/vcpkglib.cpp +++ b/toolsrc/src/vcpkg/vcpkglib.cpp @@ -178,7 +178,7 @@ namespace vcpkg { if (!pgh->is_installed()) continue; auto& ipv = ipv_map[pgh->package.spec]; - if (pgh->package.feature.empty()) + if (!pgh->package.is_feature()) { ipv.core = pgh.get(); } @@ -206,7 +206,7 @@ namespace vcpkg for (const std::unique_ptr<StatusParagraph>& pgh : status_db) { - if (!pgh->is_installed() || !pgh->package.feature.empty()) + if (!pgh->is_installed() || pgh->package.is_feature()) { continue; } diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index bf16f09f3..52dd06b7b 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -14,6 +14,7 @@ namespace vcpkg { Expected<VcpkgPaths> VcpkgPaths::create(const fs::path& vcpkg_root_dir, + const Optional<fs::path>& install_root_dir, const Optional<fs::path>& vcpkg_scripts_root_dir, const std::string& default_vs_path, const std::vector<std::string>* triplets_dirs) @@ -53,7 +54,7 @@ namespace vcpkg asPath.u8string()); } - paths.downloads = fs::stdfs::canonical(std::move(asPath), ec); + paths.downloads = fs.canonical(std::move(asPath), ec); if (ec) { return ec; @@ -65,13 +66,17 @@ namespace vcpkg } paths.ports = paths.root / "ports"; - paths.installed = paths.root / "installed"; + if (auto d = install_root_dir.get()) { + paths.installed = fs.absolute(VCPKG_LINE_INFO, std::move(*d)); + } else { + paths.installed = paths.root / "installed"; + } paths.triplets = paths.root / "triplets"; paths.community_triplets = paths.triplets / "community"; if (auto scripts_dir = vcpkg_scripts_root_dir.get()) { - if (scripts_dir->empty() || !fs::stdfs::is_directory(*scripts_dir)) + if (scripts_dir->empty() || !fs::is_directory(fs.status(VCPKG_LINE_INFO, *scripts_dir))) { Metrics::g_metrics.lock()->track_property("error", "Invalid scripts override directory."); Checks::exit_with_message( @@ -108,11 +113,11 @@ namespace vcpkg paths.get_filesystem().exists(path), "Error: Path does not exist '%s'", triplets_dir); - paths.triplets_dirs.emplace_back(fs::stdfs::canonical(path)); + paths.triplets_dirs.emplace_back(fs.canonical(VCPKG_LINE_INFO, path)); } } - paths.triplets_dirs.emplace_back(fs::stdfs::canonical(paths.triplets)); - paths.triplets_dirs.emplace_back(fs::stdfs::canonical(paths.community_triplets)); + paths.triplets_dirs.emplace_back(fs.canonical(VCPKG_LINE_INFO, paths.triplets)); + paths.triplets_dirs.emplace_back(fs.canonical(VCPKG_LINE_INFO, paths.community_triplets)); return paths; } |
