From 135f91de1eef9e906eb7a5bcf323f6eff9a2b5da Mon Sep 17 00:00:00 2001 From: ras0219 Date: Wed, 1 Jul 2020 11:36:09 -0700 Subject: [vcpkg] Implement --x-write-nuget-packages-config= setting for `install` and `x-set-installed` (#12138) * [vcpkg] Implement --x-write-nuget-packages-config= setting for `install` and `x-set-installed`. * [vcpkg] Add end-to-end testing suite for install, remove, and binary caching * [vcpkg] Define `$TestingRoot in end-to-end-tests.ps1 * [vcpkg] Address CR comments Co-authored-by: Robert Schumacher --- toolsrc/src/vcpkg-test/binarycaching.cpp | 88 ++++++++++++++++++++++++++--- toolsrc/src/vcpkg/base/files.cpp | 16 ++++++ toolsrc/src/vcpkg/binarycaching.cpp | 59 ++++++++++++++++--- toolsrc/src/vcpkg/build.cpp | 7 ++- toolsrc/src/vcpkg/commands.setinstalled.cpp | 30 +++++++++- toolsrc/src/vcpkg/install.cpp | 42 ++++++++++++-- 6 files changed, 217 insertions(+), 25 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/binarycaching.cpp b/toolsrc/src/vcpkg-test/binarycaching.cpp index 817b85e03..b220b5ccb 100644 --- a/toolsrc/src/vcpkg-test/binarycaching.cpp +++ b/toolsrc/src/vcpkg-test/binarycaching.cpp @@ -1,10 +1,11 @@ #include #include +#include #include +#include #include #include #include -#include #include using namespace vcpkg; @@ -96,9 +97,9 @@ Features: a, b Dependencies: - + - + )"; auto expected_lines = Strings::split(expected, '\n'); auto nuspec_lines = Strings::split(nuspec, '\n'); @@ -123,8 +124,14 @@ TEST_CASE ("XmlSerializer", "[XmlSerializer]") xml = XmlSerializer(); xml.emit_declaration(); - xml.start_complex_open_tag("a").text_attr("b", "<").text_attr("c", " ").finish_self_closing_complex_tag(); - REQUIRE(xml.buf == R"()"); + xml.start_complex_open_tag("a") + .text_attr("b", "<") + .text_attr("c", " ") + .finish_self_closing_complex_tag() + .line_break(); + xml.simple_tag("d", "e"); + REQUIRE(xml.buf == R"()" + "\ne"); xml = XmlSerializer(); xml.start_complex_open_tag("a").finish_complex_open_tag(); @@ -134,5 +141,72 @@ TEST_CASE ("XmlSerializer", "[XmlSerializer]") xml.line_break(); xml.open_tag("a").line_break().line_break(); xml.close_tag("a").line_break().line_break(); - REQUIRE(xml.buf == "\n\n \n \n\n"); -} \ No newline at end of file + REQUIRE(xml.buf == "\n\n\n\n\n"); + + xml = XmlSerializer(); + xml.start_complex_open_tag("a") + .text_attr("b", "<") + .line_break() + .text_attr("c", " ") + .finish_complex_open_tag() + .line_break(); + xml.simple_tag("d", "e").line_break(); + REQUIRE(xml.buf == "\n e\n"); +} + +TEST_CASE ("generate_nuget_packages_config", "[generate_nuget_packages_config]") +{ + Dependencies::ActionPlan plan; + auto packageconfig = generate_nuget_packages_config(plan); + REQUIRE(packageconfig == R"( + + +)"); + + auto pghs = Paragraphs::parse_paragraphs(R"( +Source: zlib +Version: 1.5 +Description: a spiffy compression library wrapper +)", + ""); + REQUIRE(pghs.has_value()); + auto maybe_scf = SourceControlFile::parse_control_file(fs::path(), std::move(*pghs.get())); + REQUIRE(maybe_scf.has_value()); + SourceControlFileLocation scfl{std::move(*maybe_scf.get()), fs::path()}; + plan.install_actions.push_back(Dependencies::InstallPlanAction()); + plan.install_actions[0].spec = PackageSpec("zlib", Triplet::X64_ANDROID); + plan.install_actions[0].source_control_file_location = scfl; + plan.install_actions[0].abi_info = Build::AbiInfo{}; + plan.install_actions[0].abi_info.get()->package_abi = "packageabi"; + + packageconfig = generate_nuget_packages_config(plan); + REQUIRE(packageconfig == R"( + + + +)"); + + auto pghs2 = Paragraphs::parse_paragraphs(R"( +Source: zlib2 +Version: 1.52 +Description: a spiffy compression library wrapper +)", + ""); + REQUIRE(pghs2.has_value()); + auto maybe_scf2 = SourceControlFile::parse_control_file(fs::path(), std::move(*pghs2.get())); + REQUIRE(maybe_scf2.has_value()); + SourceControlFileLocation scfl2{std::move(*maybe_scf2.get()), fs::path()}; + plan.install_actions.push_back(Dependencies::InstallPlanAction()); + plan.install_actions[1].spec = PackageSpec("zlib2", Triplet::X64_ANDROID); + plan.install_actions[1].source_control_file_location = scfl2; + plan.install_actions[1].abi_info = Build::AbiInfo{}; + plan.install_actions[1].abi_info.get()->package_abi = "packageabi2"; + + packageconfig = generate_nuget_packages_config(plan); + REQUIRE(packageconfig == R"( + + + + +)"); +} diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 9d9aecb69..2e39073ce 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -989,4 +989,20 @@ namespace vcpkg::Files message.push_back('\n'); System::print2(message); } + + fs::path combine(const fs::path& lhs, const fs::path& rhs) + { +#if VCPKG_USE_STD_FILESYSTEM + return lhs / rhs; +#else // ^^^ VCPKG_USE_STD_FILESYSTEM // !VCPKG_USE_STD_FILESYSTEM vvv + if (rhs.is_absolute()) + { + return rhs; + } + else + { + return lhs / rhs; + } +#endif + } } diff --git a/toolsrc/src/vcpkg/binarycaching.cpp b/toolsrc/src/vcpkg/binarycaching.cpp index 5bebc4fb8..532e07032 100644 --- a/toolsrc/src/vcpkg/binarycaching.cpp +++ b/toolsrc/src/vcpkg/binarycaching.cpp @@ -285,7 +285,7 @@ namespace for (auto&& action : plan.install_actions) { auto& spec = action.spec; - fs.remove_all_inside(paths.package_dir(spec), VCPKG_LINE_INFO); + fs.remove_all(paths.package_dir(spec), VCPKG_LINE_INFO); nuget_refs.emplace_back(spec, NugetReference(action)); } @@ -615,42 +615,57 @@ XmlSerializer& XmlSerializer::emit_declaration() } XmlSerializer& XmlSerializer::open_tag(StringLiteral sl) { + emit_pending_indent(); Strings::append(buf, '<', sl, '>'); - indent += 2; + m_indent += 2; return *this; } XmlSerializer& XmlSerializer::start_complex_open_tag(StringLiteral sl) { + emit_pending_indent(); Strings::append(buf, '<', sl); - indent += 2; + m_indent += 2; return *this; } XmlSerializer& XmlSerializer::text_attr(StringLiteral name, StringView content) { - Strings::append(buf, ' ', name, "=\""); + if (m_pending_indent) + { + m_pending_indent = false; + buf.append(m_indent, ' '); + } + else + { + buf.push_back(' '); + } + Strings::append(buf, name, "=\""); text(content); Strings::append(buf, '"'); return *this; } XmlSerializer& XmlSerializer::finish_complex_open_tag() { + emit_pending_indent(); Strings::append(buf, '>'); return *this; } XmlSerializer& XmlSerializer::finish_self_closing_complex_tag() { + emit_pending_indent(); Strings::append(buf, "/>"); - indent -= 2; + m_indent -= 2; return *this; } XmlSerializer& XmlSerializer::close_tag(StringLiteral sl) { + m_indent -= 2; + emit_pending_indent(); Strings::append(buf, "'); - indent -= 2; return *this; } XmlSerializer& XmlSerializer::text(StringView sv) { + emit_pending_indent(); for (auto ch : sv) { if (ch == '&') @@ -682,12 +697,21 @@ XmlSerializer& XmlSerializer::text(StringView sv) } XmlSerializer& XmlSerializer::simple_tag(StringLiteral tag, StringView content) { - return open_tag(tag).text(content).close_tag(tag); + return emit_pending_indent().open_tag(tag).text(content).close_tag(tag); } XmlSerializer& XmlSerializer::line_break() { buf.push_back('\n'); - buf.append(indent, ' '); + m_pending_indent = true; + return *this; +} +XmlSerializer& XmlSerializer::emit_pending_indent() +{ + if (m_pending_indent) + { + m_pending_indent = false; + buf.append(m_indent, ' '); + } return *this; } @@ -1118,3 +1142,22 @@ void vcpkg::help_topic_binary_caching(const VcpkgPaths&) System::print2(tbl.m_str); } + +std::string vcpkg::generate_nuget_packages_config(const Dependencies::ActionPlan& action) +{ + auto refs = Util::fmap(action.install_actions, + [&](const Dependencies::InstallPlanAction& ipa) { return NugetReference(ipa); }); + XmlSerializer xml; + xml.emit_declaration().line_break(); + xml.open_tag("packages").line_break(); + for (auto&& ref : refs) + { + xml.start_complex_open_tag("package") + .text_attr("id", ref.id) + .text_attr("version", ref.version) + .finish_self_closing_complex_tag() + .line_break(); + } + xml.close_tag("packages").line_break(); + return std::move(xml.buf); +} diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 5e2f8778b..7d2976165 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -484,8 +484,9 @@ namespace vcpkg::Build env); out_file.close(); - Checks::check_exit( - VCPKG_LINE_INFO, !compiler_hash.empty(), "Error occured while detecting compiler information"); + Checks::check_exit(VCPKG_LINE_INFO, + !compiler_hash.empty(), + "Error occured while detecting compiler information. Pass `--debug` for more information."); Debug::print("Detecting compiler hash for triplet ", triplet, ": ", compiler_hash, "\n"); return compiler_hash; @@ -866,6 +867,8 @@ namespace vcpkg::Build for (auto it = action_plan.install_actions.begin(); it != action_plan.install_actions.end(); ++it) { auto& action = *it; + if (action.abi_info.has_value()) continue; + std::vector dependency_abis; if (!Util::Enum::to_bool(action.build_options.only_downloads)) { diff --git a/toolsrc/src/vcpkg/commands.setinstalled.cpp b/toolsrc/src/vcpkg/commands.setinstalled.cpp index f52e4942b..df191ee3e 100644 --- a/toolsrc/src/vcpkg/commands.setinstalled.cpp +++ b/toolsrc/src/vcpkg/commands.setinstalled.cpp @@ -14,16 +14,22 @@ namespace vcpkg::Commands::SetInstalled { static constexpr StringLiteral OPTION_DRY_RUN = "--dry-run"; + static constexpr StringLiteral OPTION_WRITE_PACKAGES_CONFIG = "--x-write-nuget-packages-config"; static constexpr CommandSwitch INSTALL_SWITCHES[] = { {OPTION_DRY_RUN, "Do not actually build or install"}, }; + static constexpr CommandSetting INSTALL_SETTINGS[] = { + {OPTION_WRITE_PACKAGES_CONFIG, + "Writes out a NuGet packages.config-formatted file for use with external binary caching.\n" + "See `vcpkg help binarycaching` for more information."}, + }; const CommandStructure COMMAND_STRUCTURE = { create_example_string(R"(x-set-installed ...)"), 0, SIZE_MAX, - {INSTALL_SWITCHES}, + {INSTALL_SWITCHES, INSTALL_SETTINGS}, nullptr, }; @@ -34,7 +40,8 @@ namespace vcpkg::Commands::SetInstalled const CMakeVars::CMakeVarProvider& cmake_vars, const std::vector& specs, const Build::BuildPackageOptions& install_plan_options, - DryRun dry_run) + DryRun dry_run, + const Optional& maybe_pkgsconfig) { // We have a set of user-requested specs. // We need to know all the specs which are required to fulfill dependencies for those specs. @@ -91,6 +98,16 @@ namespace vcpkg::Commands::SetInstalled Dependencies::print_plan(action_plan, true, paths.ports); + if (auto p_pkgsconfig = maybe_pkgsconfig.get()) + { + Build::compute_all_abis(paths, action_plan, cmake_vars, status_db); + auto& fs = paths.get_filesystem(); + auto pkgsconfig_path = Files::combine(paths.original_cwd, *p_pkgsconfig); + auto pkgsconfig_contents = generate_nuget_packages_config(action_plan); + fs.write_contents(pkgsconfig_path, pkgsconfig_contents, VCPKG_LINE_INFO); + System::print2("Wrote NuGet packages config information to ", pkgsconfig_path.u8string(), "\n"); + } + if (dry_run == DryRun::Yes) { Checks::exit_success(VCPKG_LINE_INFO); @@ -142,6 +159,12 @@ namespace vcpkg::Commands::SetInstalled PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports); auto cmake_vars = CMakeVars::make_triplet_cmake_var_provider(paths); + Optional pkgsconfig; + auto it_pkgsconfig = options.settings.find(OPTION_WRITE_PACKAGES_CONFIG); + if (it_pkgsconfig != options.settings.end()) + { + pkgsconfig = it_pkgsconfig->second; + } perform_and_exit_ex(args, paths, provider, @@ -149,6 +172,7 @@ namespace vcpkg::Commands::SetInstalled *cmake_vars, specs, install_plan_options, - dry_run ? DryRun::Yes : DryRun::No); + dry_run ? DryRun::Yes : DryRun::No, + pkgsconfig); } } diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 5750469ad..aa79bb1f2 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -500,6 +500,7 @@ namespace vcpkg::Install static constexpr StringLiteral OPTION_XUNIT = "--x-xunit"; static constexpr StringLiteral OPTION_USE_ARIA2 = "--x-use-aria2"; static constexpr StringLiteral OPTION_CLEAN_AFTER_BUILD = "--clean-after-build"; + static constexpr StringLiteral OPTION_WRITE_PACKAGES_CONFIG = "--x-write-nuget-packages-config"; static constexpr std::array INSTALL_SWITCHES = {{ {OPTION_DRY_RUN, "Do not actually build or install"}, @@ -511,8 +512,11 @@ namespace vcpkg::Install {OPTION_USE_ARIA2, "Use aria2 to perform download tasks"}, {OPTION_CLEAN_AFTER_BUILD, "Clean buildtrees, packages and downloads after building each package"}, }}; - static constexpr std::array INSTALL_SETTINGS = {{ + static constexpr std::array INSTALL_SETTINGS = {{ {OPTION_XUNIT, "File to output results in XUnit format (Internal use)"}, + {OPTION_WRITE_PACKAGES_CONFIG, + "Writes out a NuGet packages.config-formatted file for use with external binary caching.\nSee `vcpkg help " + "binarycaching` for more information."}, }}; std::vector get_all_port_names(const VcpkgPaths& paths) @@ -654,7 +658,8 @@ namespace vcpkg::Install void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, Triplet default_triplet) { // input sanitization - const ParsedArguments options = args.parse_arguments(paths.manifest_mode_enabled() ? MANIFEST_COMMAND_STRUCTURE : COMMAND_STRUCTURE); + const ParsedArguments options = + args.parse_arguments(paths.manifest_mode_enabled() ? MANIFEST_COMMAND_STRUCTURE : COMMAND_STRUCTURE); auto binaryprovider = create_binary_provider_from_configs(paths, args.binary_sources).value_or_exit(VCPKG_LINE_INFO); @@ -697,8 +702,10 @@ namespace vcpkg::Install if (ec) { - Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to load manifest file (%s): %s\n", - path_to_manifest.u8string(), ec.message()); + Checks::exit_with_message(VCPKG_LINE_INFO, + "Failed to load manifest file (%s): %s\n", + path_to_manifest.u8string(), + ec.message()); } std::vector specs; @@ -716,7 +723,21 @@ namespace vcpkg::Install Checks::exit_fail(VCPKG_LINE_INFO); } - Commands::SetInstalled::perform_and_exit_ex(args, paths, provider, *binaryprovider, var_provider, specs, install_plan_options, dry_run ? Commands::DryRun::Yes : Commands::DryRun::No); + Optional pkgsconfig; + auto it_pkgsconfig = options.settings.find(OPTION_WRITE_PACKAGES_CONFIG); + if (it_pkgsconfig != options.settings.end()) + { + pkgsconfig = fs::u8path(it_pkgsconfig->second); + } + Commands::SetInstalled::perform_and_exit_ex(args, + paths, + provider, + *binaryprovider, + var_provider, + specs, + install_plan_options, + dry_run ? Commands::DryRun::Yes : Commands::DryRun::No, + pkgsconfig); } const std::vector specs = Util::fmap(args.command_arguments, [&](auto&& arg) { @@ -799,6 +820,17 @@ namespace vcpkg::Install Dependencies::print_plan(action_plan, is_recursive, paths.ports); + auto it_pkgsconfig = options.settings.find(OPTION_WRITE_PACKAGES_CONFIG); + if (it_pkgsconfig != options.settings.end()) + { + Build::compute_all_abis(paths, action_plan, var_provider, status_db); + + auto pkgsconfig_path = Files::combine(paths.original_cwd, fs::u8path(it_pkgsconfig->second)); + auto pkgsconfig_contents = generate_nuget_packages_config(action_plan); + fs.write_contents(pkgsconfig_path, pkgsconfig_contents, VCPKG_LINE_INFO); + System::print2("Wrote NuGet packages config information to ", pkgsconfig_path.u8string(), "\n"); + } + if (dry_run) { Checks::exit_success(VCPKG_LINE_INFO); -- cgit v1.2.3