From f3db66b403840b24ea2612d09cca30a5285f5ea3 Mon Sep 17 00:00:00 2001 From: Victor Romero Date: Fri, 21 Jun 2019 23:50:05 -0700 Subject: Ports Overlay partial implementation (#6981) * Ports Overlay feature spec * Ports Overlay implementation * [--overlay-ports] Refactor handling of additional paths * Code cleanup * [--overlay-ports] Add help * [depend-info] Support --overlay-ports * Add method to load all ports using PathsPortFileProvider * Make PortFileProvider::load_all_control_files() const * Remove unused code * [vcpkg] Avoid double-load of source control file between Build::perform_and_exit and Build::perform_and_exit_ex * [vcpkg] Clang format * [vcpkg] Fixup build failure introduced in b069ceb2f231 * Report errors from Paragraphs::try_load_port() --- toolsrc/src/tests.plan.cpp | 8 +- toolsrc/src/tests.update.cpp | 16 +-- toolsrc/src/vcpkg/build.cpp | 45 ++++--- toolsrc/src/vcpkg/commands.autocomplete.cpp | 3 +- toolsrc/src/vcpkg/commands.buildexternal.cpp | 9 +- toolsrc/src/vcpkg/commands.ci.cpp | 21 +++- toolsrc/src/vcpkg/commands.dependinfo.cpp | 19 ++- toolsrc/src/vcpkg/commands.edit.cpp | 1 + toolsrc/src/vcpkg/commands.search.cpp | 8 +- toolsrc/src/vcpkg/commands.upgrade.cpp | 9 +- toolsrc/src/vcpkg/dependencies.cpp | 170 ++++++++++++++++++++++----- toolsrc/src/vcpkg/export.cpp | 5 +- toolsrc/src/vcpkg/help.cpp | 4 +- toolsrc/src/vcpkg/install.cpp | 14 +-- toolsrc/src/vcpkg/postbuildlint.cpp | 5 +- toolsrc/src/vcpkg/remove.cpp | 3 +- toolsrc/src/vcpkg/update.cpp | 8 +- toolsrc/src/vcpkg/vcpkgcmdarguments.cpp | 115 +++++++++++++++++- toolsrc/src/vcpkg/vcpkgpaths.cpp | 3 - 19 files changed, 368 insertions(+), 98 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/tests.plan.cpp b/toolsrc/src/tests.plan.cpp index 238aa7032..ab24266b4 100644 --- a/toolsrc/src/tests.plan.cpp +++ b/toolsrc/src/tests.plan.cpp @@ -47,7 +47,8 @@ namespace UnitTest1 Assert::AreEqual(plan.spec.triplet().to_string().c_str(), triplet.to_string().c_str()); - Assert::AreEqual(pkg_name.c_str(), plan.source_control_file.get()->core_paragraph->name.c_str()); + auto* scfl = plan.source_control_file_location.get(); + Assert::AreEqual(pkg_name.c_str(), scfl->source_control_file->core_paragraph->name.c_str()); Assert::AreEqual(size_t(vec.size()), feature_list.size()); for (auto&& feature_name : vec) @@ -79,7 +80,7 @@ namespace UnitTest1 /// struct PackageSpecMap { - std::unordered_map map; + std::unordered_map map; Triplet triplet; PackageSpecMap(const Triplet& t = Triplet::X86_WINDOWS) noexcept { triplet = t; } @@ -94,7 +95,8 @@ namespace UnitTest1 { auto spec = PackageSpec::from_name_and_triplet(scf.core_paragraph->name, triplet); Assert::IsTrue(spec.has_value()); - map.emplace(scf.core_paragraph->name, std::move(scf)); + map.emplace(scf.core_paragraph->name, + SourceControlFileLocation{std::unique_ptr(std::move(&scf)), ""}); return PackageSpec{*spec.get()}; } }; diff --git a/toolsrc/src/tests.update.cpp b/toolsrc/src/tests.update.cpp index b6e487c17..5e3f9f3e2 100644 --- a/toolsrc/src/tests.update.cpp +++ b/toolsrc/src/tests.update.cpp @@ -21,9 +21,9 @@ namespace UnitTest1 StatusParagraphs status_db(std::move(status_paragraphs)); - std::unordered_map map; + std::unordered_map map; auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); - map.emplace("a", std::move(*scf)); + map.emplace("a", SourceControlFileLocation { std::move(scf), "" }); Dependencies::MapPortFileProvider provider(map); auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), @@ -45,9 +45,9 @@ namespace UnitTest1 StatusParagraphs status_db(std::move(status_paragraphs)); - std::unordered_map map; + std::unordered_map map; auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); - map.emplace("a", std::move(*scf)); + map.emplace("a", SourceControlFileLocation { std::move(scf), "" }); Dependencies::MapPortFileProvider provider(map); auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), @@ -71,9 +71,9 @@ namespace UnitTest1 StatusParagraphs status_db(std::move(status_paragraphs)); - std::unordered_map map; + std::unordered_map map; auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); - map.emplace("a", std::move(*scf)); + map.emplace("a", SourceControlFileLocation{ std::move(scf), "" }); Dependencies::MapPortFileProvider provider(map); auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), @@ -92,9 +92,9 @@ namespace UnitTest1 StatusParagraphs status_db(std::move(status_paragraphs)); - std::unordered_map map; + std::unordered_map map; auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "2"}}})); - map.emplace("a", std::move(*scf)); + map.emplace("a", SourceControlFileLocation{ std::move(scf), "" }); Dependencies::MapPortFileProvider provider(map); auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index daff7e6c8..059a09432 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -23,6 +23,7 @@ #include using vcpkg::Build::BuildResult; +using vcpkg::Dependencies::PathsPortFileProvider; using vcpkg::Parse::ParseControlErrorInfo; using vcpkg::Parse::ParseExpected; @@ -34,34 +35,26 @@ namespace vcpkg::Build::Command static constexpr StringLiteral OPTION_CHECKS_ONLY = "--checks-only"; void perform_and_exit_ex(const FullPackageSpec& full_spec, - const fs::path& port_dir, + const SourceControlFileLocation& scfl, const ParsedArguments& options, const VcpkgPaths& paths) { const PackageSpec& spec = full_spec.package_spec; + const auto& scf = *scfl.source_control_file; if (Util::Sets::contains(options.switches, OPTION_CHECKS_ONLY)) { const auto pre_build_info = Build::PreBuildInfo::from_triplet_file(paths, spec.triplet()); const auto build_info = Build::read_build_info(paths.get_filesystem(), paths.build_info_file_path(spec)); - const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info); + const size_t error_count = + PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info, scfl.source_location); Checks::check_exit(VCPKG_LINE_INFO, error_count == 0); Checks::exit_success(VCPKG_LINE_INFO); } - const ParseExpected source_control_file = - Paragraphs::try_load_port(paths.get_filesystem(), port_dir); - - if (!source_control_file.has_value()) - { - print_error_message(source_control_file.error()); - Checks::exit_fail(VCPKG_LINE_INFO); - } - - const auto& scf = source_control_file.value_or_exit(VCPKG_LINE_INFO); Checks::check_exit(VCPKG_LINE_INFO, - spec.name() == scf->core_paragraph->name, + spec.name() == scf.core_paragraph->name, "The Source field inside the CONTROL file does not match the port directory: '%s' != '%s'", - scf->core_paragraph->name, + scf.core_paragraph->name, spec.name()); const StatusParagraphs status_db = database_load_check(paths); @@ -80,7 +73,7 @@ namespace vcpkg::Build::Command features_as_set.emplace("core"); const Build::BuildPackageConfig build_config{ - *scf, spec.triplet(), fs::path{port_dir}, build_package_options, features_as_set}; + scf, spec.triplet(), fs::path(scfl.source_location), build_package_options, features_as_set}; const auto build_timer = Chrono::ElapsedTimer::create_started(); const auto result = Build::build_package(paths, build_config, status_db); @@ -128,10 +121,19 @@ namespace vcpkg::Build::Command // Build only takes a single package and all dependencies must already be installed const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); std::string first_arg = args.command_arguments.at(0); + const FullPackageSpec spec = Input::check_and_get_full_package_spec( std::move(first_arg), default_triplet, COMMAND_STRUCTURE.example_text); + Input::check_triplet(spec.package_spec.triplet(), paths); - perform_and_exit_ex(spec, paths.port_dir(spec.package_spec), options, paths); + + PathsPortFileProvider provider(paths, args.overlay_ports.get()); + const auto port_name = spec.package_spec.name(); + const auto* scfl = provider.get_control_file(port_name).get(); + + Checks::check_exit(VCPKG_LINE_INFO, scfl != nullptr, "Error: Couldn't find port '%s'", port_name); + + perform_and_exit_ex(spec, *scfl, options, paths); } } @@ -360,6 +362,12 @@ namespace vcpkg::Build auto& fs = paths.get_filesystem(); const Triplet& triplet = spec.triplet(); + if (!Strings::starts_with(Strings::ascii_to_lowercase(config.port_dir.u8string()), + Strings::ascii_to_lowercase(paths.ports.u8string()))) + { + System::printf("-- Installing port from location: %s\n", config.port_dir.u8string()); + } + #if !defined(_WIN32) // TODO: remove when vcpkg.exe is in charge for acquiring tools. Change introduced in vcpkg v0.0.107. // bootstrap should have already downloaded ninja, but making sure it is present in case it was deleted. @@ -428,7 +436,8 @@ namespace vcpkg::Build } const BuildInfo build_info = read_build_info(fs, paths.build_info_file_path(spec)); - const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info); + const size_t error_count = + PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info, config.port_dir); auto bcf = create_binary_control_file(*config.scf.core_paragraph, triplet, build_info, abi_tag); @@ -705,7 +714,7 @@ namespace vcpkg::Build } } - System::print2("Could not locate cached archive: ", archive_path.u8string(), "\n"); + System::printf("Could not locate cached archive: %s\n", archive_path.u8string()); ExtendedBuildResult result = do_build_package_and_clean_buildtrees( paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config); diff --git a/toolsrc/src/vcpkg/commands.autocomplete.cpp b/toolsrc/src/vcpkg/commands.autocomplete.cpp index afef518eb..3cf4dd98f 100644 --- a/toolsrc/src/vcpkg/commands.autocomplete.cpp +++ b/toolsrc/src/vcpkg/commands.autocomplete.cpp @@ -90,7 +90,8 @@ namespace vcpkg::Commands::Autocomplete const auto port_name = match[2].str(); const auto triplet_prefix = match[3].str(); - auto maybe_port = Paragraphs::try_load_port(paths.get_filesystem(), paths.port_dir(port_name)); + // TODO: Support autocomplete for ports in --overlay-ports + auto maybe_port = Paragraphs::try_load_port(paths.get_filesystem(), paths.ports / port_name); if (maybe_port.error()) { Checks::exit_success(VCPKG_LINE_INFO); diff --git a/toolsrc/src/vcpkg/commands.buildexternal.cpp b/toolsrc/src/vcpkg/commands.buildexternal.cpp index 19b89c2f5..1c3c511c2 100644 --- a/toolsrc/src/vcpkg/commands.buildexternal.cpp +++ b/toolsrc/src/vcpkg/commands.buildexternal.cpp @@ -23,7 +23,12 @@ namespace vcpkg::Commands::BuildExternal std::string(args.command_arguments.at(0)), default_triplet, COMMAND_STRUCTURE.example_text); Input::check_triplet(spec.package_spec.triplet(), paths); - const fs::path port_dir = args.command_arguments.at(1); - Build::Command::perform_and_exit_ex(spec, port_dir, options, paths); + auto overlays = args.overlay_ports ? *args.overlay_ports : std::vector(); + overlays.insert(overlays.begin(), args.command_arguments.at(1)); + Dependencies::PathsPortFileProvider provider(paths, &overlays); + auto maybe_scfl = provider.get_control_file(spec.package_spec.name()); + Checks::check_exit( + VCPKG_LINE_INFO, maybe_scfl.has_value(), "could not load control file for %s", spec.package_spec.name()); + Build::Command::perform_and_exit_ex(spec, maybe_scfl.value_or_exit(VCPKG_LINE_INFO), options, paths); } } diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index de66d917b..8cab79504 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -232,12 +232,17 @@ namespace vcpkg::Commands::CI { // determine abi tag std::string abi; - if (auto scf = p->source_control_file.get()) + if (auto scfl = p->source_control_file_location.get()) { auto triplet = p->spec.triplet(); const Build::BuildPackageConfig build_config{ - *scf, triplet, paths.port_dir(p->spec), build_options, p->feature_list}; + *scfl->source_control_file, + triplet, + static_cast(scfl->source_location), + build_options, + p->feature_list + }; auto dependency_abis = Util::fmap(p->computed_dependencies, [&](const PackageSpec& spec) -> Build::AbiEntry { @@ -351,7 +356,8 @@ namespace vcpkg::Commands::CI } StatusParagraphs status_db = database_load_check(paths); - const auto& paths_port_file = Dependencies::PathsPortFileProvider(paths); + + Dependencies::PathsPortFileProvider provider(paths, args.overlay_ports.get()); const Build::BuildPackageOptions install_plan_options = { Build::UseHeadVersion::NO, @@ -369,7 +375,10 @@ namespace vcpkg::Commands::CI XunitTestResults xunitTestResults; - std::vector all_ports = Install::get_all_port_names(paths); + std::vector all_ports = + Util::fmap(provider.load_all_control_files(), [](auto&& scfl) -> std::string { + return scfl->source_control_file.get()->core_paragraph->name; + }); std::vector results; auto timer = Chrono::ElapsedTimer::create_started(); for (const Triplet& triplet : triplets) @@ -378,13 +387,13 @@ namespace vcpkg::Commands::CI xunitTestResults.push_collection(triplet.canonical_name()); - Dependencies::PackageGraph pgraph(paths_port_file, status_db); + Dependencies::PackageGraph pgraph(provider, status_db); std::vector specs = PackageSpec::to_package_specs(all_ports, triplet); // Install the default features for every package auto all_feature_specs = Util::fmap(specs, [](auto& spec) { return FeatureSpec(spec, ""); }); auto split_specs = - find_unknown_ports_for_ci(paths, exclusions_set, paths_port_file, all_feature_specs, purge_tombstones); + find_unknown_ports_for_ci(paths, exclusions_set, provider, all_feature_specs, purge_tombstones); auto feature_specs = FullPackageSpec::to_feature_specs(split_specs->unknown); for (auto&& fspec : feature_specs) diff --git a/toolsrc/src/vcpkg/commands.dependinfo.cpp b/toolsrc/src/vcpkg/commands.dependinfo.cpp index 48a289fa5..c0800a4b5 100644 --- a/toolsrc/src/vcpkg/commands.dependinfo.cpp +++ b/toolsrc/src/vcpkg/commands.dependinfo.cpp @@ -6,6 +6,9 @@ #include #include #include +#include + +using vcpkg::Dependencies::PathsPortFileProvider; namespace vcpkg::Commands::DependInfo { @@ -35,7 +38,7 @@ namespace vcpkg::Commands::DependInfo return output; } - std::string create_dot_as_string(const std::vector>& source_control_files) + std::string create_dot_as_string(const std::vector& source_control_files) { int empty_node_count = 0; @@ -64,7 +67,7 @@ namespace vcpkg::Commands::DependInfo return s; } - std::string create_dgml_as_string(const std::vector>& source_control_files) + std::string create_dgml_as_string(const std::vector& source_control_files) { std::string s; s.append(""); @@ -109,7 +112,7 @@ namespace vcpkg::Commands::DependInfo } std::string create_graph_as_string(const std::unordered_set& switches, - const std::vector>& source_control_files) + const std::vector& source_control_files) { if (Util::Sets::contains(switches, OPTION_DOT)) { @@ -124,7 +127,7 @@ namespace vcpkg::Commands::DependInfo void build_dependencies_list(std::set& packages_to_keep, const std::string& requested_package, - const std::vector>& source_control_files, + const std::vector& source_control_files, const std::unordered_set& switches) { const auto source_control_file = @@ -154,7 +157,11 @@ namespace vcpkg::Commands::DependInfo { const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); - auto source_control_files = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports); + // TODO: Optimize implementation, current implementation needs to load all ports from disk which is too slow. + PathsPortFileProvider provider(paths, args.overlay_ports.get()); + auto source_control_files = Util::fmap(provider.load_all_control_files(), [](auto&& scfl) -> const SourceControlFile * { + return scfl->source_control_file.get(); + }); if (args.command_arguments.size() >= 1) { @@ -178,7 +185,7 @@ namespace vcpkg::Commands::DependInfo for (auto&& source_control_file : source_control_files) { - const SourceParagraph& source_paragraph = *source_control_file->core_paragraph; + const SourceParagraph& source_paragraph = *source_control_file->core_paragraph.get(); const auto s = Strings::join(", ", source_paragraph.depends, [](const Dependency& d) { return d.name(); }); System::print2(source_paragraph.name, ": ", s, "\n"); } diff --git a/toolsrc/src/vcpkg/commands.edit.cpp b/toolsrc/src/vcpkg/commands.edit.cpp index 98176b2b0..f2f0b1569 100644 --- a/toolsrc/src/vcpkg/commands.edit.cpp +++ b/toolsrc/src/vcpkg/commands.edit.cpp @@ -79,6 +79,7 @@ namespace vcpkg::Commands::Edit const auto& fs = paths.get_filesystem(); auto packages = fs.get_files_non_recursive(paths.packages); + // TODO: Support edit for --overlay-ports return Util::fmap(ports, [&](const std::string& port_name) -> std::string { const auto portpath = paths.ports / port_name; const auto portfile = portpath / "portfile.cmake"; diff --git a/toolsrc/src/vcpkg/commands.search.cpp b/toolsrc/src/vcpkg/commands.search.cpp index a0afd69e1..3d8387ee1 100644 --- a/toolsrc/src/vcpkg/commands.search.cpp +++ b/toolsrc/src/vcpkg/commands.search.cpp @@ -7,6 +7,9 @@ #include #include #include +#include + +using vcpkg::Dependencies::PathsPortFileProvider; namespace vcpkg::Commands::Search { @@ -63,7 +66,10 @@ namespace vcpkg::Commands::Search const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); const bool full_description = Util::Sets::contains(options.switches, OPTION_FULLDESC); - auto source_paragraphs = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports); + PathsPortFileProvider provider(paths, args.overlay_ports.get()); + auto source_paragraphs = Util::fmap(provider.load_all_control_files(), [](auto&& port) -> const SourceControlFile * { + return port->source_control_file.get(); + }); if (args.command_arguments.empty()) { diff --git a/toolsrc/src/vcpkg/commands.upgrade.cpp b/toolsrc/src/vcpkg/commands.upgrade.cpp index 29815ca94..77183ceaf 100644 --- a/toolsrc/src/vcpkg/commands.upgrade.cpp +++ b/toolsrc/src/vcpkg/commands.upgrade.cpp @@ -43,7 +43,8 @@ namespace vcpkg::Commands::Upgrade StatusParagraphs status_db = database_load_check(paths); - Dependencies::PathsPortFileProvider provider(paths); + // Load ports from ports dirs + Dependencies::PathsPortFileProvider provider(paths, args.overlay_ports.get()); Dependencies::PackageGraph graph(provider, status_db); // input sanitization @@ -85,12 +86,12 @@ namespace vcpkg::Commands::Upgrade not_installed.push_back(spec); } - auto maybe_scf = provider.get_control_file(spec.name()); - if (auto p_scf = maybe_scf.get()) + auto maybe_scfl = provider.get_control_file(spec.name()); + if (auto p_scfl = maybe_scfl.get()) { if (it != status_db.end()) { - if (p_scf->core_paragraph->version != (*it)->package.version) + if (p_scfl->source_control_file->core_paragraph->version != (*it)->package.version) { to_upgrade.push_back(spec); } diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp index f4a05e7dc..df472515f 100644 --- a/toolsrc/src/vcpkg/dependencies.cpp +++ b/toolsrc/src/vcpkg/dependencies.cpp @@ -22,7 +22,7 @@ namespace vcpkg::Dependencies struct ClusterSource { - const SourceControlFile* scf = nullptr; + const SourceControlFileLocation* scfl = nullptr; std::unordered_map> build_edges; }; @@ -92,12 +92,12 @@ namespace vcpkg::Dependencies if (it == m_graph.end()) { // Load on-demand from m_provider - auto maybe_scf = m_provider.get_control_file(spec.name()); + auto maybe_scfl = m_provider.get_control_file(spec.name()); auto& clust = m_graph[spec]; clust.spec = spec; - if (auto p_scf = maybe_scf.get()) + if (auto p_scfl = maybe_scfl.get()) { - clust.source = cluster_from_scf(*p_scf, clust.spec.triplet()); + clust.source = cluster_from_scf(*p_scfl, clust.spec.triplet()); } return clust; } @@ -105,15 +105,17 @@ namespace vcpkg::Dependencies } private: - static ClusterSource cluster_from_scf(const SourceControlFile& scf, Triplet t) + static ClusterSource cluster_from_scf(const SourceControlFileLocation& scfl, Triplet t) { ClusterSource ret; - ret.build_edges.emplace("core", filter_dependencies_to_specs(scf.core_paragraph->depends, t)); + ret.build_edges.emplace("core", + filter_dependencies_to_specs(scfl.source_control_file->core_paragraph->depends, + t)); - for (const auto& feature : scf.feature_paragraphs) + for (const auto& feature : scfl.source_control_file->feature_paragraphs) ret.build_edges.emplace(feature->name, filter_dependencies_to_specs(feature->depends, t)); - ret.scf = &scf; + ret.scfl = &scfl; return ret; } @@ -151,12 +153,12 @@ namespace vcpkg::Dependencies } InstallPlanAction::InstallPlanAction(const PackageSpec& spec, - const SourceControlFile& scf, + const SourceControlFileLocation& scfl, const std::set& features, const RequestType& request_type, std::vector&& dependencies) : spec(spec) - , source_control_file(scf) + , source_control_file_location(scfl) , plan_type(InstallPlanType::BUILD_AND_INSTALL) , request_type(request_type) , build_options{} @@ -268,37 +270,145 @@ namespace vcpkg::Dependencies return left->spec.name() < right->spec.name(); } - MapPortFileProvider::MapPortFileProvider(const std::unordered_map& map) : ports(map) - { - } + MapPortFileProvider::MapPortFileProvider(const std::unordered_map& map) + : ports(map) + {} - Optional MapPortFileProvider::get_control_file(const std::string& spec) const + Optional MapPortFileProvider::get_control_file(const std::string& spec) const { auto scf = ports.find(spec); if (scf == ports.end()) return nullopt; return scf->second; } - PathsPortFileProvider::PathsPortFileProvider(const VcpkgPaths& paths) : ports(paths) {} + std::vector MapPortFileProvider::load_all_control_files() const + { + return Util::fmap(ports, [](auto&& kvpair) -> const SourceControlFileLocation * { return &kvpair.second; }); + } - Optional PathsPortFileProvider::get_control_file(const std::string& spec) const + PathsPortFileProvider::PathsPortFileProvider(const vcpkg::VcpkgPaths& paths, + const std::vector* ports_dirs_paths) + : filesystem(paths.get_filesystem()) + { + if (ports_dirs_paths) + { + for (auto&& overlay_path : *ports_dirs_paths) + { + if (!overlay_path.empty()) + { + auto overlay = fs::stdfs::canonical(fs::u8path(overlay_path)); + + Checks::check_exit(VCPKG_LINE_INFO, + filesystem.exists(overlay), + "Error: Path \"%s\" does not exist", + overlay.string()); + + Checks::check_exit(VCPKG_LINE_INFO, + fs::stdfs::is_directory(overlay), + "Error: Path \"%s\" must be a directory", + overlay.string()); + + ports_dirs.emplace_back(overlay); + } + } + } + ports_dirs.emplace_back(paths.ports); + } + + Optional PathsPortFileProvider::get_control_file(const std::string& spec) const { auto cache_it = cache.find(spec); if (cache_it != cache.end()) { return cache_it->second; } - Parse::ParseExpected source_control_file = - Paragraphs::try_load_port(ports.get_filesystem(), ports.port_dir(spec)); - if (auto scf = source_control_file.get()) + for (auto&& ports_dir : ports_dirs) { - auto it = cache.emplace(spec, std::move(*scf->get())); - return it.first->second; + // Try loading individual port + if (filesystem.exists(ports_dir / "CONTROL")) + { + auto maybe_scf = Paragraphs::try_load_port(filesystem, ports_dir); + if (auto scf = maybe_scf.get()) + { + if (scf->get()->core_paragraph->name == spec) + { + SourceControlFileLocation scfl{ std::move(*scf), ports_dir }; + auto it = cache.emplace(spec, std::move(scfl)); + return it.first->second; + } + } + else + { + vcpkg::print_error_message(maybe_scf.error()); + Checks::exit_with_message(VCPKG_LINE_INFO, + "Error: Failed to load port from %s", + spec, ports_dir.u8string()); + } + } + + auto found_scf = Paragraphs::try_load_port(filesystem, ports_dir / spec); + if (auto scf = found_scf.get()) + { + if (scf->get()->core_paragraph->name == spec) + { + SourceControlFileLocation scfl{ std::move(*scf), ports_dir / spec }; + auto it = cache.emplace(spec, std::move(scfl)); + return it.first->second; + } + } } + return nullopt; } + std::vector PathsPortFileProvider::load_all_control_files() const + { + // Reload cache with ports contained in all ports_dirs + cache.clear(); + std::vector ret; + for (auto&& ports_dir : ports_dirs) + { + // Try loading individual port + if (filesystem.exists(ports_dir / "CONTROL")) + { + auto maybe_scf = Paragraphs::try_load_port(filesystem, ports_dir); + if (auto scf = maybe_scf.get()) + { + auto port_name = scf->get()->core_paragraph->name; + if (cache.find(port_name) == cache.end()) + { + SourceControlFileLocation scfl{ std::move(*scf), ports_dir }; + auto it = cache.emplace(port_name, std::move(scfl)); + ret.emplace_back(&it.first->second); + } + } + else + { + vcpkg::print_error_message(maybe_scf.error()); + Checks::exit_with_message(VCPKG_LINE_INFO, + "Error: Failed to load port from %s", + ports_dir.u8string()); + } + continue; + } + + // Try loading all ports inside ports_dir + auto found_scf = Paragraphs::load_all_ports(filesystem, ports_dir); + for (auto&& scf : found_scf) + { + auto port_name = scf->core_paragraph->name; + if (cache.find(port_name) == cache.end()) + { + SourceControlFileLocation scfl{ std::move(scf), ports_dir / port_name }; + auto it = cache.emplace(port_name, std::move(scfl)); + ret.emplace_back(&it.first->second); + } + } + } + return ret; + } + std::vector create_remove_plan(const std::vector& specs, const StatusParagraphs& status_db) { @@ -495,10 +605,11 @@ namespace vcpkg::Dependencies VCPKG_LINE_INFO, "Error: Cannot find definition for package `%s`.", cluster.spec.name()); } + auto&& control_file = *p_source->scfl->source_control_file.get(); if (feature.empty()) { // Add default features for this package. This is an exact reference, so ignore prevent_default_features. - for (auto&& default_feature : p_source->scf->core_paragraph.get()->default_features) + for (auto&& default_feature : control_file.core_paragraph.get()->default_features) { auto res = mark_plus(default_feature, cluster, graph, graph_plan, prevent_default_features); if (res != MarkPlusResult::SUCCESS) @@ -513,7 +624,7 @@ namespace vcpkg::Dependencies if (feature == "*") { - for (auto&& fpgh : p_source->scf->feature_paragraphs) + for (auto&& fpgh : control_file.feature_paragraphs) { auto res = mark_plus(fpgh->name, cluster, graph, graph_plan, prevent_default_features); @@ -590,7 +701,8 @@ namespace vcpkg::Dependencies // Check if any default features have been added auto& previous_df = p_installed->ipv.core->package.default_features; - for (auto&& default_feature : p_source->scf->core_paragraph->default_features) + auto&& control_file = *p_source->scfl->source_control_file.get(); + for (auto&& default_feature : control_file.core_paragraph->default_features) { if (std::find(previous_df.begin(), previous_df.end(), default_feature) == previous_df.end()) { @@ -635,7 +747,7 @@ namespace vcpkg::Dependencies /// Map of all source control files in the current environment. /// Feature specifications to resolve dependencies for. /// Status of installed packages in the current environment. - std::vector create_feature_install_plan(const std::unordered_map& map, + std::vector create_feature_install_plan(const std::unordered_map& map, const std::vector& specs, const StatusParagraphs& status_db) { @@ -698,7 +810,11 @@ namespace vcpkg::Dependencies if (p_cluster->transient_uninstalled) { // If it will be transiently uninstalled, we need to issue a full installation command - auto pscf = p_cluster->source.value_or_exit(VCPKG_LINE_INFO).scf; + auto* pscfl = p_cluster->source.value_or_exit(VCPKG_LINE_INFO).scfl; + Checks::check_exit(VCPKG_LINE_INFO, + pscfl != nullptr, + "Error: Expected a SourceControlFileLocation to exist"); + auto&& scfl = *pscfl; auto dep_specs = Util::fmap(m_graph_plan->install_graph.adjacency_list(p_cluster), [](ClusterPtr const& p) { return p->spec; }); @@ -706,7 +822,7 @@ namespace vcpkg::Dependencies plan.emplace_back(InstallPlanAction{ p_cluster->spec, - *pscf, + scfl, p_cluster->to_install_features, p_cluster->request_type, std::move(dep_specs), diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp index 23fc7441a..88c1526c5 100644 --- a/toolsrc/src/vcpkg/export.cpp +++ b/toolsrc/src/vcpkg/export.cpp @@ -488,7 +488,10 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console // create the plan const StatusParagraphs status_db = database_load_check(paths); - Dependencies::PathsPortFileProvider provider(paths); + + // Load ports from ports dirs + Dependencies::PathsPortFileProvider provider(paths, args.overlay_ports.get()); + std::vector export_plan = Dependencies::create_export_plan(opts.specs, status_db); Checks::check_exit(VCPKG_LINE_INFO, !export_plan.empty(), "Export plan cannot be empty"); diff --git a/toolsrc/src/vcpkg/help.cpp b/toolsrc/src/vcpkg/help.cpp index b92e9ca59..6ee573dfc 100644 --- a/toolsrc/src/vcpkg/help.cpp +++ b/toolsrc/src/vcpkg/help.cpp @@ -111,10 +111,12 @@ namespace vcpkg::Help " vcpkg contact Display contact information to send feedback\n" "\n" "Options:\n" - " --triplet Specify the target architecture triplet.\n" + " --triplet Specify the target architecture triplet\n" " (default: " ENVVAR(VCPKG_DEFAULT_TRIPLET) // ", see 'vcpkg help triplet')\n" "\n" + " --overlay-ports= Specify directories to be used when searching for ports\n" + "\n" " --vcpkg-root Specify the vcpkg root " "directory\n" " (default: " ENVVAR(VCPKG_ROOT) // diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 88b15fe7a..781629236 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -330,9 +330,10 @@ namespace vcpkg::Install System::printf("Building package %s...\n", display_name_with_features); auto result = [&]() -> Build::ExtendedBuildResult { - const Build::BuildPackageConfig build_config{action.source_control_file.value_or_exit(VCPKG_LINE_INFO), + const auto& scfl = action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO); + const Build::BuildPackageConfig build_config{*scfl.source_control_file, action.spec.triplet(), - paths.port_dir(action.spec), + static_cast(scfl.source_location), action.build_options, action.feature_list}; return Build::build_package(paths, build_config, status_db); @@ -652,13 +653,10 @@ namespace vcpkg::Install Build::FailOnTombstone::NO, }; - auto all_ports = Paragraphs::load_all_ports(fs, paths.ports); - std::unordered_map scf_map; - for (auto&& port : all_ports) - scf_map[port->core_paragraph->name] = std::move(*port); - MapPortFileProvider provider(scf_map); + //// Load ports from ports dirs + PathsPortFileProvider provider(paths, args.overlay_ports.get()); - // Note: action_plan will hold raw pointers to SourceControlFiles from this map + // Note: action_plan will hold raw pointers to SourceControlFileLocations from this map std::vector action_plan = create_feature_install_plan(provider, FullPackageSpec::to_feature_specs(specs), status_db); diff --git a/toolsrc/src/vcpkg/postbuildlint.cpp b/toolsrc/src/vcpkg/postbuildlint.cpp index d6581c2b4..c760a034f 100644 --- a/toolsrc/src/vcpkg/postbuildlint.cpp +++ b/toolsrc/src/vcpkg/postbuildlint.cpp @@ -857,14 +857,15 @@ namespace vcpkg::PostBuildLint size_t perform_all_checks(const PackageSpec& spec, const VcpkgPaths& paths, const PreBuildInfo& pre_build_info, - const BuildInfo& build_info) + const BuildInfo& build_info, + const fs::path& port_dir) { System::print2("-- Performing post-build validation\n"); const size_t error_count = perform_all_checks_and_return_error_count(spec, paths, pre_build_info, build_info); if (error_count != 0) { - const fs::path portfile = paths.ports / spec.name() / "portfile.cmake"; + const fs::path portfile = port_dir / "portfile.cmake"; System::print2(System::Color::error, "Found ", error_count, diff --git a/toolsrc/src/vcpkg/remove.cpp b/toolsrc/src/vcpkg/remove.cpp index f997667ac..a40b27bd7 100644 --- a/toolsrc/src/vcpkg/remove.cpp +++ b/toolsrc/src/vcpkg/remove.cpp @@ -229,7 +229,8 @@ namespace vcpkg::Remove Checks::exit_fail(VCPKG_LINE_INFO); } - Dependencies::PathsPortFileProvider provider(paths); + // Load ports from ports dirs + Dependencies::PathsPortFileProvider provider(paths, args.overlay_ports.get()); specs = Util::fmap(Update::find_outdated_packages(provider, status_db), [](auto&& outdated) { return outdated.spec; }); diff --git a/toolsrc/src/vcpkg/update.cpp b/toolsrc/src/vcpkg/update.cpp index 2c52d5952..6320bae5b 100644 --- a/toolsrc/src/vcpkg/update.cpp +++ b/toolsrc/src/vcpkg/update.cpp @@ -23,10 +23,10 @@ namespace vcpkg::Update for (auto&& ipv : installed_packages) { const auto& pgh = ipv.core; - auto maybe_scf = provider.get_control_file(pgh->package.spec.name()); - if (auto p_scf = maybe_scf.get()) + auto maybe_scfl = provider.get_control_file(pgh->package.spec.name()); + if (auto p_scfl = maybe_scfl.get()) { - auto&& port_version = p_scf->core_paragraph->version; + auto&& port_version = p_scfl->source_control_file->core_paragraph->version; auto&& installed_version = pgh->package.version; if (installed_version != port_version) { @@ -57,7 +57,7 @@ namespace vcpkg::Update const StatusParagraphs status_db = database_load_check(paths); - Dependencies::PathsPortFileProvider provider(paths); + Dependencies::PathsPortFileProvider provider(paths, args.overlay_ports.get()); const auto outdated_packages = SortedVector(find_outdated_packages(provider, status_db), &OutdatedPackage::compare_by_name); diff --git a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp index 8565c28f9..21bf4d028 100644 --- a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp +++ b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp @@ -45,6 +45,45 @@ namespace vcpkg option_field = new_setting; } + static void parse_multivalue(const std::string* arg_begin, + const std::string* arg_end, + const std::string& option_name, + std::unique_ptr>& option_field) + { + if (arg_begin == arg_end) + { + System::print2(System::Color::error, "Error: expected value after ", option_name, '\n'); + Metrics::g_metrics.lock()->track_property("error", "error option name"); + Help::print_usage(); + Checks::exit_fail(VCPKG_LINE_INFO); + } + + if (!option_field) + { + option_field = std::make_unique>(); + } + option_field->emplace_back(*arg_begin); + } + + static void parse_cojoined_multivalue(std::string new_value, + const std::string& option_name, + std::unique_ptr>& option_field) + { + if (new_value.empty()) + { + System::print2(System::Color::error, "Error: expected value after ", option_name, '\n'); + Metrics::g_metrics.lock()->track_property("error", "error option name"); + Help::print_usage(); + Checks::exit_fail(VCPKG_LINE_INFO); + } + + if (!option_field) + { + option_field = std::make_unique>(); + } + option_field->emplace_back(std::move(new_value)); + } + VcpkgCmdArguments VcpkgCmdArguments::create_from_command_line(const int argc, const CommandLineCharType* const* const argv) { @@ -117,6 +156,13 @@ namespace vcpkg parse_value(arg_begin, arg_end, "--triplet", args.triplet); continue; } + if (Strings::starts_with(arg, "--overlay-ports=")) + { + parse_cojoined_multivalue(arg.substr(sizeof("--overlay-ports=") - 1), + "--overlay-ports", + args.overlay_ports); + continue; + } if (arg == "--debug") { parse_switch(true, "debug", args.debug); @@ -166,7 +212,21 @@ namespace vcpkg const auto eq_pos = arg.find('='); if (eq_pos != std::string::npos) { - args.optional_command_arguments.emplace(arg.substr(0, eq_pos), arg.substr(eq_pos + 1)); + const auto& key = arg.substr(0, eq_pos); + const auto& value = arg.substr(eq_pos + 1); + + auto it = args.optional_command_arguments.find(key); + if (args.optional_command_arguments.end() == it) + { + args.optional_command_arguments.emplace(key, std::vector { value }); + } + else + { + if (auto* maybe_values = it->second.get()) + { + maybe_values->emplace_back(value); + } + } } else { @@ -264,7 +324,51 @@ namespace vcpkg } else { - output.settings.emplace(option.name, it->second.value_or_exit(VCPKG_LINE_INFO)); + const auto& value = it->second.value_or_exit(VCPKG_LINE_INFO); + if (value.front().empty()) + { + // Fail when not given a value, e.g.: "vcpkg install sqlite3 --additional-ports=" + System::printf( + System::Color::error, "Error: The option '%s' must be passed an argument.\n", option.name); + failed = true; + } + else + { + output.settings.emplace(option.name, value.front()); + options_copy.erase(it); + } + } + } + } + + for (auto&& option : command_structure.options.multisettings) + { + const auto it = options_copy.find(option.name); + if (it != options_copy.end()) + { + if (!it->second.has_value()) + { + // Not having a string value indicates it was passed like '--a' + System::printf( + System::Color::error, "Error: The option '%s' must be passed an argument.\n", option.name); + failed = true; + } + else + { + const auto& value = it->second.value_or_exit(VCPKG_LINE_INFO); + for (auto&& v : value) + { + if (v.empty()) + { + System::printf( + System::Color::error, "Error: The option '%s' must be passed an argument.\n", option.name); + failed = true; + } + else + { + output.multisettings[option.name].emplace_back(v); + } + } options_copy.erase(it); } } @@ -306,7 +410,14 @@ namespace vcpkg { System::printf(" %-40s %s\n", (option.name + "=..."), option.short_help_text); } + for (auto&& option : command_structure.options.multisettings) + { + System::printf(" %-40s %s\n", (option.name + "=..."), option.short_help_text); + } System::printf(" %-40s %s\n", "--triplet ", "Set the default triplet for unqualified packages"); + System::printf(" %-40s %s\n", + "--overlay-ports=", + "Specify directories to be used when searching for ports"); System::printf(" %-40s %s\n", "--vcpkg-root ", "Specify the vcpkg directory to use instead of current directory or tool directory"); diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 512bcfc35..562a18c9b 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -81,9 +81,6 @@ namespace vcpkg fs::path VcpkgPaths::package_dir(const PackageSpec& spec) const { return this->packages / spec.dir(); } - fs::path VcpkgPaths::port_dir(const PackageSpec& spec) const { return this->ports / spec.name(); } - fs::path VcpkgPaths::port_dir(const std::string& name) const { return this->ports / name; } - fs::path VcpkgPaths::build_info_file_path(const PackageSpec& spec) const { return this->package_dir(spec) / "BUILD_INFO"; -- cgit v1.2.3 From 9e565e986789cf273de12fe1b07ce31800d10417 Mon Sep 17 00:00:00 2001 From: Victor Romero Date: Mon, 24 Jun 2019 12:09:48 -0700 Subject: [--overlay-ports] Show location of overriden ports during install plan (#7002) * [--overlay-ports] Show source location of overlayed ports during install plan * Code cleanup * Code cleanup --- toolsrc/src/vcpkg/commands.ci.cpp | 2 +- toolsrc/src/vcpkg/commands.upgrade.cpp | 2 +- toolsrc/src/vcpkg/dependencies.cpp | 40 +++++++++++++++++++++++++++++----- toolsrc/src/vcpkg/install.cpp | 2 +- 4 files changed, 38 insertions(+), 8 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index 8cab79504..c12c26ff7 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -451,7 +451,7 @@ namespace vcpkg::Commands::CI if (is_dry_run) { - Dependencies::print_plan(action_plan); + Dependencies::print_plan(action_plan, true, paths.ports); } else { diff --git a/toolsrc/src/vcpkg/commands.upgrade.cpp b/toolsrc/src/vcpkg/commands.upgrade.cpp index 77183ceaf..1e64b2eb6 100644 --- a/toolsrc/src/vcpkg/commands.upgrade.cpp +++ b/toolsrc/src/vcpkg/commands.upgrade.cpp @@ -171,7 +171,7 @@ namespace vcpkg::Commands::Upgrade } } - Dependencies::print_plan(plan, true); + Dependencies::print_plan(plan, true, paths.ports); if (!no_dry_run) { diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp index df472515f..b604c9acf 100644 --- a/toolsrc/src/vcpkg/dependencies.cpp +++ b/toolsrc/src/vcpkg/dependencies.cpp @@ -123,6 +123,27 @@ namespace vcpkg::Dependencies const PortFileProvider& m_provider; }; + std::string to_output_string(RequestType request_type, + const CStringView s, + const Build::BuildPackageOptions& options, + const fs::path& install_port_path, + const fs::path& default_port_path) + { + if (!default_port_path.empty() + && !Strings::case_insensitive_ascii_starts_with(install_port_path.u8string(), + default_port_path.u8string())) + { + const char* const from_head = options.use_head_version == Build::UseHeadVersion::YES ? " (from HEAD)" : ""; + switch (request_type) + { + case RequestType::AUTO_SELECTED: return Strings::format(" * %s%s -- %s", s, from_head, install_port_path.u8string()); + case RequestType::USER_REQUESTED: return Strings::format(" %s%s -- %s", s, from_head, install_port_path.u8string()); + default: Checks::unreachable(VCPKG_LINE_INFO); + } + } + return to_output_string(request_type, s, options); + } + std::string to_output_string(RequestType request_type, const CStringView s, const Build::BuildPackageOptions& options) @@ -131,7 +152,7 @@ namespace vcpkg::Dependencies switch (request_type) { - case RequestType::AUTO_SELECTED: return Strings::format(" * %s%s", s, from_head); + case RequestType::AUTO_SELECTED: return Strings::format(" * %s%s", s, from_head); case RequestType::USER_REQUESTED: return Strings::format(" %s%s", s, from_head); default: Checks::unreachable(VCPKG_LINE_INFO); } @@ -141,7 +162,7 @@ namespace vcpkg::Dependencies { switch (request_type) { - case RequestType::AUTO_SELECTED: return Strings::format(" * %s", s); + case RequestType::AUTO_SELECTED: return Strings::format(" * %s", s); case RequestType::USER_REQUESTED: return Strings::format(" %s", s); default: Checks::unreachable(VCPKG_LINE_INFO); } @@ -893,7 +914,7 @@ namespace vcpkg::Dependencies PackageGraph::~PackageGraph() = default; - void print_plan(const std::vector& action_plan, const bool is_recursive) + void print_plan(const std::vector& action_plan, const bool is_recursive, const fs::path& default_ports_dir) { std::vector remove_plans; std::vector rebuilt_plans; @@ -948,8 +969,17 @@ namespace vcpkg::Dependencies std::sort(already_installed_plans.begin(), already_installed_plans.end(), &InstallPlanAction::compare_by_name); std::sort(excluded.begin(), excluded.end(), &InstallPlanAction::compare_by_name); - static auto actions_to_output_string = [](const std::vector& v) { - return Strings::join("\n", v, [](const InstallPlanAction* p) { + static auto actions_to_output_string = [&](const std::vector& v) { + return Strings::join("\n", v, [&](const InstallPlanAction* p) { + if (auto * pscfl = p->source_control_file_location.get()) + { + return to_output_string(p->request_type, + p->displayname(), + p->build_options, + pscfl->source_location, + default_ports_dir); + } + return to_output_string(p->request_type, p->displayname(), p->build_options); }); }; diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 781629236..de19c360a 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -684,7 +684,7 @@ namespace vcpkg::Install Metrics::g_metrics.lock()->track_property("installplan", specs_string); - Dependencies::print_plan(action_plan, is_recursive); + Dependencies::print_plan(action_plan, is_recursive, paths.ports); if (dry_run) { -- cgit v1.2.3 From 35e985d3ccf60235bc4881df4d934610cd507090 Mon Sep 17 00:00:00 2001 From: Victor Romero Date: Thu, 27 Jun 2019 12:20:12 -0700 Subject: Triplets Overlay Implementation (#7053) * Triplets Overlay Implementation * Use cache for get_triplet_file_path() * Code cleanup --- toolsrc/src/vcpkg.cpp | 4 ++- toolsrc/src/vcpkg/build.cpp | 13 +++++-- toolsrc/src/vcpkg/help.cpp | 2 ++ toolsrc/src/vcpkg/vcpkgcmdarguments.cpp | 30 ++++++---------- toolsrc/src/vcpkg/vcpkgpaths.cpp | 61 ++++++++++++++++++++++++++------- 5 files changed, 74 insertions(+), 36 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp index e02bdc71f..5da97b136 100644 --- a/toolsrc/src/vcpkg.cpp +++ b/toolsrc/src/vcpkg.cpp @@ -118,7 +118,9 @@ static void inner(const VcpkgCmdArguments& args) auto default_vs_path = System::get_environment_variable("VCPKG_VISUAL_STUDIO_PATH").value_or(""); - const Expected expected_paths = VcpkgPaths::create(vcpkg_root_dir, default_vs_path); + const Expected expected_paths = VcpkgPaths::create(vcpkg_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/build.cpp b/toolsrc/src/vcpkg/build.cpp index 059a09432..f826a4865 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -361,9 +361,15 @@ namespace vcpkg::Build { auto& fs = paths.get_filesystem(); const Triplet& triplet = spec.triplet(); + const auto& triplet_file_path = paths.get_triplet_file_path(spec.triplet()).u8string(); - if (!Strings::starts_with(Strings::ascii_to_lowercase(config.port_dir.u8string()), - Strings::ascii_to_lowercase(paths.ports.u8string()))) + if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, + paths.triplets.u8string())) + { + System::printf("-- Loading triplet configuration from: %s\n", triplet_file_path); + } + if (!Strings::case_insensitive_ascii_starts_with(config.port_dir.u8string(), + paths.ports.u8string())) { System::printf("-- Installing port from location: %s\n", config.port_dir.u8string()); } @@ -390,6 +396,7 @@ namespace vcpkg::Build {"PORT", config.scf.core_paragraph->name}, {"CURRENT_PORT_DIR", config.port_dir}, {"TARGET_TRIPLET", spec.triplet().canonical_name()}, + {"TARGET_TRIPLET_FILE", triplet_file_path}, {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()}, {"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"}, {"DOWNLOADS", paths.downloads}, @@ -890,7 +897,7 @@ namespace vcpkg::Build const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE); const fs::path ports_cmake_script_path = paths.scripts / "get_triplet_environment.cmake"; - const fs::path triplet_file_path = paths.triplets / (triplet.canonical_name() + ".cmake"); + const fs::path triplet_file_path = paths.get_triplet_file_path(triplet); const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, ports_cmake_script_path, diff --git a/toolsrc/src/vcpkg/help.cpp b/toolsrc/src/vcpkg/help.cpp index 6ee573dfc..896f62661 100644 --- a/toolsrc/src/vcpkg/help.cpp +++ b/toolsrc/src/vcpkg/help.cpp @@ -117,6 +117,8 @@ namespace vcpkg::Help "\n" " --overlay-ports= Specify directories to be used when searching for ports\n" "\n" + " --overlay-triplets= Specify directories containing triplets files\n" + "\n" " --vcpkg-root Specify the vcpkg root " "directory\n" " (default: " ENVVAR(VCPKG_ROOT) // diff --git a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp index 21bf4d028..3c1452d47 100644 --- a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp +++ b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp @@ -45,26 +45,6 @@ namespace vcpkg option_field = new_setting; } - static void parse_multivalue(const std::string* arg_begin, - const std::string* arg_end, - const std::string& option_name, - std::unique_ptr>& option_field) - { - if (arg_begin == arg_end) - { - System::print2(System::Color::error, "Error: expected value after ", option_name, '\n'); - Metrics::g_metrics.lock()->track_property("error", "error option name"); - Help::print_usage(); - Checks::exit_fail(VCPKG_LINE_INFO); - } - - if (!option_field) - { - option_field = std::make_unique>(); - } - option_field->emplace_back(*arg_begin); - } - static void parse_cojoined_multivalue(std::string new_value, const std::string& option_name, std::unique_ptr>& option_field) @@ -163,6 +143,13 @@ namespace vcpkg args.overlay_ports); continue; } + if (Strings::starts_with(arg, "--overlay-triplets=")) + { + parse_cojoined_multivalue(arg.substr(sizeof("--overlay-triplets=") - 1), + "--overlay-triplets", + args.overlay_triplets); + continue; + } if (arg == "--debug") { parse_switch(true, "debug", args.debug); @@ -418,6 +405,9 @@ namespace vcpkg System::printf(" %-40s %s\n", "--overlay-ports=", "Specify directories to be used when searching for ports"); + System::printf(" %-40s %s\n", + "--overlay-triplets=", + "Specify directories containing triplets files"); System::printf(" %-40s %s\n", "--vcpkg-root ", "Specify the vcpkg directory to use instead of current directory or tool directory"); diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 562a18c9b..909fbeb44 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -13,7 +13,9 @@ namespace vcpkg { - Expected VcpkgPaths::create(const fs::path& vcpkg_root_dir, const std::string& default_vs_path) + Expected VcpkgPaths::create(const fs::path& vcpkg_root_dir, + const std::string& default_vs_path, + const std::vector* triplets_dirs) { std::error_code ec; const fs::path canonical_vcpkg_root_dir = fs::stdfs::canonical(vcpkg_root_dir, ec); @@ -76,6 +78,20 @@ namespace vcpkg paths.ports_cmake = paths.scripts / "ports.cmake"; + if (triplets_dirs) + { + for (auto&& triplets_dir : *triplets_dirs) + { + auto path = fs::u8path(triplets_dir); + Checks::check_exit(VCPKG_LINE_INFO, + 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::stdfs::canonical(paths.root / "triplets")); + return paths; } @@ -91,26 +107,47 @@ namespace vcpkg return this->vcpkg_dir_info / (pgh.fullstem() + ".list"); } + bool VcpkgPaths::is_valid_triplet(const Triplet& t) const + { + const auto it = Util::find_if(this->get_available_triplets(), [&](auto&& available_triplet) { + return t.canonical_name() == available_triplet; + }); + return it != this->get_available_triplets().cend(); + } + const std::vector& VcpkgPaths::get_available_triplets() const { return this->available_triplets.get_lazy([this]() -> std::vector { std::vector output; - for (auto&& path : this->get_filesystem().get_files_non_recursive(this->triplets)) + for (auto&& triplets_dir : triplets_dirs) { - output.push_back(path.stem().filename().string()); + for (auto&& path : this->get_filesystem().get_files_non_recursive(triplets_dir)) + { + output.push_back(path.stem().filename().string()); + } } - Util::sort(output); - + Util::sort_unique_erase(output); return output; - }); + }); } - bool VcpkgPaths::is_valid_triplet(const Triplet& t) const - { - const auto it = Util::find_if(this->get_available_triplets(), [&](auto&& available_triplet) { - return t.canonical_name() == available_triplet; - }); - return it != this->get_available_triplets().cend(); + const fs::path VcpkgPaths::get_triplet_file_path(const Triplet& triplet) const + { + return m_triplets_cache.get_lazy(triplet, [&]()-> auto { + for (auto&& triplet_dir : triplets_dirs) + { + auto&& path = triplet_dir / (triplet.canonical_name() + ".cmake"); + if (this->get_filesystem().exists(path)) + { + return path; + } + } + + Checks::exit_with_message(VCPKG_LINE_INFO, + "Error: Triplet file %s.cmake not found", + triplet.canonical_name()); + }); + } const fs::path& VcpkgPaths::get_tool_exe(const std::string& tool) const -- cgit v1.2.3 From b9b2a38c7bd9fd66a5b324b4f398024ad2569d60 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 29 Jun 2019 23:05:09 -0700 Subject: [vcpkg-integrate] Improve spelling, help, and autocomplete. (#7095) --- toolsrc/src/vcpkg/commands.integrate.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/commands.integrate.cpp b/toolsrc/src/vcpkg/commands.integrate.cpp index 6921a5390..fda9e2b11 100644 --- a/toolsrc/src/vcpkg/commands.integrate.cpp +++ b/toolsrc/src/vcpkg/commands.integrate.cpp @@ -409,7 +409,7 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console Checks::exit_with_code(VCPKG_LINE_INFO, rc); } -#elif defined(__unix__) +#else static void integrate_bash(const VcpkgPaths& paths) { const auto home_path = System::get_environment_variable("HOME").value_or_exit(VCPKG_LINE_INFO); @@ -458,11 +458,12 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console "first use\n" " vcpkg integrate remove Remove user-wide integration\n" " vcpkg integrate project Generate a referencing nuget package for individual VS project use\n" - " vcpkg integrate powershell Enable PowerShell Tab-Completion\n"; + " vcpkg integrate powershell Enable PowerShell tab-completion\n"; #else const char* const INTEGRATE_COMMAND_HELPSTRING = " vcpkg integrate install Make installed packages available user-wide.\n" - " vcpkg integrate remove Remove user-wide integration\n"; + " vcpkg integrate remove Remove user-wide integration\n" + " vcpkg integrate bash Enable bash tab-completion\n"; #endif namespace Subcommand @@ -476,7 +477,15 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console static std::vector valid_arguments(const VcpkgPaths&) { - return {Subcommand::INSTALL, Subcommand::REMOVE, Subcommand::PROJECT, Subcommand::POWERSHELL, Subcommand::BASH}; + return + { + Subcommand::INSTALL, Subcommand::REMOVE, +#if defined(_WIN32) + Subcommand::PROJECT, Subcommand::POWERSHELL, +#else + Subcommand::BASH, +#endif + }; } const CommandStructure COMMAND_STRUCTURE = { @@ -510,7 +519,7 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console { return integrate_powershell(paths); } -#elif defined(__unix__) +#else if (args.command_arguments[0] == Subcommand::BASH) { return integrate_bash(paths); -- cgit v1.2.3 From 8e747d659c40775ce2a5a2e5d0230e4fd659ef57 Mon Sep 17 00:00:00 2001 From: Phil Christensen Date: Sun, 30 Jun 2019 00:15:08 -0700 Subject: [vcpkg] fail archived port install when decompression fails (#7086) * [vcpkg] fail port install when decompression fails * [vcpkg] clang-format --- toolsrc/src/vcpkg/build.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index f826a4865..9694bce4c 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -594,7 +594,7 @@ namespace vcpkg::Build return nullopt; } - static void decompress_archive(const VcpkgPaths& paths, const PackageSpec& spec, const fs::path& archive_path) + static int decompress_archive(const VcpkgPaths& paths, const PackageSpec& spec, const fs::path& archive_path) { auto& fs = paths.get_filesystem(); @@ -608,12 +608,13 @@ namespace vcpkg::Build #if defined(_WIN32) auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP); - System::cmd_execute_clean(Strings::format( + int result = System::cmd_execute_clean(Strings::format( R"("%s" x "%s" -o"%s" -y >nul)", seven_zip_exe.u8string(), archive_path.u8string(), pkg_path.u8string())); #else - System::cmd_execute_clean( + int result = System::cmd_execute_clean( Strings::format(R"(unzip -qq "%s" "-d%s")", archive_path.u8string(), pkg_path.u8string())); #endif + return result; } // Compress the source directory into the destination file. @@ -699,11 +700,16 @@ namespace vcpkg::Build { System::print2("Using cached binary package: ", archive_path.u8string(), "\n"); - decompress_archive(paths, spec, archive_path); + auto archive_result = decompress_archive(paths, spec, archive_path); + + if (archive_result != 0) + { + System::print2("Failed to decompress archive package\n"); + return BuildResult::BUILD_FAILED; + } auto maybe_bcf = Paragraphs::try_load_cached_package(paths, spec); - std::unique_ptr bcf = - std::make_unique(std::move(maybe_bcf).value_or_exit(VCPKG_LINE_INFO)); + auto bcf = std::make_unique(std::move(maybe_bcf).value_or_exit(VCPKG_LINE_INFO)); return {BuildResult::SUCCEEDED, std::move(bcf)}; } -- cgit v1.2.3 From e2049cb9754006b6a2abed781d34030e16702fad Mon Sep 17 00:00:00 2001 From: Victor Romero Date: Sun, 30 Jun 2019 09:31:22 -0700 Subject: [vcpkg_configure_cmake] Add NO_CHARSET_FLAG option (#7074) * [vcpkg_configure_cmake] Add NO_CHARSET_FLAG option * [vcpkg_configure_cmake] Add documentation for new NO_CHARSET_FLAG option * [vcpkg_configure_cmake, windows toolchain] Handle NO_CHARSET_FLAG in toolchain * [build.cpp] Add Windows toolchain to package hash * [duilib,msix,thrift,tidy-html5] Use NO_CHARSET_FLAG to fix regressions --- toolsrc/src/vcpkg/build.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 9694bce4c..1975d3aaf 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -1007,6 +1007,12 @@ namespace vcpkg::Build hash += "-"; hash += Hash::get_file_hash(fs, *p, "SHA1"); } + else if (pre_build_info.cmake_system_name.empty() || + pre_build_info.cmake_system_name == "WindowsStore") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "windows.cmake", "SHA1"); + } else if (pre_build_info.cmake_system_name == "Linux") { hash += "-"; -- cgit v1.2.3 From 91da4aab4c74af1d30c68896a058100257910e8d Mon Sep 17 00:00:00 2001 From: martin-s Date: Tue, 2 Jul 2019 05:51:07 +0000 Subject: Allow redirection of the scripts folder. (#6552) * Allow redirection of the scripts folder with an environment variable. * - Updated feature from environment variable to argument. * Fix crash when no scripts override is given and use --scripts-root= format * Update help messages to use --scripts-root= format --- toolsrc/src/tests.arguments.cpp | 6 ++-- toolsrc/src/vcpkg.cpp | 10 +++++++ toolsrc/src/vcpkg/help.cpp | 2 ++ toolsrc/src/vcpkg/vcpkgcmdarguments.cpp | 30 +++++++++++++++++-- toolsrc/src/vcpkg/vcpkgpaths.cpp | 53 ++++++++++++++++++++++----------- 5 files changed, 80 insertions(+), 21 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/tests.arguments.cpp b/toolsrc/src/tests.arguments.cpp index 51ababd3d..533b3a0d0 100644 --- a/toolsrc/src/tests.arguments.cpp +++ b/toolsrc/src/tests.arguments.cpp @@ -15,9 +15,10 @@ namespace UnitTest1 { TEST_METHOD(create_from_arg_sequence_options_lower) { - std::vector t = {"--vcpkg-root", "C:\\vcpkg", "--debug", "--sendmetrics", "--printmetrics"}; + std::vector t = {"--vcpkg-root", "C:\\vcpkg", "--scripts-root", "C:\\scripts", "--debug", "--sendmetrics", "--printmetrics"}; auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); Assert::AreEqual("C:\\vcpkg", v.vcpkg_root_dir.get()->c_str()); + Assert::AreEqual("C:\\scripts", v.scripts_root_dir.get()->c_str()); Assert::IsTrue(v.debug && *v.debug.get()); Assert::IsTrue(v.sendmetrics && v.sendmetrics.get()); Assert::IsTrue(v.printmetrics && *v.printmetrics.get()); @@ -25,9 +26,10 @@ namespace UnitTest1 TEST_METHOD(create_from_arg_sequence_options_upper) { - std::vector t = {"--VCPKG-ROOT", "C:\\vcpkg", "--DEBUG", "--SENDMETRICS", "--PRINTMETRICS"}; + std::vector t = {"--VCPKG-ROOT", "C:\\vcpkg", "--SCRIPTS-ROOT", "C:\\scripts", "--DEBUG", "--SENDMETRICS", "--PRINTMETRICS"}; auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); Assert::AreEqual("C:\\vcpkg", v.vcpkg_root_dir.get()->c_str()); + Assert::AreEqual("C:\\scripts", v.scripts_root_dir.get()->c_str()); Assert::IsTrue(v.debug && *v.debug.get()); Assert::IsTrue(v.sendmetrics && v.sendmetrics.get()); Assert::IsTrue(v.printmetrics && *v.printmetrics.get()); diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp index 5da97b136..363b39814 100644 --- a/toolsrc/src/vcpkg.cpp +++ b/toolsrc/src/vcpkg.cpp @@ -116,9 +116,19 @@ static void inner(const VcpkgCmdArguments& args) Debug::print("Using vcpkg-root: ", vcpkg_root_dir.u8string(), '\n'); + Optional vcpkg_scripts_root_dir = nullopt; + if (nullptr != args.scripts_root_dir) + { + vcpkg_scripts_root_dir = fs::stdfs::canonical(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 expected_paths = VcpkgPaths::create(vcpkg_root_dir, + vcpkg_scripts_root_dir, default_vs_path, args.overlay_triplets.get()); Checks::check_exit(VCPKG_LINE_INFO, diff --git a/toolsrc/src/vcpkg/help.cpp b/toolsrc/src/vcpkg/help.cpp index 896f62661..9b2751739 100644 --- a/toolsrc/src/vcpkg/help.cpp +++ b/toolsrc/src/vcpkg/help.cpp @@ -124,6 +124,8 @@ namespace vcpkg::Help " (default: " ENVVAR(VCPKG_ROOT) // ")\n" "\n" + " --scripts-root= Specify the scripts root directory\n" + "\n" " @response_file Specify a " "response file to provide additional parameters\n" "\n" diff --git a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp index 3c1452d47..7a28fb571 100644 --- a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp +++ b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp @@ -33,6 +33,21 @@ namespace vcpkg option_field = std::make_unique(*arg_begin); } + static void parse_cojoined_value(std::string new_value, + const std::string& option_name, + std::unique_ptr& option_field) + { + if (nullptr != option_field) + { + System::printf(System::Color::error, "Error: %s specified multiple times\n", option_name); + Metrics::g_metrics.lock()->track_property("error", "error option specified multiple times"); + Help::print_usage(); + Checks::exit_fail(VCPKG_LINE_INFO); + } + + option_field = std::make_unique(std::move(new_value)); + } + static void parse_switch(bool new_setting, const std::string& option_name, Optional& option_field) { if (option_field && option_field != new_setting) @@ -120,9 +135,10 @@ namespace vcpkg if (arg[0] == '-' && arg[1] == '-') { - // make argument case insensitive + // make argument case insensitive before the first = auto& f = std::use_facet>(std::locale()); - f.tolower(&arg[0], &arg[0] + arg.size()); + auto first_eq = std::find(std::begin(arg), std::end(arg), '='); + f.tolower(&arg[0], &arg[0] + (first_eq - std::begin(arg))); // command switch if (arg == "--vcpkg-root") { @@ -130,6 +146,13 @@ namespace vcpkg parse_value(arg_begin, arg_end, "--vcpkg-root", args.vcpkg_root_dir); continue; } + if (Strings::starts_with(arg, "--scripts-root=")) + { + parse_cojoined_value(arg.substr(sizeof("--scripts-root=") - 1), + "--scripts-root", + args.scripts_root_dir); + continue; + } if (arg == "--triplet") { ++arg_begin; @@ -411,5 +434,8 @@ namespace vcpkg System::printf(" %-40s %s\n", "--vcpkg-root ", "Specify the vcpkg directory to use instead of current directory or tool directory"); + System::printf(" %-40s %s\n", + "--scripts-root=", + "Specify the scripts directory to use instead of default vcpkg scripts directory"); } } diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 909fbeb44..d16acf2e8 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -13,7 +13,8 @@ namespace vcpkg { - Expected VcpkgPaths::create(const fs::path& vcpkg_root_dir, + Expected VcpkgPaths::create(const fs::path& vcpkg_root_dir, + const Optional& vcpkg_scripts_root_dir, const std::string& default_vs_path, const std::vector* triplets_dirs) { @@ -65,7 +66,25 @@ namespace vcpkg paths.ports = paths.root / "ports"; paths.installed = paths.root / "installed"; paths.triplets = paths.root / "triplets"; - paths.scripts = paths.root / "scripts"; + + if (auto scripts_dir = vcpkg_scripts_root_dir.get()) + { + if (scripts_dir->empty() || !fs::stdfs::is_directory(*scripts_dir)) + { + Metrics::g_metrics.lock()->track_property("error", "Invalid scripts override directory."); + Checks::exit_with_message( + VCPKG_LINE_INFO, + "Invalid scripts override directory: %s; " + "create that directory or unset --scripts-root to use the default scripts location.", + scripts_dir->u8string()); + } + + paths.scripts = *scripts_dir; + } + else + { + paths.scripts = paths.root / "scripts"; + } paths.tools = paths.downloads / "tools"; paths.buildsystems = paths.scripts / "buildsystems"; @@ -132,21 +151,21 @@ namespace vcpkg } const fs::path VcpkgPaths::get_triplet_file_path(const Triplet& triplet) const - { - return m_triplets_cache.get_lazy(triplet, [&]()-> auto { - for (auto&& triplet_dir : triplets_dirs) - { - auto&& path = triplet_dir / (triplet.canonical_name() + ".cmake"); - if (this->get_filesystem().exists(path)) - { - return path; - } - } - - Checks::exit_with_message(VCPKG_LINE_INFO, - "Error: Triplet file %s.cmake not found", - triplet.canonical_name()); - }); + { + return m_triplets_cache.get_lazy(triplet, [&]()-> auto { + for (auto&& triplet_dir : triplets_dirs) + { + auto&& path = triplet_dir / (triplet.canonical_name() + ".cmake"); + if (this->get_filesystem().exists(path)) + { + return path; + } + } + + Checks::exit_with_message(VCPKG_LINE_INFO, + "Error: Triplet file %s.cmake not found", + triplet.canonical_name()); + }); } -- cgit v1.2.3 From 2b8e225b2ea83a3138d4b7345f104c1bd9a129dd Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 6 Jul 2019 13:29:46 -0700 Subject: [vcpkg] Fix powershell font corruption bug (#7094) * [vcpkg] Fix font corruption bug on Windows by downloading Powershell Core * [vcpkg] Rename subtool to powershell-core * [vcpkg] Add missing includes to project files --- toolsrc/src/vcpkg/base/system.cpp | 21 ++++++++++++--------- toolsrc/src/vcpkg/build.cpp | 23 +++++++++++++++++------ toolsrc/src/vcpkg/commands.integrate.cpp | 11 ++--------- 3 files changed, 31 insertions(+), 24 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/system.cpp b/toolsrc/src/vcpkg/base/system.cpp index c5ff050f0..3d5c60088 100644 --- a/toolsrc/src/vcpkg/base/system.cpp +++ b/toolsrc/src/vcpkg/base/system.cpp @@ -188,12 +188,17 @@ namespace vcpkg } #if defined(_WIN32) - static std::wstring compute_clean_environment(const std::unordered_map& extra_env) + static std::wstring compute_clean_environment(const std::unordered_map& extra_env, + const std::string& prepend_to_path) { static const std::string SYSTEM_ROOT = get_environment_variable("SystemRoot").value_or_exit(VCPKG_LINE_INFO); static const std::string SYSTEM_32 = SYSTEM_ROOT + R"(\system32)"; - std::string new_path = Strings::format( - R"(Path=%s;%s;%s\Wbem;%s\WindowsPowerShell\v1.0\)", SYSTEM_32, SYSTEM_ROOT, SYSTEM_32, SYSTEM_32); + std::string new_path = Strings::format(R"(Path=%s%s;%s;%s\Wbem;%s\WindowsPowerShell\v1.0\)", + prepend_to_path, + SYSTEM_32, + SYSTEM_ROOT, + SYSTEM_32, + SYSTEM_32); std::vector env_wstrings = { L"ALLUSERSPROFILE", @@ -348,7 +353,8 @@ namespace vcpkg #endif int System::cmd_execute_clean(const ZStringView cmd_line, - const std::unordered_map& extra_env) + const std::unordered_map& extra_env, + const std::string& prepend_to_path) { auto timer = Chrono::ElapsedTimer::create_started(); #if defined(_WIN32) @@ -357,7 +363,7 @@ namespace vcpkg memset(&process_info, 0, sizeof(PROCESS_INFORMATION)); g_ctrl_c_state.transition_to_spawn_process(); - auto clean_env = compute_clean_environment(extra_env); + auto clean_env = compute_clean_environment(extra_env, prepend_to_path); windows_create_process(cmd_line, clean_env.data(), process_info, NULL); CloseHandle(process_info.hThread); @@ -608,10 +614,7 @@ namespace vcpkg void System::register_console_ctrl_handler() {} #endif - int System::get_num_logical_cores() - { - return std::thread::hardware_concurrency(); - } + int System::get_num_logical_cores() { return std::thread::hardware_concurrency(); } } namespace vcpkg::Debug diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 1975d3aaf..68df1f965 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -363,13 +363,11 @@ namespace vcpkg::Build const Triplet& triplet = spec.triplet(); const auto& triplet_file_path = paths.get_triplet_file_path(spec.triplet()).u8string(); - if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, - paths.triplets.u8string())) + if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.triplets.u8string())) { System::printf("-- Loading triplet configuration from: %s\n", triplet_file_path); } - if (!Strings::case_insensitive_ascii_starts_with(config.port_dir.u8string(), - paths.ports.u8string())) + if (!Strings::case_insensitive_ascii_starts_with(config.port_dir.u8string(), paths.ports.u8string())) { System::printf("-- Installing port from location: %s\n", config.port_dir.u8string()); } @@ -382,6 +380,13 @@ namespace vcpkg::Build const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE); const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT); +#if defined(_WIN32) + const fs::path& powershell_exe_path = paths.get_tool_exe("powershell-core"); + if (!fs.exists(powershell_exe_path.parent_path() / "powershell.exe")) + { + fs.copy(powershell_exe_path, powershell_exe_path.parent_path() / "powershell.exe", fs::copy_options::none); + } +#endif std::string all_features; for (auto& feature : config.scf.feature_paragraphs) @@ -425,8 +430,14 @@ namespace vcpkg::Build } command.append(cmd_launch_cmake); const auto timer = Chrono::ElapsedTimer::create_started(); - - const int return_code = System::cmd_execute_clean(command); + const int return_code = System::cmd_execute_clean( + command, + {} +#ifdef _WIN32 + , + powershell_exe_path.parent_path().u8string() + ";" +#endif + ); const auto buildtimeus = timer.microseconds(); const auto spec_string = spec.to_string(); diff --git a/toolsrc/src/vcpkg/commands.integrate.cpp b/toolsrc/src/vcpkg/commands.integrate.cpp index fda9e2b11..8b2b377bf 100644 --- a/toolsrc/src/vcpkg/commands.integrate.cpp +++ b/toolsrc/src/vcpkg/commands.integrate.cpp @@ -380,17 +380,10 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console static constexpr StringLiteral TITLE = "PowerShell Tab-Completion"; const fs::path script_path = paths.scripts / "addPoshVcpkgToPowershellProfile.ps1"; - // Console font corruption workaround - SetConsoleCP(437); - SetConsoleOutputCP(437); - + const auto& ps = paths.get_tool_exe("powershell-core"); const std::string cmd = Strings::format( - R"(powershell -NoProfile -ExecutionPolicy Bypass -Command "& {& '%s' %s}")", script_path.u8string(), ""); + R"("%s" -NoProfile -ExecutionPolicy Bypass -Command "& {& '%s' }")", ps.u8string(), script_path.u8string()); const int rc = System::cmd_execute(cmd); - - SetConsoleCP(CP_UTF8); - SetConsoleOutputCP(CP_UTF8); - if (rc) { System::printf(System::Color::error, -- cgit v1.2.3 From 7f80c0e2d311c7ff2453bdd558e4e7fd91cea872 Mon Sep 17 00:00:00 2001 From: gnaggnoyil Date: Wed, 10 Jul 2019 04:02:48 +0800 Subject: Make handle features (#6797) --- toolsrc/src/vcpkg/commands.dependinfo.cpp | 61 +++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/commands.dependinfo.cpp b/toolsrc/src/vcpkg/commands.dependinfo.cpp index c0800a4b5..8394e0166 100644 --- a/toolsrc/src/vcpkg/commands.dependinfo.cpp +++ b/toolsrc/src/vcpkg/commands.dependinfo.cpp @@ -6,6 +6,10 @@ #include #include #include +#include + +#include +#include #include using vcpkg::Dependencies::PathsPortFileProvider; @@ -130,14 +134,29 @@ namespace vcpkg::Commands::DependInfo const std::vector& source_control_files, const std::unordered_set& switches) { + auto maybe_requested_spec = ParsedSpecifier::from_string(requested_package); + // TODO: move this check to the top-level invocation of this function since + // argument `requested_package` shall always be valid in inner-level invocation. + if (!maybe_requested_spec.has_value()) + { + System::print2(System::Color::warning, + "'", + requested_package, + "' is not a valid package specifier: ", + vcpkg::to_string(maybe_requested_spec.error()), + "\n"); + return; + } + auto requested_spec = maybe_requested_spec.get(); + const auto source_control_file = - Util::find_if(source_control_files, [&requested_package](const auto& source_control_file) { - return source_control_file->core_paragraph->name == requested_package; + Util::find_if(source_control_files, [&requested_spec](const auto& source_control_file) { + return source_control_file->core_paragraph->name == requested_spec->name; }); if (source_control_file != source_control_files.end()) { - const auto new_package = packages_to_keep.insert(requested_package).second; + const auto new_package = packages_to_keep.insert(requested_spec->name).second; if (new_package && !Util::Sets::contains(switches, OPTION_NO_RECURSE)) { @@ -145,6 +164,42 @@ namespace vcpkg::Commands::DependInfo { build_dependencies_list(packages_to_keep, dependency.depend.name, source_control_files, switches); } + + // Collect features with `*` considered + std::set collected_features; + for (const auto& requested_feature_name : requested_spec->features) + { + if (requested_feature_name == "*") + { + for (auto &&feature_paragraph : (*source_control_file)->feature_paragraphs) + { + collected_features.insert(std::addressof(Util::as_const(*feature_paragraph))); + } + continue; + } + auto maybe_feature = (*source_control_file)->find_feature(requested_feature_name); + if (auto &&feature_paragraph = maybe_feature.get()) + { + collected_features.insert(std::addressof(Util::as_const(*feature_paragraph))); + } + else + { + System::print2(System::Color::warning, + "dependency '", + requested_feature_name, + "' of package '", + requested_spec->name, + "' does not exist\n"); + continue; + } + } + for (auto feature_paragraph : collected_features) + { + for (const auto& dependency : feature_paragraph->depends) + { + build_dependencies_list(packages_to_keep, dependency.depend.name, source_control_files, switches); + } + } } } else -- cgit v1.2.3 From 60bff8d54996d55ffc81995bcb63510686863c84 Mon Sep 17 00:00:00 2001 From: Phil Christensen Date: Wed, 10 Jul 2019 11:36:37 -0700 Subject: allow spaces in pathname on linux (#7216) --- toolsrc/src/vcpkg/base/hash.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/hash.cpp b/toolsrc/src/vcpkg/base/hash.cpp index 310b8c35e..e9a7fa2ef 100644 --- a/toolsrc/src/vcpkg/base/hash.cpp +++ b/toolsrc/src/vcpkg/base/hash.cpp @@ -178,9 +178,11 @@ namespace vcpkg::Hash static std::string parse_shasum_output(const std::string& shasum_output) { std::vector split = Strings::split(shasum_output, " "); + // Checking if >= 3 because filenames with spaces will show up as multiple tokens. + // The hash is the first token so we don't need to parse the filename anyway. Checks::check_exit(VCPKG_LINE_INFO, - split.size() == 3, - "Expected output of the form [hash filename\n] (3 tokens), but got\n" + split.size() >= 3, + "Expected output of the form [hash filename\n] (3+ tokens), but got\n" "[%s] (%s tokens)", shasum_output, std::to_string(split.size())); -- cgit v1.2.3 From 7dbe375a2c270e91f9742dd78cf2b579d1f5f2fa Mon Sep 17 00:00:00 2001 From: Victor Romero Date: Thu, 11 Jul 2019 17:00:55 -0700 Subject: Testing for --overlay-ports and --overlay-triplets args (#7243) --- toolsrc/src/tests.arguments.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- toolsrc/src/tests.plan.cpp | 11 ++++++----- 2 files changed, 44 insertions(+), 7 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/tests.arguments.cpp b/toolsrc/src/tests.arguments.cpp index 533b3a0d0..e108b983a 100644 --- a/toolsrc/src/tests.arguments.cpp +++ b/toolsrc/src/tests.arguments.cpp @@ -15,24 +15,60 @@ namespace UnitTest1 { TEST_METHOD(create_from_arg_sequence_options_lower) { - std::vector t = {"--vcpkg-root", "C:\\vcpkg", "--scripts-root", "C:\\scripts", "--debug", "--sendmetrics", "--printmetrics"}; + std::vector t = { + "--vcpkg-root", "C:\\vcpkg", + "--scripts-root=C:\\scripts", + "--debug", + "--sendmetrics", + "--printmetrics", + "--overlay-ports=C:\\ports1", + "--overlay-ports=C:\\ports2", + "--overlay-triplets=C:\\tripletsA", + "--overlay-triplets=C:\\tripletsB" + }; auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); Assert::AreEqual("C:\\vcpkg", v.vcpkg_root_dir.get()->c_str()); Assert::AreEqual("C:\\scripts", v.scripts_root_dir.get()->c_str()); Assert::IsTrue(v.debug && *v.debug.get()); Assert::IsTrue(v.sendmetrics && v.sendmetrics.get()); Assert::IsTrue(v.printmetrics && *v.printmetrics.get()); + + Assert::IsTrue(v.overlay_ports.get()->size() == 2); + Assert::AreEqual("C:\\ports1", v.overlay_ports.get()->at(0).c_str()); + Assert::AreEqual("C:\\ports2", v.overlay_ports.get()->at(1).c_str()); + + Assert::IsTrue(v.overlay_triplets.get()->size() == 2); + Assert::AreEqual("C:\\tripletsA", v.overlay_triplets.get()->at(0).c_str()); + Assert::AreEqual("C:\\tripletsB", v.overlay_triplets.get()->at(1).c_str()); } TEST_METHOD(create_from_arg_sequence_options_upper) { - std::vector t = {"--VCPKG-ROOT", "C:\\vcpkg", "--SCRIPTS-ROOT", "C:\\scripts", "--DEBUG", "--SENDMETRICS", "--PRINTMETRICS"}; + std::vector t = { + "--VCPKG-ROOT", "C:\\vcpkg", + "--SCRIPTS-ROOT=C:\\scripts", + "--DEBUG", + "--SENDMETRICS", + "--PRINTMETRICS", + "--OVERLAY-PORTS=C:\\ports1", + "--OVERLAY-PORTS=C:\\ports2", + "--OVERLAY-TRIPLETS=C:\\tripletsA", + "--OVERLAY-TRIPLETS=C:\\tripletsB" + }; auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); Assert::AreEqual("C:\\vcpkg", v.vcpkg_root_dir.get()->c_str()); Assert::AreEqual("C:\\scripts", v.scripts_root_dir.get()->c_str()); Assert::IsTrue(v.debug && *v.debug.get()); Assert::IsTrue(v.sendmetrics && v.sendmetrics.get()); Assert::IsTrue(v.printmetrics && *v.printmetrics.get()); + + Assert::IsTrue(v.overlay_ports.get()->size() == 2); + Assert::AreEqual("C:\\ports1", v.overlay_ports.get()->at(0).c_str()); + Assert::AreEqual("C:\\ports2", v.overlay_ports.get()->at(1).c_str()); + + Assert::IsTrue(v.overlay_triplets.get()->size() == 2); + Assert::AreEqual("C:\\tripletsA", v.overlay_triplets.get()->at(0).c_str()); + Assert::AreEqual("C:\\tripletsB", v.overlay_triplets.get()->at(1).c_str()); } TEST_METHOD(create_from_arg_sequence_valued_options) diff --git a/toolsrc/src/tests.plan.cpp b/toolsrc/src/tests.plan.cpp index ab24266b4..9d8717878 100644 --- a/toolsrc/src/tests.plan.cpp +++ b/toolsrc/src/tests.plan.cpp @@ -89,14 +89,15 @@ namespace UnitTest1 const std::vector>& features = {}, const std::vector& default_features = {}) { - return emplace(std::move(*make_control_file(name, depends, features, default_features))); + auto scfl = SourceControlFileLocation { make_control_file(name, depends, features, default_features), "" }; + return emplace(std::move(scfl)); } - PackageSpec emplace(vcpkg::SourceControlFile&& scf) + + PackageSpec emplace(vcpkg::SourceControlFileLocation&& scfl) { - auto spec = PackageSpec::from_name_and_triplet(scf.core_paragraph->name, triplet); + auto spec = PackageSpec::from_name_and_triplet(scfl.source_control_file->core_paragraph->name, triplet); Assert::IsTrue(spec.has_value()); - map.emplace(scf.core_paragraph->name, - SourceControlFileLocation{std::unique_ptr(std::move(&scf)), ""}); + map.emplace(scfl.source_control_file->core_paragraph->name, std::move(scfl)); return PackageSpec{*spec.get()}; } }; -- cgit v1.2.3 From 5857e2c680fde9e37abc8f799f8d5509dd47ed62 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 8 Jul 2019 16:45:27 -0700 Subject: initial remove-in-parallel doesn't actually do parallel remove yet --- toolsrc/src/vcpkg/base/files.cpp | 68 ++++++++++++++++++++++++++++++---------- toolsrc/src/vcpkg/base/rng.cpp | 14 +++++++++ 2 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 toolsrc/src/vcpkg/base/rng.cpp (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 5099795e9..d0926bb4c 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include +#include #include #include #include @@ -256,26 +257,61 @@ namespace vcpkg::Files virtual bool remove(const fs::path& path, std::error_code& ec) override { return fs::stdfs::remove(path, ec); } virtual std::uintmax_t remove_all(const fs::path& path, std::error_code& ec) override { - // Working around the currently buggy remove_all() - std::uintmax_t out = fs::stdfs::remove_all(path, ec); + /* + does not use the std::filesystem call since it is buggy, and can + have spurious errors before VS 2017 update 6, and on later versions + (as well as on macOS and Linux), this is just as fast and will have + fewer spurious errors due to locks. + */ + struct recursive { + const fs::path& tmp_directory; + std::error_code& ec; + xoshiro256ss_engine& rng; + + void operator()(const fs::path& current) const { + const auto type = fs::stdfs::symlink_status(current, ec).type(); + if (ec) return; + + const auto tmp_name = Strings::b64url_encode(rng()); + const auto tmp_path = tmp_directory / tmp_name; + + switch (type) { + case fs::file_type::directory: { + fs::stdfs::rename(current, tmp_path, ec); + if (ec) return; + for (const auto& entry : fs::stdfs::directory_iterator(tmp_path)) { + (*this)(entry); + } + fs::stdfs::remove(tmp_path, ec); + } break; + case fs::file_type::symlink: + case fs::file_type::regular: { + fs::stdfs::rename(current, tmp_path, ec); + fs::stdfs::remove(current, ec); + } break; + case fs::file_type::not_found: return; + case fs::file_type::none: { + Checks::exit_with_message(VCPKG_LINE_INFO, "Error occurred when evaluating file type of file: %s", current); + } + default: { + Checks::exit_with_message(VCPKG_LINE_INFO, "Attempted to delete special file: %s", current); + } + } + } + }; - for (int i = 0; i < 5 && this->exists(path); i++) - { - using namespace std::chrono_literals; - std::this_thread::sleep_for(i * 100ms); - out += fs::stdfs::remove_all(path, ec); - } + auto const real_path = fs::stdfs::absolute(path); - if (this->exists(path)) - { - System::print2( - System::Color::warning, - "Some files in ", - path.u8string(), - " were unable to be removed. Close any editors operating in this directory and retry.\n"); + if (! real_path.has_parent_path()) { + Checks::exit_with_message(VCPKG_LINE_INFO, "Attempted to remove_all the base directory"); } - return out; + // thoughts: is this fine? or should we do something different? + // maybe a temporary directory? + auto const base_path = real_path.parent_path(); + + xoshiro256ss_engine rng{}; + recursive{base_path, ec, rng}(real_path); } virtual bool exists(const fs::path& path) const override { return fs::stdfs::exists(path); } virtual bool is_directory(const fs::path& path) const override { return fs::stdfs::is_directory(path); } diff --git a/toolsrc/src/vcpkg/base/rng.cpp b/toolsrc/src/vcpkg/base/rng.cpp new file mode 100644 index 000000000..9fe2ea3b4 --- /dev/null +++ b/toolsrc/src/vcpkg/base/rng.cpp @@ -0,0 +1,14 @@ +#include + +namespace vcpkg { + namespace { + std::random_device system_entropy{}; + } + + splitmix64_engine::splitmix64_engine() { + std::uint64_t top_half = system_entropy(); + std::uint64_t bottom_half = system_entropy(); + + state = (top_half << 32) | bottom_half; + } +} -- cgit v1.2.3 From 2d6df16849ebcf237d17c919727756d90974daba Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 10 Jul 2019 14:35:10 -0700 Subject: remove_all parallelized, and fix the issues with symlink --- toolsrc/src/vcpkg/base/files.cpp | 196 +++++++++++++++++++++++++++++++-------- toolsrc/src/vcpkg/base/rng.cpp | 4 +- 2 files changed, 157 insertions(+), 43 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index d0926bb4c..e89c531be 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #if defined(__linux__) || defined(__APPLE__) @@ -21,6 +22,45 @@ #include #endif +namespace fs { + file_status decltype(symlink_status)::operator()(const path& p, std::error_code& ec) const noexcept { +#if defined(_WIN32) + /* + do not find the permissions of the file -- it's unnecessary for the + things that vcpkg does. + if one were to add support for this in the future, one should look + into GetFileSecurityW + */ + perms permissions = perms::unknown; + + WIN32_FILE_ATTRIBUTE_DATA file_attributes; + file_type ft = file_type::unknown; + if (!GetFileAttributesExW(p.c_str(), GetFileExInfoStandard, &file_attributes)) { + ft = file_type::not_found; + } else if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + // check for reparse point -- if yes, then symlink + ft = file_type::symlink; + } else if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + ft = file_type::directory; + } else { + // otherwise, the file is a regular file + ft = file_type::regular; + } + + return file_status(ft, permissions); + +#else + return stdfs::symlink_status(p, ec); +#endif + } + + file_status decltype(symlink_status)::operator()(const path& p) const noexcept { + std::error_code ec; + auto result = symlink_status(p, ec); + if (ec) vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "error getting status of path %s: %s", p, ec.message()); + } +} + namespace vcpkg::Files { static const std::regex FILESYSTEM_INVALID_CHARACTERS_REGEX = std::regex(R"([\/:*?"<>|])"); @@ -263,55 +303,129 @@ namespace vcpkg::Files (as well as on macOS and Linux), this is just as fast and will have fewer spurious errors due to locks. */ - struct recursive { - const fs::path& tmp_directory; - std::error_code& ec; - xoshiro256ss_engine& rng; - - void operator()(const fs::path& current) const { - const auto type = fs::stdfs::symlink_status(current, ec).type(); - if (ec) return; - - const auto tmp_name = Strings::b64url_encode(rng()); - const auto tmp_path = tmp_directory / tmp_name; - - switch (type) { - case fs::file_type::directory: { - fs::stdfs::rename(current, tmp_path, ec); - if (ec) return; - for (const auto& entry : fs::stdfs::directory_iterator(tmp_path)) { - (*this)(entry); + + /* + `remove` doesn't actually remove anything -- it simply moves the + files into a parent directory (which ends up being at `path`), + and then inserts `actually_remove{current_path}` into the work + queue. + */ + struct remove { + struct tld { + const fs::path& tmp_directory; + std::uint64_t index; + + std::atomic& files_deleted; + + std::mutex& ec_mutex; + std::error_code& ec; + }; + + struct actually_remove; + using queue = WorkQueue; + + /* + if `current_path` is a directory, first `remove`s all + elements of the directory, then calls remove. + + else, just calls remove. + */ + struct actually_remove { + fs::path current_path; + + void operator()(tld& info, const queue& queue) const { + std::error_code ec; + const auto path_type = fs::symlink_status(current_path, ec).type(); + + if (check_ec(ec, info, queue)) return; + + if (path_type == fs::file_type::directory) { + for (const auto& entry : fs::stdfs::directory_iterator(current_path)) { + remove{}(entry, info, queue); + } + } + + if (fs::stdfs::remove(current_path, ec)) { + info.files_deleted.fetch_add(1, std::memory_order_relaxed); + } else { + check_ec(ec, info, queue); } - fs::stdfs::remove(tmp_path, ec); - } break; - case fs::file_type::symlink: - case fs::file_type::regular: { - fs::stdfs::rename(current, tmp_path, ec); - fs::stdfs::remove(current, ec); - } break; - case fs::file_type::not_found: return; - case fs::file_type::none: { - Checks::exit_with_message(VCPKG_LINE_INFO, "Error occurred when evaluating file type of file: %s", current); - } - default: { - Checks::exit_with_message(VCPKG_LINE_INFO, "Attempted to delete special file: %s", current); } + }; + + static bool check_ec(const std::error_code& ec, tld& info, const queue& queue) { + if (ec) { + queue.terminate(); + + auto lck = std::unique_lock(info.ec_mutex); + if (!info.ec) { + info.ec = ec; + } + + return true; + } else { + return false; } } + + void operator()(const fs::path& current_path, tld& info, const queue& queue) const { + std::error_code ec; + + const auto type = fs::symlink_status(current_path, ec).type(); + if (check_ec(ec, info, queue)) return; + + const auto tmp_name = Strings::b64url_encode(info.index++); + const auto tmp_path = info.tmp_directory / tmp_name; + + fs::stdfs::rename(current_path, tmp_path, ec); + if (check_ec(ec, info, queue)) return; + + queue.enqueue_action(actually_remove{std::move(tmp_path)}); + } }; - auto const real_path = fs::stdfs::absolute(path); + const auto path_type = fs::symlink_status(path, ec).type(); - if (! real_path.has_parent_path()) { - Checks::exit_with_message(VCPKG_LINE_INFO, "Attempted to remove_all the base directory"); + std::atomic files_deleted = 0; + + if (path_type == fs::file_type::directory) { + std::uint64_t index = 0; + std::mutex ec_mutex; + + auto queue = remove::queue([&] { + index += 1 << 32; + return remove::tld{path, index, files_deleted, ec_mutex, ec}; + }); + + index += 1 << 32; + auto main_tld = remove::tld{path, index, files_deleted, ec_mutex, ec}; + for (const auto& entry : fs::stdfs::directory_iterator(path)) { + remove{}(entry, main_tld, queue); + } + + queue.join(); } - // thoughts: is this fine? or should we do something different? - // maybe a temporary directory? - auto const base_path = real_path.parent_path(); + /* + we need to do backoff on the removal of the top level directory, + since we need to place all moved files into that top level + directory, and so we can only delete the directory after all the + lower levels have been deleted. + */ + for (int backoff = 0; backoff < 5; ++backoff) { + if (backoff) { + using namespace std::chrono_literals; + auto backoff_time = 100ms * backoff; + std::this_thread::sleep_for(backoff_time); + } + + if (fs::stdfs::remove(path, ec)) { + files_deleted.fetch_add(1, std::memory_order_relaxed); + break; + } + } - xoshiro256ss_engine rng{}; - recursive{base_path, ec, rng}(real_path); + return files_deleted; } virtual bool exists(const fs::path& path) const override { return fs::stdfs::exists(path); } virtual bool is_directory(const fs::path& path) const override { return fs::stdfs::is_directory(path); } @@ -343,11 +457,11 @@ namespace vcpkg::Files virtual fs::file_status status(const fs::path& path, std::error_code& ec) const override { - return fs::stdfs::status(path, ec); + return fs::status(path, ec); } virtual fs::file_status symlink_status(const fs::path& path, std::error_code& ec) const override { - return fs::stdfs::symlink_status(path, ec); + return fs::symlink_status(path, ec); } virtual void write_contents(const fs::path& file_path, const std::string& data, std::error_code& ec) override { diff --git a/toolsrc/src/vcpkg/base/rng.cpp b/toolsrc/src/vcpkg/base/rng.cpp index 9fe2ea3b4..40ff646b7 100644 --- a/toolsrc/src/vcpkg/base/rng.cpp +++ b/toolsrc/src/vcpkg/base/rng.cpp @@ -1,11 +1,11 @@ #include -namespace vcpkg { +namespace vcpkg::Rng { namespace { std::random_device system_entropy{}; } - splitmix64_engine::splitmix64_engine() { + splitmix::splitmix() { std::uint64_t top_half = system_entropy(); std::uint64_t bottom_half = system_entropy(); -- cgit v1.2.3 From 43493b56df7c8f7aab02256ab7f65135d4dd1d4c Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 10 Jul 2019 15:18:44 -0700 Subject: delete the random number generator --- toolsrc/src/vcpkg/base/rng.cpp | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 toolsrc/src/vcpkg/base/rng.cpp (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/rng.cpp b/toolsrc/src/vcpkg/base/rng.cpp deleted file mode 100644 index 40ff646b7..000000000 --- a/toolsrc/src/vcpkg/base/rng.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include - -namespace vcpkg::Rng { - namespace { - std::random_device system_entropy{}; - } - - splitmix::splitmix() { - std::uint64_t top_half = system_entropy(); - std::uint64_t bottom_half = system_entropy(); - - state = (top_half << 32) | bottom_half; - } -} -- cgit v1.2.3 From 3b6d6b3465e0e79999e5995f0104a6e8c021088c Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 10 Jul 2019 15:42:13 -0700 Subject: actually get the code compiling --- toolsrc/src/vcpkg/base/files.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index e89c531be..d8a982164 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -1,7 +1,6 @@ #include "pch.h" #include -#include #include #include #include @@ -57,7 +56,9 @@ namespace fs { file_status decltype(symlink_status)::operator()(const path& p) const noexcept { std::error_code ec; auto result = symlink_status(p, ec); - if (ec) vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "error getting status of path %s: %s", p, ec.message()); + if (ec) vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "error getting status of path %s: %s", p.string(), ec.message()); + + return result; } } @@ -393,11 +394,11 @@ namespace vcpkg::Files std::mutex ec_mutex; auto queue = remove::queue([&] { - index += 1 << 32; + index += static_cast(1) << 32; return remove::tld{path, index, files_deleted, ec_mutex, ec}; }); - index += 1 << 32; + index += static_cast(1) << 32; auto main_tld = remove::tld{path, index, files_deleted, ec_mutex, ec}; for (const auto& entry : fs::stdfs::directory_iterator(path)) { remove{}(entry, main_tld, queue); -- cgit v1.2.3 From 5b76f24f35976739991941d3b6289fb78fd93648 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 10 Jul 2019 16:28:56 -0700 Subject: make this compile on macos --- toolsrc/src/vcpkg/base/files.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index d8a982164..f4c2106d4 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -21,8 +21,8 @@ #include #endif -namespace fs { - file_status decltype(symlink_status)::operator()(const path& p, std::error_code& ec) const noexcept { +namespace fs::detail { + file_status symlink_status_t::operator()(const path& p, std::error_code& ec) const noexcept { #if defined(_WIN32) /* do not find the permissions of the file -- it's unnecessary for the @@ -53,7 +53,7 @@ namespace fs { #endif } - file_status decltype(symlink_status)::operator()(const path& p) const noexcept { + file_status symlink_status_t::operator()(const path& p) const noexcept { std::error_code ec; auto result = symlink_status(p, ec); if (ec) vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "error getting status of path %s: %s", p.string(), ec.message()); -- cgit v1.2.3 From bb579072077153fabfa74acec852bce222265357 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 10 Jul 2019 17:39:04 -0700 Subject: make it compile on macos under g++6 --- toolsrc/src/vcpkg/base/files.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index f4c2106d4..8bc37819a 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -129,7 +129,7 @@ namespace vcpkg::Files file_stream.read(&output[0], length); file_stream.close(); - return std::move(output); + return output; } virtual Expected> read_lines(const fs::path& file_path) const override { @@ -147,7 +147,7 @@ namespace vcpkg::Files } file_stream.close(); - return std::move(output); + return output; } virtual fs::path find_file_recursively_up(const fs::path& starting_dir, const std::string& filename) const override @@ -372,9 +372,6 @@ namespace vcpkg::Files void operator()(const fs::path& current_path, tld& info, const queue& queue) const { std::error_code ec; - const auto type = fs::symlink_status(current_path, ec).type(); - if (check_ec(ec, info, queue)) return; - const auto tmp_name = Strings::b64url_encode(info.index++); const auto tmp_path = info.tmp_directory / tmp_name; @@ -387,16 +384,16 @@ namespace vcpkg::Files const auto path_type = fs::symlink_status(path, ec).type(); - std::atomic files_deleted = 0; + std::atomic files_deleted{0}; if (path_type == fs::file_type::directory) { std::uint64_t index = 0; std::mutex ec_mutex; - auto queue = remove::queue([&] { + remove::queue queue{[&] { index += static_cast(1) << 32; return remove::tld{path, index, files_deleted, ec_mutex, ec}; - }); + }}; index += static_cast(1) << 32; auto main_tld = remove::tld{path, index, files_deleted, ec_mutex, ec}; -- cgit v1.2.3 From 510b0c5cc0233311b6993b89cd5ce488218ed78d Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 11 Jul 2019 15:01:29 -0700 Subject: fix more comments --- toolsrc/src/vcpkg/archives.cpp | 5 +- toolsrc/src/vcpkg/base/files.cpp | 133 ++++++++++++++++++++++--------- toolsrc/src/vcpkg/base/strings.cpp | 42 ++++++++++ toolsrc/src/vcpkg/build.cpp | 12 +-- toolsrc/src/vcpkg/commands.exportifw.cpp | 16 ++-- toolsrc/src/vcpkg/commands.portsdiff.cpp | 2 +- toolsrc/src/vcpkg/export.cpp | 6 +- toolsrc/src/vcpkg/install.cpp | 3 +- toolsrc/src/vcpkg/remove.cpp | 3 +- 9 files changed, 164 insertions(+), 58 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/archives.cpp b/toolsrc/src/vcpkg/archives.cpp index 69a916828..d22e841de 100644 --- a/toolsrc/src/vcpkg/archives.cpp +++ b/toolsrc/src/vcpkg/archives.cpp @@ -15,9 +15,10 @@ namespace vcpkg::Archives #endif ; + fs.remove_all(to_path, VCPKG_LINE_INFO); + fs.remove_all(to_path_partial, VCPKG_LINE_INFO); + // TODO: check this error code std::error_code ec; - fs.remove_all(to_path, ec); - fs.remove_all(to_path_partial, ec); fs.create_directories(to_path_partial, ec); const auto ext = archive.extension(); #if defined(_WIN32) diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 8bc37819a..a4e67a142 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -5,8 +5,8 @@ #include #include #include -#include #include +#include #if defined(__linux__) || defined(__APPLE__) #include @@ -21,8 +21,10 @@ #include #endif -namespace fs::detail { - file_status symlink_status_t::operator()(const path& p, std::error_code& ec) const noexcept { +namespace fs::detail +{ + file_status symlink_status_t::operator()(const path& p, std::error_code& ec) const noexcept + { #if defined(_WIN32) /* do not find the permissions of the file -- it's unnecessary for the @@ -34,14 +36,21 @@ namespace fs::detail { WIN32_FILE_ATTRIBUTE_DATA file_attributes; file_type ft = file_type::unknown; - if (!GetFileAttributesExW(p.c_str(), GetFileExInfoStandard, &file_attributes)) { + if (!GetFileAttributesExW(p.c_str(), GetFileExInfoStandard, &file_attributes)) + { ft = file_type::not_found; - } else if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + } + else if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + { // check for reparse point -- if yes, then symlink ft = file_type::symlink; - } else if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + } + else if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { ft = file_type::directory; - } else { + } + else + { // otherwise, the file is a regular file ft = file_type::regular; } @@ -53,12 +62,13 @@ namespace fs::detail { #endif } - file_status symlink_status_t::operator()(const path& p) const noexcept { + file_status symlink_status_t::operator()(const path& p, vcpkg::LineInfo li) const noexcept + { std::error_code ec; auto result = symlink_status(p, ec); - if (ec) vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "error getting status of path %s: %s", p.string(), ec.message()); + if (ec) vcpkg::Checks::exit_with_message(li, "error getting status of path %s: %s", p.string(), ec.message()); - return result; + return result; } } @@ -105,6 +115,25 @@ namespace vcpkg::Files if (ec) Checks::exit_with_message(linfo, "error writing lines: %s: %s", path.u8string(), ec.message()); } + std::uintmax_t Filesystem::remove_all(const fs::path& path, LineInfo li) + { + std::error_code ec; + fs::path failure_point; + + const auto result = this->remove_all(path, ec, failure_point); + + if (ec) + { + Checks::exit_with_message(li, + "Failure to remove_all(%s) due to file %s: %s", + path.string(), + failure_point.string(), + ec.message()); + } + + return result; + } + struct RealFilesystem final : Filesystem { virtual Expected read_contents(const fs::path& file_path) const override @@ -296,7 +325,7 @@ namespace vcpkg::Files #endif } virtual bool remove(const fs::path& path, std::error_code& ec) override { return fs::stdfs::remove(path, ec); } - virtual std::uintmax_t remove_all(const fs::path& path, std::error_code& ec) override + virtual std::uintmax_t remove_all(const fs::path& path, std::error_code& ec, fs::path& failure_point) override { /* does not use the std::filesystem call since it is buggy, and can @@ -311,8 +340,10 @@ namespace vcpkg::Files and then inserts `actually_remove{current_path}` into the work queue. */ - struct remove { - struct tld { + struct remove + { + struct tld + { const fs::path& tmp_directory; std::uint64_t index; @@ -320,6 +351,7 @@ namespace vcpkg::Files std::mutex& ec_mutex; std::error_code& ec; + fs::path& failure_point; }; struct actually_remove; @@ -331,52 +363,68 @@ namespace vcpkg::Files else, just calls remove. */ - struct actually_remove { + struct actually_remove + { fs::path current_path; - void operator()(tld& info, const queue& queue) const { + void operator()(tld& info, const queue& queue) const + { std::error_code ec; const auto path_type = fs::symlink_status(current_path, ec).type(); - if (check_ec(ec, info, queue)) return; + if (check_ec(ec, info, queue, current_path)) return; - if (path_type == fs::file_type::directory) { - for (const auto& entry : fs::stdfs::directory_iterator(current_path)) { + if (path_type == fs::file_type::directory) + { + for (const auto& entry : fs::stdfs::directory_iterator(current_path)) + { remove{}(entry, info, queue); } } - if (fs::stdfs::remove(current_path, ec)) { + if (fs::stdfs::remove(current_path, ec)) + { info.files_deleted.fetch_add(1, std::memory_order_relaxed); - } else { - check_ec(ec, info, queue); + } + else + { + check_ec(ec, info, queue, current_path); } } }; - static bool check_ec(const std::error_code& ec, tld& info, const queue& queue) { - if (ec) { + static bool check_ec(const std::error_code& ec, + tld& info, + const queue& queue, + const fs::path& failure_point) + { + if (ec) + { queue.terminate(); auto lck = std::unique_lock(info.ec_mutex); - if (!info.ec) { + if (!info.ec) + { info.ec = ec; } return true; - } else { + } + else + { return false; } } - void operator()(const fs::path& current_path, tld& info, const queue& queue) const { + void operator()(const fs::path& current_path, tld& info, const queue& queue) const + { std::error_code ec; const auto tmp_name = Strings::b64url_encode(info.index++); const auto tmp_path = info.tmp_directory / tmp_name; fs::stdfs::rename(current_path, tmp_path, ec); - if (check_ec(ec, info, queue)) return; + if (check_ec(ec, info, queue, current_path)) return; queue.enqueue_action(actually_remove{std::move(tmp_path)}); } @@ -386,22 +434,28 @@ namespace vcpkg::Files std::atomic files_deleted{0}; - if (path_type == fs::file_type::directory) { + if (path_type == fs::file_type::directory) + { std::uint64_t index = 0; std::mutex ec_mutex; - remove::queue queue{[&] { + auto const tld_gen = [&] { index += static_cast(1) << 32; - return remove::tld{path, index, files_deleted, ec_mutex, ec}; - }}; + return remove::tld{path, index, files_deleted, ec_mutex, ec, failure_point}; + }; - index += static_cast(1) << 32; - auto main_tld = remove::tld{path, index, files_deleted, ec_mutex, ec}; - for (const auto& entry : fs::stdfs::directory_iterator(path)) { + remove::queue queue{4, VCPKG_LINE_INFO, tld_gen}; + + // note: we don't actually start the queue running until the + // `join()`. This allows us to rename all the top-level files in + // peace, so that we don't get collisions. + auto main_tld = tld_gen(); + for (const auto& entry : fs::stdfs::directory_iterator(path)) + { remove{}(entry, main_tld, queue); } - queue.join(); + queue.join(VCPKG_LINE_INFO); } /* @@ -410,14 +464,17 @@ namespace vcpkg::Files directory, and so we can only delete the directory after all the lower levels have been deleted. */ - for (int backoff = 0; backoff < 5; ++backoff) { - if (backoff) { + for (int backoff = 0; backoff < 5; ++backoff) + { + if (backoff) + { using namespace std::chrono_literals; auto backoff_time = 100ms * backoff; std::this_thread::sleep_for(backoff_time); } - if (fs::stdfs::remove(path, ec)) { + if (fs::stdfs::remove(path, ec)) + { files_deleted.fetch_add(1, std::memory_order_relaxed); break; } diff --git a/toolsrc/src/vcpkg/base/strings.cpp b/toolsrc/src/vcpkg/base/strings.cpp index 54a74a7a1..16543046e 100644 --- a/toolsrc/src/vcpkg/base/strings.cpp +++ b/toolsrc/src/vcpkg/base/strings.cpp @@ -288,3 +288,45 @@ bool Strings::contains(StringView haystack, StringView needle) { return Strings::search(haystack, needle) != haystack.end(); } + +namespace vcpkg::Strings::detail { + + template + std::string b64url_encode_implementation(Integral x) { + static_assert(std::is_integral::value, "b64url_encode must take an integer type"); + using Unsigned = std::make_unsigned_t; + auto value = static_cast(x); + + // 64 values, plus the implicit \0 + constexpr static char map[0x41] = + /* 0123456789ABCDEF */ + /*0*/ "ABCDEFGHIJKLMNOP" + /*1*/ "QRSTUVWXYZabcdef" + /*2*/ "ghijklmnopqrstuv" + /*3*/ "wxyz0123456789-_" + ; + + constexpr static int shift = 5; + constexpr static auto mask = (static_cast(1) << shift) - 1; + + std::string result; + // reserve ceiling(number of bits / 3) + result.resize((sizeof(value) * 8 + 2) / 3, map[0]); + + for (char& c: result) { + if (value == 0) { + break; + } + c = map[value & mask]; + value >>= shift; + } + + return result; + } + + std::string b64url_encode_t::operator()(std::uint64_t x) const noexcept{ + return b64url_encode_implementation(x); + } + +} + diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 68df1f965..c50acce7e 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -363,7 +363,8 @@ namespace vcpkg::Build const Triplet& triplet = spec.triplet(); const auto& triplet_file_path = paths.get_triplet_file_path(spec.triplet()).u8string(); - if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.triplets.u8string())) + if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, + paths.triplets.u8string())) { System::printf("-- Loading triplet configuration from: %s\n", triplet_file_path); } @@ -495,7 +496,8 @@ namespace vcpkg::Build if (fs.is_directory(file)) // Will only keep the logs { std::error_code ec; - fs.remove_all(file, ec); + fs::path failure_point; + fs.remove_all(file, ec, failure_point); } } } @@ -610,8 +612,8 @@ namespace vcpkg::Build auto& fs = paths.get_filesystem(); auto pkg_path = paths.package_dir(spec); + fs.remove_all(pkg_path, VCPKG_LINE_INFO); std::error_code ec; - fs.remove_all(pkg_path, ec); fs.create_directories(pkg_path, ec); auto files = fs.get_files_non_recursive(pkg_path); Checks::check_exit(VCPKG_LINE_INFO, files.empty(), "unable to clear path: %s", pkg_path.u8string()); @@ -794,7 +796,7 @@ namespace vcpkg::Build fs.rename_or_copy(tmp_failure_zip, archive_tombstone_path, ".tmp", ec); // clean up temporary directory - fs.remove_all(tmp_log_path, ec); + fs.remove_all(tmp_log_path, VCPKG_LINE_INFO); } } @@ -1018,7 +1020,7 @@ namespace vcpkg::Build hash += "-"; hash += Hash::get_file_hash(fs, *p, "SHA1"); } - else if (pre_build_info.cmake_system_name.empty() || + else if (pre_build_info.cmake_system_name.empty() || pre_build_info.cmake_system_name == "WindowsStore") { hash += "-"; diff --git a/toolsrc/src/vcpkg/commands.exportifw.cpp b/toolsrc/src/vcpkg/commands.exportifw.cpp index f0946110c..3d963a297 100644 --- a/toolsrc/src/vcpkg/commands.exportifw.cpp +++ b/toolsrc/src/vcpkg/commands.exportifw.cpp @@ -352,13 +352,15 @@ namespace vcpkg::Export::IFW System::print2("Generating repository ", repository_dir.generic_u8string(), "...\n"); std::error_code ec; + fs::path failure_point; Files::Filesystem& fs = paths.get_filesystem(); - fs.remove_all(repository_dir, ec); + fs.remove_all(repository_dir, ec, failure_point); Checks::check_exit(VCPKG_LINE_INFO, !ec, - "Could not remove outdated repository directory %s", - repository_dir.generic_u8string()); + "Could not remove outdated repository directory %s due to file %s", + repository_dir.generic_u8string(), + failure_point.string()); const auto cmd_line = Strings::format(R"("%s" --packages "%s" "%s" > nul)", repogen_exe.u8string(), @@ -414,16 +416,18 @@ namespace vcpkg::Export::IFW const VcpkgPaths& paths) { std::error_code ec; + fs::path failure_point; Files::Filesystem& fs = paths.get_filesystem(); // Prepare packages directory const fs::path ifw_packages_dir_path = get_packages_dir_path(export_id, ifw_options, paths); - fs.remove_all(ifw_packages_dir_path, ec); + fs.remove_all(ifw_packages_dir_path, ec, failure_point); Checks::check_exit(VCPKG_LINE_INFO, !ec, - "Could not remove outdated packages directory %s", - ifw_packages_dir_path.generic_u8string()); + "Could not remove outdated packages directory %s due to file %s", + ifw_packages_dir_path.generic_u8string(), + failure_point.string()); fs.create_directory(ifw_packages_dir_path, ec); Checks::check_exit( diff --git a/toolsrc/src/vcpkg/commands.portsdiff.cpp b/toolsrc/src/vcpkg/commands.portsdiff.cpp index b30c38f43..cddc274b8 100644 --- a/toolsrc/src/vcpkg/commands.portsdiff.cpp +++ b/toolsrc/src/vcpkg/commands.portsdiff.cpp @@ -105,7 +105,7 @@ namespace vcpkg::Commands::PortsDiff std::map names_and_versions; for (auto&& port : all_ports) names_and_versions.emplace(port->core_paragraph->name, port->core_paragraph->version); - fs.remove_all(temp_checkout_path, ec); + fs.remove_all(temp_checkout_path, VCPKG_LINE_INFO); return names_and_versions; } diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp index 88c1526c5..f306bf4e6 100644 --- a/toolsrc/src/vcpkg/export.cpp +++ b/toolsrc/src/vcpkg/export.cpp @@ -400,8 +400,10 @@ namespace vcpkg::Export Files::Filesystem& fs = paths.get_filesystem(); const fs::path export_to_path = paths.root; const fs::path raw_exported_dir_path = export_to_path / export_id; + fs.remove_all(raw_exported_dir_path, VCPKG_LINE_INFO); + + // TODO: error handling std::error_code ec; - fs.remove_all(raw_exported_dir_path, ec); fs.create_directory(raw_exported_dir_path, ec); // execute the plan @@ -476,7 +478,7 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console if (!opts.raw) { - fs.remove_all(raw_exported_dir_path, ec); + fs.remove_all(raw_exported_dir_path, VCPKG_LINE_INFO); } } diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index de19c360a..981a9233f 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -355,8 +355,7 @@ namespace vcpkg::Install { auto& fs = paths.get_filesystem(); const fs::path package_dir = paths.package_dir(action.spec); - std::error_code ec; - fs.remove_all(package_dir, ec); + fs.remove_all(package_dir, VCPKG_LINE_INFO); } if (action.build_options.clean_downloads == Build::CleanDownloads::YES) diff --git a/toolsrc/src/vcpkg/remove.cpp b/toolsrc/src/vcpkg/remove.cpp index a40b27bd7..84ec6c981 100644 --- a/toolsrc/src/vcpkg/remove.cpp +++ b/toolsrc/src/vcpkg/remove.cpp @@ -179,8 +179,7 @@ namespace vcpkg::Remove { System::printf("Purging package %s...\n", display_name); Files::Filesystem& fs = paths.get_filesystem(); - std::error_code ec; - fs.remove_all(paths.packages / action.spec.dir(), ec); + fs.remove_all(paths.packages / action.spec.dir(), VCPKG_LINE_INFO); System::printf(System::Color::success, "Purging package %s... done\n", display_name); } } -- cgit v1.2.3 From a0fe40ea5842006c0da901a99ae07d7a25531175 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 11 Jul 2019 18:16:10 -0700 Subject: add tests! Also, fix all the bugs I found when I wrote the tests! --- toolsrc/src/tests.files.cpp | 80 ++++++++++++++++++++++++++++++++++++++ toolsrc/src/tests.strings.cpp | 38 ++++++++++++++++++ toolsrc/src/vcpkg/base/files.cpp | 3 +- toolsrc/src/vcpkg/base/strings.cpp | 72 +++++++++++++++++----------------- 4 files changed, 157 insertions(+), 36 deletions(-) create mode 100644 toolsrc/src/tests.files.cpp create mode 100644 toolsrc/src/tests.strings.cpp (limited to 'toolsrc/src') diff --git a/toolsrc/src/tests.files.cpp b/toolsrc/src/tests.files.cpp new file mode 100644 index 000000000..73c7eb5bc --- /dev/null +++ b/toolsrc/src/tests.files.cpp @@ -0,0 +1,80 @@ +#include "tests.pch.h" + +#include +#include + +#include +#include + +#include + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace UnitTest1 { + class FilesTest : public TestClass { + using uid = std::uniform_int_distribution; + + std::string get_random_filename() + { + std::random_device rd; + return vcpkg::Strings::b64url_encode(uid{}(rd)); + } + + void create_directory_tree( + vcpkg::Files::Filesystem& fs, + std::uint64_t depth, + const fs::path& base) + { + std::random_device rd; + constexpr auto max_depth = std::uint64_t(3); + const auto width = depth ? uid{0, (max_depth - depth) * 3 / 2}(rd) : 5; + + std::error_code ec; + if (width == 0) { + fs.write_contents(base, "", ec); + Assert::IsFalse(bool(ec)); + + return; + } + + fs.create_directory(base, ec); + Assert::IsFalse(bool(ec)); + + for (int i = 0; i < width; ++i) { + create_directory_tree(fs, depth + 1, base / get_random_filename()); + } + } + + TEST_METHOD(remove_all) { + fs::path temp_dir; + + { + wchar_t* tmp = static_cast(calloc(32'767, 2)); + + if (!GetEnvironmentVariableW(L"TEMP", tmp, 32'767)) { + Assert::Fail(L"GetEnvironmentVariable(\"TEMP\") failed"); + } + + temp_dir = tmp; + + std::string dir_name = "vcpkg-tmp-dir-"; + dir_name += get_random_filename(); + + temp_dir /= dir_name; + } + + auto& fs = vcpkg::Files::get_real_filesystem(); + + std::cout << "temp dir is: " << temp_dir << '\n'; + + std::error_code ec; + create_directory_tree(fs, 0, temp_dir); + + fs::path fp; + fs.remove_all(temp_dir, ec, fp); + Assert::IsFalse(bool(ec)); + + Assert::IsFalse(fs.exists(temp_dir)); + } + }; +} diff --git a/toolsrc/src/tests.strings.cpp b/toolsrc/src/tests.strings.cpp new file mode 100644 index 000000000..14b449e86 --- /dev/null +++ b/toolsrc/src/tests.strings.cpp @@ -0,0 +1,38 @@ +#include "tests.pch.h" + +#include + +#include +#include +#include + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace UnitTest1 { + class StringsTest : public TestClass { + TEST_METHOD(b64url_encode) + { + using u64 = std::uint64_t; + + std::vector> map; + + map.emplace_back(0, "AAAAAAAAAAA"); + map.emplace_back(1, "BAAAAAAAAAA"); + + map.emplace_back(u64(1) << 32, "AAAAAEAAAAA"); + map.emplace_back((u64(1) << 32) + 1, "BAAAAEAAAAA"); + + map.emplace_back(0xE4D0'1065'D11E'0229, "pIgHRXGEQTO"); + map.emplace_back(0xA626'FE45'B135'07FF, "_fQNxWk_mYK"); + map.emplace_back(0xEE36'D228'0C31'D405, "FQdMMgi024O"); + map.emplace_back(0x1405'64E7'FE7E'A88C, "Miqf-fOZFQB"); + map.emplace_back(0xFFFF'FFFF'FFFF'FFFF, "__________P"); + + std::string result; + for (const auto& pr : map) { + result = vcpkg::Strings::b64url_encode(pr.first); + Assert::AreEqual(result, pr.second); + } + } + }; +} diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index a4e67a142..4e36fe990 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -23,7 +23,7 @@ namespace fs::detail { - file_status symlink_status_t::operator()(const path& p, std::error_code& ec) const noexcept + file_status symlink_status_t::operator()(const path& p, std::error_code&) const noexcept { #if defined(_WIN32) /* @@ -406,6 +406,7 @@ namespace vcpkg::Files if (!info.ec) { info.ec = ec; + info.failure_point = failure_point; } return true; diff --git a/toolsrc/src/vcpkg/base/strings.cpp b/toolsrc/src/vcpkg/base/strings.cpp index 16543046e..ade4384a9 100644 --- a/toolsrc/src/vcpkg/base/strings.cpp +++ b/toolsrc/src/vcpkg/base/strings.cpp @@ -289,44 +289,46 @@ bool Strings::contains(StringView haystack, StringView needle) return Strings::search(haystack, needle) != haystack.end(); } -namespace vcpkg::Strings::detail { - - template - std::string b64url_encode_implementation(Integral x) { - static_assert(std::is_integral::value, "b64url_encode must take an integer type"); - using Unsigned = std::make_unsigned_t; - auto value = static_cast(x); - - // 64 values, plus the implicit \0 - constexpr static char map[0x41] = - /* 0123456789ABCDEF */ - /*0*/ "ABCDEFGHIJKLMNOP" - /*1*/ "QRSTUVWXYZabcdef" - /*2*/ "ghijklmnopqrstuv" - /*3*/ "wxyz0123456789-_" - ; - - constexpr static int shift = 5; - constexpr static auto mask = (static_cast(1) << shift) - 1; - - std::string result; - // reserve ceiling(number of bits / 3) - result.resize((sizeof(value) * 8 + 2) / 3, map[0]); - - for (char& c: result) { - if (value == 0) { - break; +namespace vcpkg::Strings +{ + namespace + { + template + std::string b64url_encode_implementation(Integral x) + { + static_assert(std::is_integral::value, "b64url_encode must take an integer type"); + using Unsigned = std::make_unsigned_t; + auto value = static_cast(x); + + // 64 values, plus the implicit \0 + constexpr static char map[65] = + /* 0123456789ABCDEF */ + /*0*/ "ABCDEFGHIJKLMNOP" + /*1*/ "QRSTUVWXYZabcdef" + /*2*/ "ghijklmnopqrstuv" + /*3*/ "wxyz0123456789-_"; + + // log2(64) + constexpr static int shift = 6; + // 64 - 1 + constexpr static auto mask = 63; + + // ceiling(bitsize(Integral) / log2(64)) + constexpr static auto result_size = (sizeof(value) * 8 + shift - 1) / shift; + + std::string result; + result.reserve(result_size); + + for (std::size_t i = 0; i < result_size; ++i) + { + result.push_back(map[value & mask]); + value >>= shift; } - c = map[value & mask]; - value >>= shift; - } - return result; + return result; + } } - std::string b64url_encode_t::operator()(std::uint64_t x) const noexcept{ - return b64url_encode_implementation(x); - } + std::string b64url_encode(std::uint64_t x) noexcept { return b64url_encode_implementation(x); } } - -- cgit v1.2.3 From 771e23c665f1960ef4e7fd9816e0d21c943a7903 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 11 Jul 2019 18:26:42 -0700 Subject: forgot to test on macos >.< --- toolsrc/src/vcpkg/base/files.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 4e36fe990..e40822705 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -23,9 +23,11 @@ namespace fs::detail { - file_status symlink_status_t::operator()(const path& p, std::error_code&) const noexcept + file_status symlink_status_t::operator()(const path& p, std::error_code& ec) const noexcept { #if defined(_WIN32) + static_cast(ec); + /* do not find the permissions of the file -- it's unnecessary for the things that vcpkg does. -- cgit v1.2.3 From 02c977186e890e4090d91c171b42d20729e668af Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 15 Jul 2019 16:43:55 -0700 Subject: modify files test to include symlinks --- toolsrc/src/tests.files.cpp | 121 +++++++++++++++++++++++++++++++------------- 1 file changed, 87 insertions(+), 34 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/tests.files.cpp b/toolsrc/src/tests.files.cpp index 73c7eb5bc..c99dbb286 100644 --- a/toolsrc/src/tests.files.cpp +++ b/toolsrc/src/tests.files.cpp @@ -10,65 +10,60 @@ using namespace Microsoft::VisualStudio::CppUnitTestFramework; -namespace UnitTest1 { - class FilesTest : public TestClass { +namespace UnitTest1 +{ + class FilesTest : public TestClass + { using uid = std::uniform_int_distribution; - - std::string get_random_filename() - { - std::random_device rd; - return vcpkg::Strings::b64url_encode(uid{}(rd)); - } - - void create_directory_tree( - vcpkg::Files::Filesystem& fs, - std::uint64_t depth, - const fs::path& base) - { - std::random_device rd; - constexpr auto max_depth = std::uint64_t(3); - const auto width = depth ? uid{0, (max_depth - depth) * 3 / 2}(rd) : 5; - std::error_code ec; - if (width == 0) { - fs.write_contents(base, "", ec); - Assert::IsFalse(bool(ec)); + public: + FilesTest() + { + HKEY key; + const auto status = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock)", 0, KEY_READ, &key); - return; + if (!status) + { + ALLOW_SYMLINKS = false; + std::clog << "Symlinks are not allowed on this system\n"; } - - fs.create_directory(base, ec); - Assert::IsFalse(bool(ec)); - - for (int i = 0; i < width; ++i) { - create_directory_tree(fs, depth + 1, base / get_random_filename()); + else + { + ALLOW_SYMLINKS = true; + RegCloseKey(key); } } - - TEST_METHOD(remove_all) { + + private: + TEST_METHOD(remove_all) + { + auto urbg = get_urbg(0); + fs::path temp_dir; { wchar_t* tmp = static_cast(calloc(32'767, 2)); - if (!GetEnvironmentVariableW(L"TEMP", tmp, 32'767)) { + if (!GetEnvironmentVariableW(L"TEMP", tmp, 32'767)) + { Assert::Fail(L"GetEnvironmentVariable(\"TEMP\") failed"); } temp_dir = tmp; std::string dir_name = "vcpkg-tmp-dir-"; - dir_name += get_random_filename(); + dir_name += get_random_filename(urbg); temp_dir /= dir_name; } auto& fs = vcpkg::Files::get_real_filesystem(); - std::cout << "temp dir is: " << temp_dir << '\n'; + std::clog << "temp dir is: " << temp_dir << '\n'; std::error_code ec; - create_directory_tree(fs, 0, temp_dir); + create_directory_tree(urbg, fs, 0, temp_dir); fs::path fp; fs.remove_all(temp_dir, ec, fp); @@ -76,5 +71,63 @@ namespace UnitTest1 { Assert::IsFalse(fs.exists(temp_dir)); } + + bool ALLOW_SYMLINKS; + + std::mt19937_64 get_urbg(std::uint64_t index) + { + // smallest prime > 2**63 - 1 + return std::mt19937_64{index + 9223372036854775837}; + } + + std::string get_random_filename(std::mt19937_64& urbg) { return vcpkg::Strings::b64url_encode(uid{}(urbg)); } + + void create_directory_tree(std::mt19937_64& urbg, + vcpkg::Files::Filesystem& fs, + std::uint64_t depth, + const fs::path& base) + { + std::random_device rd; + constexpr auto max_depth = std::uint64_t(3); + const auto width = depth ? uid{0, (max_depth - depth) * 3 / 2}(urbg) : 5; + + std::error_code ec; + if (width == 0) + { + // I don't want to move urbg forward conditionally + const auto type = uid{0, 3}(urbg); + if (type == 0 || !ALLOW_SYMLINKS) + { + // 0 is a regular file + fs.write_contents(base, "", ec); + } + else if (type == 1) + { + // 1 is a regular symlink + fs.write_contents(base, "", ec); + Assert::IsFalse(bool(ec)); + fs::path base_link = base; + base_link.append("-link"); + fs::stdfs::create_symlink(base, base_link, ec); + } + else + { + // 2 is a directory symlink + fs::stdfs::create_directory_symlink(".", base, ec); + } + + Assert::IsFalse(bool(ec)); + + return; + } + + fs.create_directory(base, ec); + Assert::IsFalse(bool(ec)); + + for (int i = 0; i < width; ++i) + { + create_directory_tree(urbg, fs, depth + 1, base / get_random_filename(urbg)); + } + } }; } -- cgit v1.2.3 From 65d34c5e55ef30a6572dfb3b79d212196fbadc0d Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 15 Jul 2019 18:51:03 -0700 Subject: wheeeee more fixes --- toolsrc/src/tests.files.cpp | 64 +++++++++++++++++++++++--------------- toolsrc/src/tests.strings.cpp | 20 ++++++------ toolsrc/src/vcpkg/base/files.cpp | 2 +- toolsrc/src/vcpkg/base/strings.cpp | 23 ++++++-------- 4 files changed, 59 insertions(+), 50 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/tests.files.cpp b/toolsrc/src/tests.files.cpp index c99dbb286..56b0ceac6 100644 --- a/toolsrc/src/tests.files.cpp +++ b/toolsrc/src/tests.files.cpp @@ -4,6 +4,7 @@ #include #include +#include // required for filesystem::create_{directory_}symlink #include #include @@ -21,18 +22,20 @@ namespace UnitTest1 { HKEY key; const auto status = RegOpenKeyExW( - HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock)", 0, KEY_READ, &key); + HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock)", 0, 0, &key); - if (!status) + if (status == ERROR_FILE_NOT_FOUND) { ALLOW_SYMLINKS = false; std::clog << "Symlinks are not allowed on this system\n"; } else { + // if we get a permissions error, we still know that we're in developer mode ALLOW_SYMLINKS = true; - RegCloseKey(key); } + + if (status == ERROR_SUCCESS) RegCloseKey(key); } private: @@ -62,9 +65,9 @@ namespace UnitTest1 std::clog << "temp dir is: " << temp_dir << '\n'; - std::error_code ec; create_directory_tree(urbg, fs, 0, temp_dir); + std::error_code ec; fs::path fp; fs.remove_all(temp_dir, ec, fp); Assert::IsFalse(bool(ec)); @@ -80,7 +83,7 @@ namespace UnitTest1 return std::mt19937_64{index + 9223372036854775837}; } - std::string get_random_filename(std::mt19937_64& urbg) { return vcpkg::Strings::b64url_encode(uid{}(urbg)); } + std::string get_random_filename(std::mt19937_64& urbg) { return vcpkg::Strings::b32_encode(uid{}(urbg)); } void create_directory_tree(std::mt19937_64& urbg, vcpkg::Files::Filesystem& fs, @@ -88,46 +91,57 @@ namespace UnitTest1 const fs::path& base) { std::random_device rd; - constexpr auto max_depth = std::uint64_t(3); - const auto width = depth ? uid{0, (max_depth - depth) * 3 / 2}(urbg) : 5; + constexpr std::uint64_t max_depth = 5; + constexpr std::uint64_t width = 5; + const auto type = depth < max_depth ? uid{0, 9}(urbg) : uid{7, 9}(urbg); + + // 0 <= type < 7 : directory + // 7 = type : regular + // 8 = type : regular symlink (regular file if !ALLOW_SYMLINKS) + // 9 = type : directory symlink (^^) std::error_code ec; - if (width == 0) + if (type >= 7) { // I don't want to move urbg forward conditionally - const auto type = uid{0, 3}(urbg); - if (type == 0 || !ALLOW_SYMLINKS) + if (type == 7 || !ALLOW_SYMLINKS) { - // 0 is a regular file + // regular file fs.write_contents(base, "", ec); } - else if (type == 1) + else if (type == 8) { - // 1 is a regular symlink + // regular symlink fs.write_contents(base, "", ec); Assert::IsFalse(bool(ec)); - fs::path base_link = base; - base_link.append("-link"); - fs::stdfs::create_symlink(base, base_link, ec); + const std::filesystem::path basep = base.native(); + auto basep_link = basep; + basep_link.replace_filename(basep.filename().native() + L"-link"); + std::filesystem::create_symlink(basep, basep_link, ec); } else { - // 2 is a directory symlink - fs::stdfs::create_directory_symlink(".", base, ec); + // directory symlink + std::filesystem::path basep = base.native(); + std::filesystem::create_directory_symlink(basep / "..", basep, ec); } Assert::IsFalse(bool(ec)); - return; } - - fs.create_directory(base, ec); - Assert::IsFalse(bool(ec)); - - for (int i = 0; i < width; ++i) + else { - create_directory_tree(urbg, fs, depth + 1, base / get_random_filename(urbg)); + // directory + fs.create_directory(base, ec); + Assert::IsFalse(bool(ec)); + + for (int i = 0; i < width; ++i) + { + create_directory_tree(urbg, fs, depth + 1, base / get_random_filename(urbg)); + } + } + } }; } diff --git a/toolsrc/src/tests.strings.cpp b/toolsrc/src/tests.strings.cpp index 14b449e86..6301ea05d 100644 --- a/toolsrc/src/tests.strings.cpp +++ b/toolsrc/src/tests.strings.cpp @@ -16,21 +16,21 @@ namespace UnitTest1 { std::vector> map; - map.emplace_back(0, "AAAAAAAAAAA"); - map.emplace_back(1, "BAAAAAAAAAA"); + map.emplace_back(0, "AAAAAAAAAAAAA"); + map.emplace_back(1, "BAAAAAAAAAAAA"); - map.emplace_back(u64(1) << 32, "AAAAAEAAAAA"); - map.emplace_back((u64(1) << 32) + 1, "BAAAAEAAAAA"); + map.emplace_back(u64(1) << 32, "AAAAAAEAAAAAA"); + map.emplace_back((u64(1) << 32) + 1, "BAAAAAEAAAAAA"); - map.emplace_back(0xE4D0'1065'D11E'0229, "pIgHRXGEQTO"); - map.emplace_back(0xA626'FE45'B135'07FF, "_fQNxWk_mYK"); - map.emplace_back(0xEE36'D228'0C31'D405, "FQdMMgi024O"); - map.emplace_back(0x1405'64E7'FE7E'A88C, "Miqf-fOZFQB"); - map.emplace_back(0xFFFF'FFFF'FFFF'FFFF, "__________P"); + map.emplace_back(0xE4D0'1065'D11E'0229, "JRA4RIXMQAUJO"); + map.emplace_back(0xA626'FE45'B135'07FF, "77BKTYWI6XJMK"); + map.emplace_back(0xEE36'D228'0C31'D405, "FAVDDGAFSWN4O"); + map.emplace_back(0x1405'64E7'FE7E'A88C, "MEK5H774ELBIB"); + map.emplace_back(0xFFFF'FFFF'FFFF'FFFF, "777777777777P"); std::string result; for (const auto& pr : map) { - result = vcpkg::Strings::b64url_encode(pr.first); + result = vcpkg::Strings::b32_encode(pr.first); Assert::AreEqual(result, pr.second); } } diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index e40822705..6c6945e44 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -423,7 +423,7 @@ namespace vcpkg::Files { std::error_code ec; - const auto tmp_name = Strings::b64url_encode(info.index++); + const auto tmp_name = Strings::b32_encode(info.index++); const auto tmp_path = info.tmp_directory / tmp_name; fs::stdfs::rename(current_path, tmp_path, ec); diff --git a/toolsrc/src/vcpkg/base/strings.cpp b/toolsrc/src/vcpkg/base/strings.cpp index ade4384a9..7970e1b46 100644 --- a/toolsrc/src/vcpkg/base/strings.cpp +++ b/toolsrc/src/vcpkg/base/strings.cpp @@ -294,26 +294,21 @@ namespace vcpkg::Strings namespace { template - std::string b64url_encode_implementation(Integral x) + std::string b32_encode_implementation(Integral x) { static_assert(std::is_integral::value, "b64url_encode must take an integer type"); using Unsigned = std::make_unsigned_t; auto value = static_cast(x); - // 64 values, plus the implicit \0 - constexpr static char map[65] = - /* 0123456789ABCDEF */ - /*0*/ "ABCDEFGHIJKLMNOP" - /*1*/ "QRSTUVWXYZabcdef" - /*2*/ "ghijklmnopqrstuv" - /*3*/ "wxyz0123456789-_"; + // 32 values, plus the implicit \0 + constexpr static char map[33] = "ABCDEFGHIJKLMNOP" "QRSTUVWXYZ234567"; - // log2(64) - constexpr static int shift = 6; - // 64 - 1 - constexpr static auto mask = 63; + // log2(32) + constexpr static int shift = 5; + // 32 - 1 + constexpr static auto mask = 31; - // ceiling(bitsize(Integral) / log2(64)) + // ceiling(bitsize(Integral) / log2(32)) constexpr static auto result_size = (sizeof(value) * 8 + shift - 1) / shift; std::string result; @@ -329,6 +324,6 @@ namespace vcpkg::Strings } } - std::string b64url_encode(std::uint64_t x) noexcept { return b64url_encode_implementation(x); } + std::string b32_encode(std::uint64_t x) noexcept { return b32_encode_implementation(x); } } -- cgit v1.2.3 From 684989a1e48b6b7f0ac1c340a702236974762f05 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 16 Jul 2019 14:02:13 -0700 Subject: use additional env param --- toolsrc/src/vcpkg/build.cpp | 398 ++++++++++++++++++++-------------- toolsrc/src/vcpkg/sourceparagraph.cpp | 22 ++ 2 files changed, 255 insertions(+), 165 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 68df1f965..e0c78f2da 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -32,24 +32,14 @@ namespace vcpkg::Build::Command using Dependencies::InstallPlanAction; using Dependencies::InstallPlanType; - static constexpr StringLiteral OPTION_CHECKS_ONLY = "--checks-only"; - void perform_and_exit_ex(const FullPackageSpec& full_spec, const SourceControlFileLocation& scfl, const ParsedArguments& options, const VcpkgPaths& paths) { + const StatusParagraphs status_db = database_load_check(paths); const PackageSpec& spec = full_spec.package_spec; - const auto& scf = *scfl.source_control_file; - if (Util::Sets::contains(options.switches, OPTION_CHECKS_ONLY)) - { - const auto pre_build_info = Build::PreBuildInfo::from_triplet_file(paths, spec.triplet()); - const auto build_info = Build::read_build_info(paths.get_filesystem(), paths.build_info_file_path(spec)); - const size_t error_count = - PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info, scfl.source_location); - Checks::check_exit(VCPKG_LINE_INFO, error_count == 0); - Checks::exit_success(VCPKG_LINE_INFO); - } + const SourceControlFile& scf = *scfl.source_control_file; Checks::check_exit(VCPKG_LINE_INFO, spec.name() == scf.core_paragraph->name, @@ -57,7 +47,6 @@ namespace vcpkg::Build::Command scf.core_paragraph->name, spec.name()); - const StatusParagraphs status_db = database_load_check(paths); const Build::BuildPackageOptions build_package_options{ Build::UseHeadVersion::NO, Build::AllowDownloads::YES, @@ -104,15 +93,11 @@ namespace vcpkg::Build::Command Checks::exit_success(VCPKG_LINE_INFO); } - static constexpr std::array BUILD_SWITCHES = {{ - {OPTION_CHECKS_ONLY, "Only run checks, do not rebuild package"}, - }}; - const CommandStructure COMMAND_STRUCTURE = { Help::create_example_string("build zlib:x64-windows"), 1, 1, - {BUILD_SWITCHES, {}}, + {{}, {}}, nullptr, }; @@ -230,6 +215,23 @@ namespace vcpkg::Build })); } + std::unordered_map make_env_passthrough(const PreBuildInfo& pre_build_info) + { + std::unordered_map env; + + for (auto&& env_var : pre_build_info.passthrough_env_vars) + { + auto env_val = System::get_environment_variable(env_var); + + if (env_val) + { + env[env_var] = env_val.value_or_exit(VCPKG_LINE_INFO); + } + } + + return env; + } + std::string make_build_env_cmd(const PreBuildInfo& pre_build_info, const Toolset& toolset) { if (pre_build_info.external_toolchain_file.has_value()) return ""; @@ -274,7 +276,7 @@ namespace vcpkg::Build return bcf; } - static void write_binary_control_file(const VcpkgPaths& paths, BinaryControlFile bcf) + static void write_binary_control_file(const VcpkgPaths& paths, const BinaryControlFile& bcf) { std::string start = Strings::serialize(bcf.core_paragraph); for (auto&& feature : bcf.features) @@ -285,23 +287,63 @@ namespace vcpkg::Build paths.get_filesystem().write_contents(binary_control_file, start, VCPKG_LINE_INFO); } - static std::vector compute_required_feature_specs(const BuildPackageConfig& config, - const StatusParagraphs& status_db) + static std::vector get_dependencies(const SourceControlFile& scf, + const std::set& feature_list, + const Triplet& triplet) { - const Triplet& triplet = config.triplet; - - const std::vector dep_strings = - Util::fmap_flatten(config.feature_list, [&](std::string const& feature) -> std::vector { - if (feature == "core") + return Util::fmap_flatten(feature_list, + [&](std::string const& feature) -> std::vector { + if (feature == "core") { - return filter_dependencies(config.scf.core_paragraph->depends, triplet); + return filter_dependencies_to_features(scf.core_paragraph->depends, triplet); } - auto maybe_feature = config.scf.find_feature(feature); + auto maybe_feature = scf.find_feature(feature); Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value()); - return filter_dependencies(maybe_feature.get()->depends, triplet); - }); + return filter_dependencies_to_features(maybe_feature.get()->depends, triplet); + } + ); + } + + static std::vector get_dependency_names(const SourceControlFile& scf, + const std::set& feature_list, + const Triplet& triplet) + { + return Util::fmap(get_dependencies(scf, feature_list, triplet), + [&](const Features& feat) { + return feat.name; + } + ); + } + + static std::vector get_partials(const VcpkgPaths& paths, + const std::vector& dependencies, + const Triplet& triplet) + { + std::vector ret; + Files::Filesystem& fs = paths.get_filesystem(); + + for (const std::string& dependency : dependencies) + { + fs::path partial = + paths.buildtrees / dependency / triplet.canonical_name() / "partial_triplet.cmake"; + if (fs.is_regular_file(partial)) + { + ret.emplace_back(std::move(partial)); + } + } + + return ret; + } + + static std::vector compute_required_feature_specs(const BuildPackageConfig& config, + const StatusParagraphs& status_db) + { + const Triplet& triplet = config.triplet; + + const std::vector dep_strings = + get_dependency_names(config.scf, config.feature_list, triplet); auto dep_fspecs = FeatureSpec::from_strings_and_triplet(dep_strings, triplet); Util::sort_unique_erase(dep_fspecs); @@ -353,40 +395,19 @@ namespace vcpkg::Build return concurrency; } - static ExtendedBuildResult do_build_package(const VcpkgPaths& paths, - const PreBuildInfo& pre_build_info, - const PackageSpec& spec, - const std::string& abi_tag, - const BuildPackageConfig& config) + static std::vector get_cmake_vars(const VcpkgPaths& paths, + const PreBuildInfo& pre_build_info, + const BuildPackageConfig& config, + const Triplet& triplet, + const Toolset& toolset) { - auto& fs = paths.get_filesystem(); - const Triplet& triplet = spec.triplet(); - const auto& triplet_file_path = paths.get_triplet_file_path(spec.triplet()).u8string(); - - if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.triplets.u8string())) - { - System::printf("-- Loading triplet configuration from: %s\n", triplet_file_path); - } - if (!Strings::case_insensitive_ascii_starts_with(config.port_dir.u8string(), paths.ports.u8string())) - { - System::printf("-- Installing port from location: %s\n", config.port_dir.u8string()); - } - #if !defined(_WIN32) // TODO: remove when vcpkg.exe is in charge for acquiring tools. Change introduced in vcpkg v0.0.107. // bootstrap should have already downloaded ninja, but making sure it is present in case it was deleted. vcpkg::Util::unused(paths.get_tool_exe(Tools::NINJA)); #endif - const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE); const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT); -#if defined(_WIN32) - const fs::path& powershell_exe_path = paths.get_tool_exe("powershell-core"); - if (!fs.exists(powershell_exe_path.parent_path() / "powershell.exe")) - { - fs.copy(powershell_exe_path, powershell_exe_path.parent_path() / "powershell.exe", fs::copy_options::none); - } -#endif std::string all_features; for (auto& feature : config.scf.feature_paragraphs) @@ -394,14 +415,21 @@ namespace vcpkg::Build all_features.append(feature->name + ";"); } - const Toolset& toolset = paths.get_toolset(pre_build_info); + std::vector partials = + Util::fmap( + get_partials(paths, get_dependency_names(config.scf, config.feature_list, triplet), triplet), + [&](const fs::path& path) + { + return path.u8string(); + } + ); std::vector variables{ {"CMD", "BUILD"}, {"PORT", config.scf.core_paragraph->name}, {"CURRENT_PORT_DIR", config.port_dir}, - {"TARGET_TRIPLET", spec.triplet().canonical_name()}, - {"TARGET_TRIPLET_FILE", triplet_file_path}, + {"TARGET_TRIPLET", triplet.canonical_name()}, + {"TARGET_TRIPLET_FILE", paths.get_triplet_file_path(triplet).u8string()}, {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()}, {"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"}, {"DOWNLOADS", paths.downloads}, @@ -410,6 +438,7 @@ namespace vcpkg::Build {"FEATURES", Strings::join(";", config.feature_list)}, {"ALL_FEATURES", all_features}, {"VCPKG_CONCURRENCY", std::to_string(get_concurrency())}, + {"VCPKG_PARTIAL_TRIPLETS", Strings::join(";", partials)}, }; if (!System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value()) @@ -417,9 +446,22 @@ namespace vcpkg::Build variables.push_back({"GIT", git_exe_path}); } + return variables; + } + + static std::string make_build_cmd(const VcpkgPaths& paths, + const PreBuildInfo& pre_build_info, + const BuildPackageConfig& config, + const Triplet& triplet) + { + const Toolset& toolset = paths.get_toolset(pre_build_info); + const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE); + std::vector variables = + get_cmake_vars(paths, pre_build_info, config, triplet, toolset); + const std::string cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, paths.ports_cmake, variables); - auto command = make_build_env_cmd(pre_build_info, toolset); + std::string command = make_build_env_cmd(pre_build_info, toolset); if (!command.empty()) { #ifdef _WIN32 @@ -428,16 +470,93 @@ namespace vcpkg::Build command.append(" && "); #endif } + command.append(cmd_launch_cmake); + + return command; + } + + static std::string get_triplet_abi(const VcpkgPaths& paths, + const PreBuildInfo& pre_build_info, + const Triplet& triplet) + { + static std::map s_hash_cache; + + const fs::path triplet_file_path = paths.get_triplet_file_path(triplet); + const auto& fs = paths.get_filesystem(); + + std::string hash; + + auto it_hash = s_hash_cache.find(triplet_file_path); + if (it_hash != s_hash_cache.end()) + { + hash = it_hash->second; + } + else + { + hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1"); + + if (auto p = pre_build_info.external_toolchain_file.get()) + { + hash += "-"; + hash += Hash::get_file_hash(fs, *p, "SHA1"); + } + else if (pre_build_info.cmake_system_name == "Linux") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1"); + } + else if (pre_build_info.cmake_system_name == "Darwin") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1"); + } + else if (pre_build_info.cmake_system_name == "FreeBSD") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1"); + } + else if (pre_build_info.cmake_system_name == "Android") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1"); + } + + s_hash_cache.emplace(triplet_file_path, hash); + } + + return hash; + } + + static ExtendedBuildResult do_build_package(const VcpkgPaths& paths, + const PreBuildInfo& pre_build_info, + const PackageSpec& spec, + const std::string& abi_tag, + const BuildPackageConfig& config) + { + auto& fs = paths.get_filesystem(); + const Triplet& triplet = spec.triplet(); + const auto& triplet_file_path = paths.get_triplet_file_path(spec.triplet()).u8string(); + + if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.triplets.u8string())) + { + System::printf("-- Loading triplet configuration from: %s\n", triplet_file_path); + } + if (!Strings::case_insensitive_ascii_starts_with(config.port_dir.u8string(), paths.ports.u8string())) + { + System::printf("-- Installing port from location: %s\n", config.port_dir.u8string()); + } + const auto timer = Chrono::ElapsedTimer::create_started(); - const int return_code = System::cmd_execute_clean( - command, - {} -#ifdef _WIN32 - , - powershell_exe_path.parent_path().u8string() + ";" -#endif - ); + + std::string command = + make_build_cmd(paths, pre_build_info, config, triplet); + std::unordered_map env = + make_env_passthrough(pre_build_info); + + const int return_code = + System::cmd_execute_clean(command, env); + const auto buildtimeus = timer.microseconds(); const auto spec_string = spec.to_string(); @@ -711,7 +830,7 @@ namespace vcpkg::Build { System::print2("Using cached binary package: ", archive_path.u8string(), "\n"); - auto archive_result = decompress_archive(paths, spec, archive_path); + int archive_result = decompress_archive(paths, spec, archive_path); if (archive_result != 0) { @@ -946,111 +1065,60 @@ namespace vcpkg::Build const std::string variable_name = s.at(0); const std::string variable_value = variable_with_no_value ? "" : s.at(1); - if (variable_name == "VCPKG_TARGET_ARCHITECTURE") - { - pre_build_info.target_architecture = variable_value; - continue; - } - - if (variable_name == "VCPKG_CMAKE_SYSTEM_NAME") - { - pre_build_info.cmake_system_name = variable_value; - continue; - } - - if (variable_name == "VCPKG_CMAKE_SYSTEM_VERSION") - { - pre_build_info.cmake_system_version = variable_value; - continue; - } - - if (variable_name == "VCPKG_PLATFORM_TOOLSET") - { - pre_build_info.platform_toolset = - variable_value.empty() ? nullopt : Optional{variable_value}; - continue; - } - - if (variable_name == "VCPKG_VISUAL_STUDIO_PATH") + auto maybe_option = VCPKG_OPTIONS.find(variable_name); + if (maybe_option != VCPKG_OPTIONS.end()) { - pre_build_info.visual_studio_path = - variable_value.empty() ? nullopt : Optional{variable_value}; - continue; - } - - if (variable_name == "VCPKG_CHAINLOAD_TOOLCHAIN_FILE") - { - pre_build_info.external_toolchain_file = - variable_value.empty() ? nullopt : Optional{variable_value}; - continue; + switch (maybe_option->second) + { + case VcpkgTripletVar::TARGET_ARCHITECTURE : + pre_build_info.target_architecture = variable_value; + break; + case VcpkgTripletVar::CMAKE_SYSTEM_NAME : + pre_build_info.cmake_system_name = variable_value; + break; + case VcpkgTripletVar::CMAKE_SYSTEM_VERSION : + pre_build_info.cmake_system_version = variable_value; + break; + case VcpkgTripletVar::PLATFORM_TOOLSET : + pre_build_info.platform_toolset = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::VISUAL_STUDIO_PATH : + pre_build_info.visual_studio_path = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE : + pre_build_info.external_toolchain_file = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::BUILD_TYPE : + if (variable_value.empty()) + pre_build_info.build_type = nullopt; + else if (Strings::case_insensitive_ascii_equals(variable_value, "debug")) + pre_build_info.build_type = ConfigurationType::DEBUG; + else if (Strings::case_insensitive_ascii_equals(variable_value, "release")) + pre_build_info.build_type = ConfigurationType::RELEASE; + else + Checks::exit_with_message( + VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value); + break; + case VcpkgTripletVar::ENV_PASSTHROUGH : + pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";"); + break; + } } - - if (variable_name == "VCPKG_BUILD_TYPE") + else { - if (variable_value.empty()) - pre_build_info.build_type = nullopt; - else if (Strings::case_insensitive_ascii_equals(variable_value, "debug")) - pre_build_info.build_type = ConfigurationType::DEBUG; - else if (Strings::case_insensitive_ascii_equals(variable_value, "release")) - pre_build_info.build_type = ConfigurationType::RELEASE; - else - Checks::exit_with_message( - VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value); - continue; + Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown variable name %s", line); } - - Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown variable name %s", line); } - pre_build_info.triplet_abi_tag = [&]() { - const auto& fs = paths.get_filesystem(); - static std::map s_hash_cache; - - auto it_hash = s_hash_cache.find(triplet_file_path); - if (it_hash != s_hash_cache.end()) - { - return it_hash->second; - } - auto hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1"); - - if (auto p = pre_build_info.external_toolchain_file.get()) - { - hash += "-"; - hash += Hash::get_file_hash(fs, *p, "SHA1"); - } - else if (pre_build_info.cmake_system_name.empty() || - pre_build_info.cmake_system_name == "WindowsStore") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "windows.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Linux") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Darwin") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "FreeBSD") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Android") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1"); - } - - s_hash_cache.emplace(triplet_file_path, hash); - return hash; - }(); + pre_build_info.triplet_abi_tag = + get_triplet_abi(paths, pre_build_info, triplet); return pre_build_info; } + ExtendedBuildResult::ExtendedBuildResult(BuildResult code) : code(code) {} ExtendedBuildResult::ExtendedBuildResult(BuildResult code, std::unique_ptr&& bcf) : code(code), binary_control_file(std::move(bcf)) diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 9bc59cbe7..1a52bd05f 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -238,6 +238,28 @@ namespace vcpkg return ret; } + std::vector filter_dependencies_to_features(const std::vector& deps, + const Triplet& t) + { + std::vector ret; + for (auto&& dep : deps) + { + auto qualifiers = Strings::split(dep.qualifier, "&"); + if (std::all_of(qualifiers.begin(), qualifiers.end(), [&](const std::string& qualifier) { + if (qualifier.empty()) return true; + if (qualifier[0] == '!') + { + return t.canonical_name().find(qualifier.substr(1)) == std::string::npos; + } + return t.canonical_name().find(qualifier) != std::string::npos; + })) + { + ret.emplace_back(dep.depend); + } + } + return ret; + } + std::vector filter_dependencies_to_specs(const std::vector& deps, const Triplet& t) { return FeatureSpec::from_strings_and_triplet(filter_dependencies(deps, t), t); -- cgit v1.2.3 From 6bef95b6f50b2bb602781d6d8898d27639294ff6 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 16 Jul 2019 14:43:56 -0700 Subject: remove partials --- toolsrc/src/vcpkg/build.cpp | 30 ------------------------------ 1 file changed, 30 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index e0c78f2da..dd2beec9d 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -317,26 +317,6 @@ namespace vcpkg::Build ); } - static std::vector get_partials(const VcpkgPaths& paths, - const std::vector& dependencies, - const Triplet& triplet) - { - std::vector ret; - Files::Filesystem& fs = paths.get_filesystem(); - - for (const std::string& dependency : dependencies) - { - fs::path partial = - paths.buildtrees / dependency / triplet.canonical_name() / "partial_triplet.cmake"; - if (fs.is_regular_file(partial)) - { - ret.emplace_back(std::move(partial)); - } - } - - return ret; - } - static std::vector compute_required_feature_specs(const BuildPackageConfig& config, const StatusParagraphs& status_db) { @@ -415,15 +395,6 @@ namespace vcpkg::Build all_features.append(feature->name + ";"); } - std::vector partials = - Util::fmap( - get_partials(paths, get_dependency_names(config.scf, config.feature_list, triplet), triplet), - [&](const fs::path& path) - { - return path.u8string(); - } - ); - std::vector variables{ {"CMD", "BUILD"}, {"PORT", config.scf.core_paragraph->name}, @@ -438,7 +409,6 @@ namespace vcpkg::Build {"FEATURES", Strings::join(";", config.feature_list)}, {"ALL_FEATURES", all_features}, {"VCPKG_CONCURRENCY", std::to_string(get_concurrency())}, - {"VCPKG_PARTIAL_TRIPLETS", Strings::join(";", partials)}, }; if (!System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value()) -- cgit v1.2.3 From 44dcc3d4f3d2bc56cc9f6d0371a141ad0145d537 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 16 Jul 2019 15:34:13 -0700 Subject: First pass at port settings --- toolsrc/src/vcpkg/build.cpp | 21 ++++++++++++++++----- toolsrc/src/vcpkg/commands.ci.cpp | 9 ++++++++- 2 files changed, 24 insertions(+), 6 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index dd2beec9d..646da7398 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -782,7 +782,8 @@ namespace vcpkg::Build AbiEntry{status_it->get()->package.spec.name(), status_it->get()->package.abi}); } - const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet); + const auto pre_build_info = + PreBuildInfo::from_triplet_file(paths, triplet, config.scf.core_paragraph->name); auto maybe_abi_tag_and_file = compute_abi_tag(paths, config, pre_build_info, dependency_abis); @@ -997,7 +998,9 @@ namespace vcpkg::Build return inner_create_buildinfo(*pghs.get()); } - PreBuildInfo PreBuildInfo::from_triplet_file(const VcpkgPaths& paths, const Triplet& triplet) + PreBuildInfo PreBuildInfo::from_triplet_file(const VcpkgPaths& paths, + const Triplet& triplet, + Optional port) { static constexpr CStringView FLAG_GUID = "c35112b6-d1ba-415b-aa5d-81de856ef8eb"; @@ -1005,11 +1008,19 @@ namespace vcpkg::Build const fs::path ports_cmake_script_path = paths.scripts / "get_triplet_environment.cmake"; const fs::path triplet_file_path = paths.get_triplet_file_path(triplet); + std::vector args{{"CMAKE_TRIPLET_FILE", triplet_file_path}}; + + if (port) + { + args.emplace_back( + "CMAKE_PORT_SETTINGS", + paths.ports / port.value_or_exit(VCPKG_LINE_INFO) / "port_settings.cmake"); + } + const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, ports_cmake_script_path, - { - {"CMAKE_TRIPLET_FILE", triplet_file_path}, - }); + args); + const auto ec_data = System::cmd_execute_and_capture_output(cmd_launch_cmake); Checks::check_exit(VCPKG_LINE_INFO, ec_data.exit_code == 0, ec_data.output); diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index c12c26ff7..493c052cb 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -254,7 +254,14 @@ namespace vcpkg::Commands::CI return {spec.name(), it->second}; }); const auto& pre_build_info = pre_build_info_cache.get_lazy( - triplet, [&]() { return Build::PreBuildInfo::from_triplet_file(paths, triplet); }); + triplet, + [&]() { + return Build::PreBuildInfo::from_triplet_file( + paths, + triplet, + scfl->source_control_file->core_paragraph->name); + } + ); auto maybe_tag_and_file = Build::compute_abi_tag(paths, build_config, pre_build_info, dependency_abis); -- cgit v1.2.3 From 64198a8109b9d1cffcc3830f70d0c3f2b066638d Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 16 Jul 2019 15:51:50 -0700 Subject: Add to vcpkg.cmake --- toolsrc/src/vcpkg/build.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 646da7398..03e0c0b1d 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -401,6 +401,7 @@ namespace vcpkg::Build {"CURRENT_PORT_DIR", config.port_dir}, {"TARGET_TRIPLET", triplet.canonical_name()}, {"TARGET_TRIPLET_FILE", paths.get_triplet_file_path(triplet).u8string()}, + {"CMAKE_PORT_SETTINGS", config.port_dir / "port_settings.cmake"}, {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()}, {"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"}, {"DOWNLOADS", paths.downloads}, -- cgit v1.2.3 From d4ab567609495a5c239f537d7c1e200f7b8a19c0 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Wed, 17 Jul 2019 10:10:36 -0700 Subject: first pass at abi additional files --- toolsrc/src/vcpkg/build.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 03e0c0b1d..daed6f695 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -496,6 +496,31 @@ namespace vcpkg::Build s_hash_cache.emplace(triplet_file_path, hash); } + for (const fs::path& additional_file : pre_build_info.additional_files) + { + it_hash = s_hash_cache.find(additional_file); + + if (it_hash != s_hash_cache.end()) + { + hash += "-"; + hash += it_hash->second; + } + else if (fs.is_regular_file(additional_file)) + { + std::string tmp_hash = Hash::get_file_hash(fs, additional_file, "SHA1"); + hash += "-"; + hash += tmp_hash; + + s_hash_cache.emplace(additional_file, tmp_hash); + } + else + { + Checks::exit_with_message( + VCPKG_LINE_INFO, + additional_file + " was listed as an additional file for calculating the abi, but was not found."); + } + } + return hash; } @@ -1087,6 +1112,13 @@ namespace vcpkg::Build case VcpkgTripletVar::ENV_PASSTHROUGH : pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";"); break; + case VcpkgTripletVar::ABI_ADDITIONAL_FILES : + pre_build_info.additional_files = Util::fmap(Strings::split(variable_value, ";"), + [](const std::string& path) + { + return fs::path{path}; + }); + break; } } else -- cgit v1.2.3 From e81d22ddec6887a497055d4804a004ca662b4526 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Wed, 17 Jul 2019 10:18:20 -0700 Subject: Convert name of file to u8 string, to compile on windows --- toolsrc/src/vcpkg/build.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index daed6f695..b88d4fd1a 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -517,7 +517,7 @@ namespace vcpkg::Build { Checks::exit_with_message( VCPKG_LINE_INFO, - additional_file + " was listed as an additional file for calculating the abi, but was not found."); + additional_file.u8string() + " was listed as an additional file for calculating the abi, but was not found."); } } -- cgit v1.2.3 From f0f615532f9aa03f1518f03009cff5c716e9b1fd Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Wed, 17 Jul 2019 11:40:27 -0700 Subject: always calculate abi --- toolsrc/src/vcpkg/build.cpp | 116 ++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 57 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index b88d4fd1a..47599bfca 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -623,8 +623,6 @@ namespace vcpkg::Build const PreBuildInfo& pre_build_info, Span dependency_abis) { - if (config.build_package_options.binary_caching == BinaryCaching::NO) return nullopt; - auto& fs = paths.get_filesystem(); const Triplet& triplet = config.triplet; const std::string& name = config.scf.core_paragraph->name; @@ -713,7 +711,7 @@ namespace vcpkg::Build } System::print2( - "Warning: binary caching disabled because abi keys are missing values:\n", + "Warning: abi keys are missing values:\n", Strings::join("", abi_tag_entries_missing, [](const AbiEntry& e) { return " " + e.key + "\n"; }), "\n"); @@ -814,15 +812,14 @@ namespace vcpkg::Build auto maybe_abi_tag_and_file = compute_abi_tag(paths, config, pre_build_info, dependency_abis); const auto abi_tag_and_file = maybe_abi_tag_and_file.get(); + const fs::path archives_root_dir = paths.root / "archives"; + const std::string archive_name = abi_tag_and_file->tag + ".zip"; + const fs::path archive_subpath = fs::u8path(abi_tag_and_file->tag.substr(0, 2)) / archive_name; + const fs::path archive_path = archives_root_dir / archive_subpath; + const fs::path archive_tombstone_path = archives_root_dir / "fail" / archive_subpath; if (config.build_package_options.binary_caching == BinaryCaching::YES && abi_tag_and_file) { - const fs::path archives_root_dir = paths.root / "archives"; - const std::string archive_name = abi_tag_and_file->tag + ".zip"; - const fs::path archive_subpath = fs::u8path(abi_tag_and_file->tag.substr(0, 2)) / archive_name; - const fs::path archive_path = archives_root_dir / archive_subpath; - const fs::path archive_tombstone_path = archives_root_dir / "fail" / archive_subpath; - if (fs.exists(archive_path)) { System::print2("Using cached binary package: ", archive_path.u8string(), "\n"); @@ -855,70 +852,75 @@ namespace vcpkg::Build } System::printf("Could not locate cached archive: %s\n", archive_path.u8string()); + } - ExtendedBuildResult result = do_build_package_and_clean_buildtrees( - paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config); + ExtendedBuildResult result = + do_build_package_and_clean_buildtrees( + paths, + pre_build_info, + spec, + maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, + config); - std::error_code ec; - fs.create_directories(paths.package_dir(spec) / "share" / spec.name(), ec); - auto abi_file_in_package = paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt"; - fs.copy_file(abi_tag_and_file->tag_file, abi_file_in_package, fs::stdfs::copy_options::none, ec); - Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string()); + std::error_code ec; + fs.create_directories(paths.package_dir(spec) / "share" / spec.name(), ec); + auto abi_file_in_package = paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt"; + fs.copy_file(abi_tag_and_file->tag_file, abi_file_in_package, fs::stdfs::copy_options::none, ec); + Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string()); - if (result.code == BuildResult::SUCCEEDED) - { - const auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip"); + if (config.build_package_options.binary_caching == BinaryCaching::YES && + result.code == BuildResult::SUCCEEDED) + { + const auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip"); - compress_archive(paths, spec, tmp_archive_path); + compress_archive(paths, spec, tmp_archive_path); - fs.create_directories(archive_path.parent_path(), ec); - fs.rename_or_copy(tmp_archive_path, archive_path, ".tmp", ec); - if (ec) - { - System::printf(System::Color::warning, - "Failed to store binary cache %s: %s\n", - archive_path.u8string(), - ec.message()); - } - else - System::printf("Stored binary cache: %s\n", archive_path.u8string()); + fs.create_directories(archive_path.parent_path(), ec); + fs.rename_or_copy(tmp_archive_path, archive_path, ".tmp", ec); + if (ec) + { + System::printf(System::Color::warning, + "Failed to store binary cache %s: %s\n", + archive_path.u8string(), + ec.message()); } - else if (result.code == BuildResult::BUILD_FAILED || result.code == BuildResult::POST_BUILD_CHECKS_FAILED) + else + System::printf("Stored binary cache: %s\n", archive_path.u8string()); + } + else if (config.build_package_options.binary_caching == BinaryCaching::YES && + (result.code == BuildResult::BUILD_FAILED || + result.code == BuildResult::POST_BUILD_CHECKS_FAILED)) + { + if (!fs.exists(archive_tombstone_path)) { - if (!fs.exists(archive_tombstone_path)) - { - // Build failed, store all failure logs in the tombstone. - const auto tmp_log_path = paths.buildtrees / spec.name() / "tmp_failure_logs"; - const auto tmp_log_path_destination = tmp_log_path / spec.name(); - const auto tmp_failure_zip = paths.buildtrees / spec.name() / "failure_logs.zip"; - fs.create_directories(tmp_log_path_destination, ec); + // Build failed, store all failure logs in the tombstone. + const auto tmp_log_path = paths.buildtrees / spec.name() / "tmp_failure_logs"; + const auto tmp_log_path_destination = tmp_log_path / spec.name(); + const auto tmp_failure_zip = paths.buildtrees / spec.name() / "failure_logs.zip"; + fs.create_directories(tmp_log_path_destination, ec); - for (auto& log_file : fs::stdfs::directory_iterator(paths.buildtrees / spec.name())) + for (auto& log_file : fs::stdfs::directory_iterator(paths.buildtrees / spec.name())) + { + if (log_file.path().extension() == ".log") { - if (log_file.path().extension() == ".log") - { - fs.copy_file(log_file.path(), - tmp_log_path_destination / log_file.path().filename(), - fs::stdfs::copy_options::none, - ec); - } + fs.copy_file(log_file.path(), + tmp_log_path_destination / log_file.path().filename(), + fs::stdfs::copy_options::none, + ec); } + } - compress_directory(paths, tmp_log_path, paths.buildtrees / spec.name() / "failure_logs.zip"); + compress_directory(paths, tmp_log_path, paths.buildtrees / spec.name() / "failure_logs.zip"); - fs.create_directories(archive_tombstone_path.parent_path(), ec); - fs.rename_or_copy(tmp_failure_zip, archive_tombstone_path, ".tmp", ec); + fs.create_directories(archive_tombstone_path.parent_path(), ec); + fs.rename_or_copy(tmp_failure_zip, archive_tombstone_path, ".tmp", ec); - // clean up temporary directory - fs.remove_all(tmp_log_path, ec); - } + // clean up temporary directory + fs.remove_all(tmp_log_path, ec); } - - return result; } - return do_build_package_and_clean_buildtrees( - paths, pre_build_info, spec, maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, config); + return result; } const std::string& to_string(const BuildResult build_result) -- cgit v1.2.3 From 58958eb0ea47c6c423fe78f2cd6fd1e31cbcb082 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Wed, 17 Jul 2019 14:27:18 -0700 Subject: sourceparagraph changes --- toolsrc/src/vcpkg/sourceparagraph.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 1a52bd05f..26a7ab118 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -25,6 +25,7 @@ namespace vcpkg static const std::string SUPPORTS = "Supports"; static const std::string VERSION = "Version"; static const std::string HOMEPAGE = "Homepage"; + static const std::string TYPE = "Type"; } static Span get_list_of_valid_fields() @@ -36,6 +37,7 @@ namespace vcpkg SourceParagraphFields::MAINTAINER, SourceParagraphFields::BUILD_DEPENDS, SourceParagraphFields::HOMEPAGE, + SourceParagraphFields::TYPE, }; return valid_fields; @@ -98,6 +100,35 @@ namespace vcpkg } } + static SourceParagraph::TYPE type_from_string(const std::string& in) + { + if (Strings::equals(in, "port") || Strings::equals(in, "")) + { + return SourceParagraph::PORT; + } + + if (Strings::equals(in, "sys-tool")) + { + return SourceParagraph::SYS_TOOL; + } + + System::print2( + in, " is not a valid control file type. Valid types are:", + "\n port\n sys-tool"); + + Checks::exit_fail(VCPKG_LINE_INFO); + } + + static std::string string_from_type(const SourceParagraph::TYPE& in) + { + switch (in) + { + case SourceParagraph::PORT : return "port"; + case SourceParagraph::SYS_TOOL : return "sys-tool"; + default : Checks::exit_with_message(VCPKG_LINE_INFO, "Invalid CONTROL_TYPE value."); + } + } + static ParseExpected parse_source_paragraph(RawParagraph&& fields) { ParagraphParser parser(std::move(fields)); @@ -114,6 +145,7 @@ namespace vcpkg parse_comma_list(parser.optional_field(SourceParagraphFields::BUILD_DEPENDS))); spgh->supports = parse_comma_list(parser.optional_field(SourceParagraphFields::SUPPORTS)); spgh->default_features = parse_comma_list(parser.optional_field(SourceParagraphFields::DEFAULTFEATURES)); + spgh->type = type_from_string(parser.optional_field(SourceParagraphFields::TYPE)); auto err = parser.error_info(spgh->name); if (err) -- cgit v1.2.3 From f18ffe996877a058da9e0208f92331c83517f6a0 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Wed, 17 Jul 2019 16:04:05 -0700 Subject: Add type field --- toolsrc/src/vcpkg/binaryparagraph.cpp | 10 ++++++++-- toolsrc/src/vcpkg/sourceparagraph.cpp | 6 +++--- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index 4b80debab..ad7790fe1 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -23,6 +23,7 @@ namespace vcpkg static const std::string MAINTAINER = "Maintainer"; static const std::string DEPENDS = "Depends"; static const std::string DEFAULTFEATURES = "Default-Features"; + static const std::string TYPE = "Type"; } BinaryParagraph::BinaryParagraph() = default; @@ -60,6 +61,9 @@ namespace vcpkg this->default_features = parse_comma_list(parser.optional_field(Fields::DEFAULTFEATURES)); } + this->type = + SourceParagraph::type_from_string(parser.optional_field(Fields::TYPE)); + if (const auto err = parser.error_info(this->spec.to_string())) { System::print2(System::Color::error, "Error: while parsing the Binary Paragraph for ", this->spec, '\n'); @@ -72,14 +76,14 @@ namespace vcpkg } BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const Triplet& triplet, const std::string& abi_tag) - : version(spgh.version), description(spgh.description), maintainer(spgh.maintainer), abi(abi_tag) + : version(spgh.version), description(spgh.description), maintainer(spgh.maintainer), abi(abi_tag), type(spgh.type) { this->spec = PackageSpec::from_name_and_triplet(spgh.name, triplet).value_or_exit(VCPKG_LINE_INFO); this->depends = filter_dependencies(spgh.depends, triplet); } BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const FeatureParagraph& fpgh, const Triplet& triplet) - : version(), description(fpgh.description), maintainer(), feature(fpgh.name) + : version(), description(fpgh.description), maintainer(), feature(fpgh.name), type(spgh.type) { this->spec = PackageSpec::from_name_and_triplet(spgh.name, triplet).value_or_exit(VCPKG_LINE_INFO); this->depends = filter_dependencies(fpgh.depends, triplet); @@ -119,5 +123,7 @@ namespace vcpkg if (!pgh.maintainer.empty()) out_str.append("Maintainer: ").append(pgh.maintainer).push_back('\n'); if (!pgh.abi.empty()) out_str.append("Abi: ").append(pgh.abi).push_back('\n'); if (!pgh.description.empty()) out_str.append("Description: ").append(pgh.description).push_back('\n'); + + out_str.append("Type: ").append(SourceParagraph::string_from_type(pgh.type)).push_back('\n'); } } diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 26a7ab118..6af93a99b 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -100,7 +100,7 @@ namespace vcpkg } } - static SourceParagraph::TYPE type_from_string(const std::string& in) + SourceParagraph::TYPE SourceParagraph::type_from_string(const std::string& in) { if (Strings::equals(in, "port") || Strings::equals(in, "")) { @@ -119,7 +119,7 @@ namespace vcpkg Checks::exit_fail(VCPKG_LINE_INFO); } - static std::string string_from_type(const SourceParagraph::TYPE& in) + std::string SourceParagraph::string_from_type(const SourceParagraph::TYPE& in) { switch (in) { @@ -145,7 +145,7 @@ namespace vcpkg parse_comma_list(parser.optional_field(SourceParagraphFields::BUILD_DEPENDS))); spgh->supports = parse_comma_list(parser.optional_field(SourceParagraphFields::SUPPORTS)); spgh->default_features = parse_comma_list(parser.optional_field(SourceParagraphFields::DEFAULTFEATURES)); - spgh->type = type_from_string(parser.optional_field(SourceParagraphFields::TYPE)); + spgh->type = SourceParagraph::type_from_string(parser.optional_field(SourceParagraphFields::TYPE)); auto err = parser.error_info(spgh->name); if (err) -- cgit v1.2.3 From f599f19bad8fd97b60f41063537be2e4ecef3ca7 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 17 Jul 2019 18:58:23 -0700 Subject: tests.files.cpp:create_directory_tree -- change magic numbers to names --- toolsrc/src/tests.files.cpp | 79 ++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 36 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/tests.files.cpp b/toolsrc/src/tests.files.cpp index 56b0ceac6..e60662fd9 100644 --- a/toolsrc/src/tests.files.cpp +++ b/toolsrc/src/tests.files.cpp @@ -93,45 +93,31 @@ namespace UnitTest1 std::random_device rd; constexpr std::uint64_t max_depth = 5; constexpr std::uint64_t width = 5; - const auto type = depth < max_depth ? uid{0, 9}(urbg) : uid{7, 9}(urbg); - // 0 <= type < 7 : directory - // 7 = type : regular - // 8 = type : regular symlink (regular file if !ALLOW_SYMLINKS) - // 9 = type : directory symlink (^^) - - std::error_code ec; - if (type >= 7) - { - // I don't want to move urbg forward conditionally - if (type == 7 || !ALLOW_SYMLINKS) - { - // regular file - fs.write_contents(base, "", ec); - } - else if (type == 8) - { - // regular symlink - fs.write_contents(base, "", ec); - Assert::IsFalse(bool(ec)); - const std::filesystem::path basep = base.native(); - auto basep_link = basep; - basep_link.replace_filename(basep.filename().native() + L"-link"); - std::filesystem::create_symlink(basep, basep_link, ec); - } - else - { - // directory symlink - std::filesystem::path basep = base.native(); - std::filesystem::create_directory_symlink(basep / "..", basep, ec); - } - - Assert::IsFalse(bool(ec)); + // we want ~70% of our "files" to be directories, and then a third + // each of the remaining ~30% to be regular files, directory symlinks, + // and regular symlinks + constexpr std::uint64_t directory_min_tag = 0; + constexpr std::uint64_t directory_max_tag = 6; + constexpr std::uint64_t regular_file_tag = 7; + constexpr std::uint64_t regular_symlink_tag = 8; + constexpr std::uint64_t directory_symlink_tag = 9; + + // if we're at the max depth, we only want to build non-directories + std::uint64_t file_type; + if (depth < max_depth) { + file_type = uid{directory_min_tag, regular_symlink_tag}(urbg); + } else { + file_type = uid{regular_file_tag, regular_symlink_tag}(urbg); + } + if (!ALLOW_SYMLINKS && file_type > regular_file_tag) { + file_type = regular_file_tag; } - else + + std::error_code ec; + if (type <= directory_max_tag) { - // directory fs.create_directory(base, ec); Assert::IsFalse(bool(ec)); @@ -139,9 +125,30 @@ namespace UnitTest1 { create_directory_tree(urbg, fs, depth + 1, base / get_random_filename(urbg)); } - + } + else if (type == regular_file_tag) + { + // regular file + fs.write_contents(base, "", ec); + } + else if (type == regular_symlink_tag) + { + // regular symlink + fs.write_contents(base, "", ec); + Assert::IsFalse(bool(ec)); + const std::filesystem::path basep = base.native(); + auto basep_link = basep; + basep_link.replace_filename(basep.filename().native() + L"-link"); + std::filesystem::create_symlink(basep, basep_link, ec); + } + else // type == directory_symlink_tag + { + // directory symlink + std::filesystem::path basep = base.native(); + std::filesystem::create_directory_symlink(basep / "..", basep, ec); } + Assert::IsFalse(bool(ec)); } }; } -- cgit v1.2.3 From bb3a9ddb6ec917f549e991f6bd344ce77054bb67 Mon Sep 17 00:00:00 2001 From: Curtis J Bezault Date: Thu, 18 Jul 2019 09:02:21 -0700 Subject: [vcpkg] Environment Variable Passthrough (#7290) * use additional env param * remove partials * remove change to linux triplet * Fix some issues that vicroms pointed out * whitespace change --- toolsrc/src/vcpkg/build.cpp | 367 +++++++++++++++++++--------------- toolsrc/src/vcpkg/sourceparagraph.cpp | 22 ++ 2 files changed, 225 insertions(+), 164 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 68df1f965..2f58a3341 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -32,24 +32,16 @@ namespace vcpkg::Build::Command using Dependencies::InstallPlanAction; using Dependencies::InstallPlanType; - static constexpr StringLiteral OPTION_CHECKS_ONLY = "--checks-only"; - void perform_and_exit_ex(const FullPackageSpec& full_spec, const SourceControlFileLocation& scfl, const ParsedArguments& options, const VcpkgPaths& paths) { + vcpkg::Util::unused(options); + + const StatusParagraphs status_db = database_load_check(paths); const PackageSpec& spec = full_spec.package_spec; - const auto& scf = *scfl.source_control_file; - if (Util::Sets::contains(options.switches, OPTION_CHECKS_ONLY)) - { - const auto pre_build_info = Build::PreBuildInfo::from_triplet_file(paths, spec.triplet()); - const auto build_info = Build::read_build_info(paths.get_filesystem(), paths.build_info_file_path(spec)); - const size_t error_count = - PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info, scfl.source_location); - Checks::check_exit(VCPKG_LINE_INFO, error_count == 0); - Checks::exit_success(VCPKG_LINE_INFO); - } + const SourceControlFile& scf = *scfl.source_control_file; Checks::check_exit(VCPKG_LINE_INFO, spec.name() == scf.core_paragraph->name, @@ -57,7 +49,6 @@ namespace vcpkg::Build::Command scf.core_paragraph->name, spec.name()); - const StatusParagraphs status_db = database_load_check(paths); const Build::BuildPackageOptions build_package_options{ Build::UseHeadVersion::NO, Build::AllowDownloads::YES, @@ -104,15 +95,11 @@ namespace vcpkg::Build::Command Checks::exit_success(VCPKG_LINE_INFO); } - static constexpr std::array BUILD_SWITCHES = {{ - {OPTION_CHECKS_ONLY, "Only run checks, do not rebuild package"}, - }}; - const CommandStructure COMMAND_STRUCTURE = { Help::create_example_string("build zlib:x64-windows"), 1, 1, - {BUILD_SWITCHES, {}}, + {{}, {}}, nullptr, }; @@ -230,6 +217,23 @@ namespace vcpkg::Build })); } + std::unordered_map make_env_passthrough(const PreBuildInfo& pre_build_info) + { + std::unordered_map env; + + for (auto&& env_var : pre_build_info.passthrough_env_vars) + { + auto env_val = System::get_environment_variable(env_var); + + if (env_val) + { + env[env_var] = env_val.value_or_exit(VCPKG_LINE_INFO); + } + } + + return env; + } + std::string make_build_env_cmd(const PreBuildInfo& pre_build_info, const Toolset& toolset) { if (pre_build_info.external_toolchain_file.has_value()) return ""; @@ -274,7 +278,7 @@ namespace vcpkg::Build return bcf; } - static void write_binary_control_file(const VcpkgPaths& paths, BinaryControlFile bcf) + static void write_binary_control_file(const VcpkgPaths& paths, const BinaryControlFile& bcf) { std::string start = Strings::serialize(bcf.core_paragraph); for (auto&& feature : bcf.features) @@ -285,23 +289,43 @@ namespace vcpkg::Build paths.get_filesystem().write_contents(binary_control_file, start, VCPKG_LINE_INFO); } - static std::vector compute_required_feature_specs(const BuildPackageConfig& config, - const StatusParagraphs& status_db) + static std::vector get_dependencies(const SourceControlFile& scf, + const std::set& feature_list, + const Triplet& triplet) { - const Triplet& triplet = config.triplet; - - const std::vector dep_strings = - Util::fmap_flatten(config.feature_list, [&](std::string const& feature) -> std::vector { + return Util::fmap_flatten( + feature_list, + [&](std::string const& feature) -> std::vector { if (feature == "core") { - return filter_dependencies(config.scf.core_paragraph->depends, triplet); + return filter_dependencies_to_features(scf.core_paragraph->depends, triplet); } - auto maybe_feature = config.scf.find_feature(feature); + auto maybe_feature = scf.find_feature(feature); Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value()); - return filter_dependencies(maybe_feature.get()->depends, triplet); + return filter_dependencies_to_features(maybe_feature.get()->depends, triplet); }); + } + + static std::vector get_dependency_names(const SourceControlFile& scf, + const std::set& feature_list, + const Triplet& triplet) + { + return Util::fmap(get_dependencies(scf, feature_list, triplet), + [&](const Features& feat) { + return feat.name; + } + ); + } + + static std::vector compute_required_feature_specs(const BuildPackageConfig& config, + const StatusParagraphs& status_db) + { + const Triplet& triplet = config.triplet; + + const std::vector dep_strings = + get_dependency_names(config.scf, config.feature_list, triplet); auto dep_fspecs = FeatureSpec::from_strings_and_triplet(dep_strings, triplet); Util::sort_unique_erase(dep_fspecs); @@ -353,40 +377,18 @@ namespace vcpkg::Build return concurrency; } - static ExtendedBuildResult do_build_package(const VcpkgPaths& paths, - const PreBuildInfo& pre_build_info, - const PackageSpec& spec, - const std::string& abi_tag, - const BuildPackageConfig& config) + static std::vector get_cmake_vars(const VcpkgPaths& paths, + const BuildPackageConfig& config, + const Triplet& triplet, + const Toolset& toolset) { - auto& fs = paths.get_filesystem(); - const Triplet& triplet = spec.triplet(); - const auto& triplet_file_path = paths.get_triplet_file_path(spec.triplet()).u8string(); - - if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.triplets.u8string())) - { - System::printf("-- Loading triplet configuration from: %s\n", triplet_file_path); - } - if (!Strings::case_insensitive_ascii_starts_with(config.port_dir.u8string(), paths.ports.u8string())) - { - System::printf("-- Installing port from location: %s\n", config.port_dir.u8string()); - } - #if !defined(_WIN32) // TODO: remove when vcpkg.exe is in charge for acquiring tools. Change introduced in vcpkg v0.0.107. // bootstrap should have already downloaded ninja, but making sure it is present in case it was deleted. vcpkg::Util::unused(paths.get_tool_exe(Tools::NINJA)); #endif - const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE); const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT); -#if defined(_WIN32) - const fs::path& powershell_exe_path = paths.get_tool_exe("powershell-core"); - if (!fs.exists(powershell_exe_path.parent_path() / "powershell.exe")) - { - fs.copy(powershell_exe_path, powershell_exe_path.parent_path() / "powershell.exe", fs::copy_options::none); - } -#endif std::string all_features; for (auto& feature : config.scf.feature_paragraphs) @@ -394,14 +396,12 @@ namespace vcpkg::Build all_features.append(feature->name + ";"); } - const Toolset& toolset = paths.get_toolset(pre_build_info); - std::vector variables{ {"CMD", "BUILD"}, {"PORT", config.scf.core_paragraph->name}, {"CURRENT_PORT_DIR", config.port_dir}, - {"TARGET_TRIPLET", spec.triplet().canonical_name()}, - {"TARGET_TRIPLET_FILE", triplet_file_path}, + {"TARGET_TRIPLET", triplet.canonical_name()}, + {"TARGET_TRIPLET_FILE", paths.get_triplet_file_path(triplet).u8string()}, {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()}, {"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"}, {"DOWNLOADS", paths.downloads}, @@ -417,9 +417,22 @@ namespace vcpkg::Build variables.push_back({"GIT", git_exe_path}); } + return variables; + } + + static std::string make_build_cmd(const VcpkgPaths& paths, + const PreBuildInfo& pre_build_info, + const BuildPackageConfig& config, + const Triplet& triplet) + { + const Toolset& toolset = paths.get_toolset(pre_build_info); + const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE); + std::vector variables = + get_cmake_vars(paths, config, triplet, toolset); + const std::string cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, paths.ports_cmake, variables); - auto command = make_build_env_cmd(pre_build_info, toolset); + std::string command = make_build_env_cmd(pre_build_info, toolset); if (!command.empty()) { #ifdef _WIN32 @@ -428,16 +441,93 @@ namespace vcpkg::Build command.append(" && "); #endif } + command.append(cmd_launch_cmake); + + return command; + } + + static std::string get_triplet_abi(const VcpkgPaths& paths, + const PreBuildInfo& pre_build_info, + const Triplet& triplet) + { + static std::map s_hash_cache; + + const fs::path triplet_file_path = paths.get_triplet_file_path(triplet); + const auto& fs = paths.get_filesystem(); + + std::string hash; + + auto it_hash = s_hash_cache.find(triplet_file_path); + if (it_hash != s_hash_cache.end()) + { + hash = it_hash->second; + } + else + { + hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1"); + + if (auto p = pre_build_info.external_toolchain_file.get()) + { + hash += "-"; + hash += Hash::get_file_hash(fs, *p, "SHA1"); + } + else if (pre_build_info.cmake_system_name == "Linux") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1"); + } + else if (pre_build_info.cmake_system_name == "Darwin") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1"); + } + else if (pre_build_info.cmake_system_name == "FreeBSD") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1"); + } + else if (pre_build_info.cmake_system_name == "Android") + { + hash += "-"; + hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1"); + } + + s_hash_cache.emplace(triplet_file_path, hash); + } + + return hash; + } + + static ExtendedBuildResult do_build_package(const VcpkgPaths& paths, + const PreBuildInfo& pre_build_info, + const PackageSpec& spec, + const std::string& abi_tag, + const BuildPackageConfig& config) + { + auto& fs = paths.get_filesystem(); + const Triplet& triplet = spec.triplet(); + const auto& triplet_file_path = paths.get_triplet_file_path(spec.triplet()).u8string(); + + if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.triplets.u8string())) + { + System::printf("-- Loading triplet configuration from: %s\n", triplet_file_path); + } + if (!Strings::case_insensitive_ascii_starts_with(config.port_dir.u8string(), paths.ports.u8string())) + { + System::printf("-- Installing port from location: %s\n", config.port_dir.u8string()); + } + const auto timer = Chrono::ElapsedTimer::create_started(); - const int return_code = System::cmd_execute_clean( - command, - {} -#ifdef _WIN32 - , - powershell_exe_path.parent_path().u8string() + ";" -#endif - ); + + std::string command = + make_build_cmd(paths, pre_build_info, config, triplet); + std::unordered_map env = + make_env_passthrough(pre_build_info); + + const int return_code = + System::cmd_execute_clean(command, env); + const auto buildtimeus = timer.microseconds(); const auto spec_string = spec.to_string(); @@ -711,7 +801,7 @@ namespace vcpkg::Build { System::print2("Using cached binary package: ", archive_path.u8string(), "\n"); - auto archive_result = decompress_archive(paths, spec, archive_path); + int archive_result = decompress_archive(paths, spec, archive_path); if (archive_result != 0) { @@ -946,111 +1036,60 @@ namespace vcpkg::Build const std::string variable_name = s.at(0); const std::string variable_value = variable_with_no_value ? "" : s.at(1); - if (variable_name == "VCPKG_TARGET_ARCHITECTURE") - { - pre_build_info.target_architecture = variable_value; - continue; - } - - if (variable_name == "VCPKG_CMAKE_SYSTEM_NAME") - { - pre_build_info.cmake_system_name = variable_value; - continue; - } - - if (variable_name == "VCPKG_CMAKE_SYSTEM_VERSION") - { - pre_build_info.cmake_system_version = variable_value; - continue; - } - - if (variable_name == "VCPKG_PLATFORM_TOOLSET") - { - pre_build_info.platform_toolset = - variable_value.empty() ? nullopt : Optional{variable_value}; - continue; - } - - if (variable_name == "VCPKG_VISUAL_STUDIO_PATH") - { - pre_build_info.visual_studio_path = - variable_value.empty() ? nullopt : Optional{variable_value}; - continue; - } - - if (variable_name == "VCPKG_CHAINLOAD_TOOLCHAIN_FILE") + auto maybe_option = VCPKG_OPTIONS.find(variable_name); + if (maybe_option != VCPKG_OPTIONS.end()) { - pre_build_info.external_toolchain_file = - variable_value.empty() ? nullopt : Optional{variable_value}; - continue; + switch (maybe_option->second) + { + case VcpkgTripletVar::TARGET_ARCHITECTURE : + pre_build_info.target_architecture = variable_value; + break; + case VcpkgTripletVar::CMAKE_SYSTEM_NAME : + pre_build_info.cmake_system_name = variable_value; + break; + case VcpkgTripletVar::CMAKE_SYSTEM_VERSION : + pre_build_info.cmake_system_version = variable_value; + break; + case VcpkgTripletVar::PLATFORM_TOOLSET : + pre_build_info.platform_toolset = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::VISUAL_STUDIO_PATH : + pre_build_info.visual_studio_path = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE : + pre_build_info.external_toolchain_file = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::BUILD_TYPE : + if (variable_value.empty()) + pre_build_info.build_type = nullopt; + else if (Strings::case_insensitive_ascii_equals(variable_value, "debug")) + pre_build_info.build_type = ConfigurationType::DEBUG; + else if (Strings::case_insensitive_ascii_equals(variable_value, "release")) + pre_build_info.build_type = ConfigurationType::RELEASE; + else + Checks::exit_with_message( + VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value); + break; + case VcpkgTripletVar::ENV_PASSTHROUGH : + pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";"); + break; + } } - - if (variable_name == "VCPKG_BUILD_TYPE") + else { - if (variable_value.empty()) - pre_build_info.build_type = nullopt; - else if (Strings::case_insensitive_ascii_equals(variable_value, "debug")) - pre_build_info.build_type = ConfigurationType::DEBUG; - else if (Strings::case_insensitive_ascii_equals(variable_value, "release")) - pre_build_info.build_type = ConfigurationType::RELEASE; - else - Checks::exit_with_message( - VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value); - continue; + Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown variable name %s", line); } - - Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown variable name %s", line); } - pre_build_info.triplet_abi_tag = [&]() { - const auto& fs = paths.get_filesystem(); - static std::map s_hash_cache; - - auto it_hash = s_hash_cache.find(triplet_file_path); - if (it_hash != s_hash_cache.end()) - { - return it_hash->second; - } - auto hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1"); - - if (auto p = pre_build_info.external_toolchain_file.get()) - { - hash += "-"; - hash += Hash::get_file_hash(fs, *p, "SHA1"); - } - else if (pre_build_info.cmake_system_name.empty() || - pre_build_info.cmake_system_name == "WindowsStore") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "windows.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Linux") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Darwin") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "FreeBSD") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Android") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1"); - } - - s_hash_cache.emplace(triplet_file_path, hash); - return hash; - }(); + pre_build_info.triplet_abi_tag = + get_triplet_abi(paths, pre_build_info, triplet); return pre_build_info; } + ExtendedBuildResult::ExtendedBuildResult(BuildResult code) : code(code) {} ExtendedBuildResult::ExtendedBuildResult(BuildResult code, std::unique_ptr&& bcf) : code(code), binary_control_file(std::move(bcf)) diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 9bc59cbe7..1a52bd05f 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -238,6 +238,28 @@ namespace vcpkg return ret; } + std::vector filter_dependencies_to_features(const std::vector& deps, + const Triplet& t) + { + std::vector ret; + for (auto&& dep : deps) + { + auto qualifiers = Strings::split(dep.qualifier, "&"); + if (std::all_of(qualifiers.begin(), qualifiers.end(), [&](const std::string& qualifier) { + if (qualifier.empty()) return true; + if (qualifier[0] == '!') + { + return t.canonical_name().find(qualifier.substr(1)) == std::string::npos; + } + return t.canonical_name().find(qualifier) != std::string::npos; + })) + { + ret.emplace_back(dep.depend); + } + } + return ret; + } + std::vector filter_dependencies_to_specs(const std::vector& deps, const Triplet& t) { return FeatureSpec::from_strings_and_triplet(filter_dependencies(deps, t), t); -- cgit v1.2.3 From d39bd70d533c64e929d4399cb9a1bdbfe0efaecd Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Thu, 18 Jul 2019 13:24:31 -0700 Subject: add needs_rebuild, should probably be moved to somewhere else --- toolsrc/src/vcpkg/statusparagraphs.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/statusparagraphs.cpp b/toolsrc/src/vcpkg/statusparagraphs.cpp index c642af59b..f204ed568 100644 --- a/toolsrc/src/vcpkg/statusparagraphs.cpp +++ b/toolsrc/src/vcpkg/statusparagraphs.cpp @@ -118,6 +118,31 @@ namespace vcpkg return it != end() && (*it)->is_installed(); } + bool vcpkg::StatusParagraphs::needs_rebuild(const PackageSpec& spec) + { + auto it = find(spec); + if (it != end()) + { + for (const std::string& dep : (*it)->package.depends) + { + PackageSpec dep_spec = + PackageSpec::from_name_and_triplet( + dep, + spec.triplet()).value_or_exit(VCPKG_LINE_INFO); + + if (needs_rebuild(dep_spec)) + { + (*it)->state = InstallState::NEEDS_REBUILD; + return true; + } + } + + return (*it)->needs_rebuild(); + } + + return false; + } + StatusParagraphs::iterator StatusParagraphs::insert(std::unique_ptr pgh) { Checks::check_exit(VCPKG_LINE_INFO, pgh != nullptr, "Inserted null paragraph"); -- cgit v1.2.3 From ef48500ac6ec3f9e0f494329365452d3ad9e1271 Mon Sep 17 00:00:00 2001 From: Dan Nissenbaum Date: Thu, 18 Jul 2019 16:53:24 -0400 Subject: Better error message when VCPKG_ROOT is independently defined (#7229) --- toolsrc/src/vcpkg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp index 363b39814..46ec8c013 100644 --- a/toolsrc/src/vcpkg.cpp +++ b/toolsrc/src/vcpkg.cpp @@ -143,7 +143,7 @@ static void inner(const VcpkgCmdArguments& args) #else const int exit_code = chdir(paths.root.c_str()); #endif - Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Changing the working dir failed"); + Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Changing the working directory to the vcpkg root directory failed. Did you incorrectly define the VCPKG_ROOT environment variable, or did you mistakenly create a file named .vcpkg-root somewhere?"); if (args.command == "install" || args.command == "remove" || args.command == "export" || args.command == "update") { -- cgit v1.2.3 From fddebb75da034752fb267ba121497ba58157bb79 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 18 Jul 2019 16:40:52 -0700 Subject: clang-format all the things --- toolsrc/src/tests.files.cpp | 16 ++++++++++------ toolsrc/src/tests.strings.cpp | 9 ++++++--- toolsrc/src/vcpkg/base/strings.cpp | 3 ++- toolsrc/src/vcpkg/build.cpp | 15 ++++++--------- 4 files changed, 24 insertions(+), 19 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/tests.files.cpp b/toolsrc/src/tests.files.cpp index e60662fd9..482675c34 100644 --- a/toolsrc/src/tests.files.cpp +++ b/toolsrc/src/tests.files.cpp @@ -3,8 +3,8 @@ #include #include -#include #include // required for filesystem::create_{directory_}symlink +#include #include #include @@ -31,11 +31,11 @@ namespace UnitTest1 } else { - // if we get a permissions error, we still know that we're in developer mode + // if we get a permissions error, we still know that we're in developer mode ALLOW_SYMLINKS = true; } - if (status == ERROR_SUCCESS) RegCloseKey(key); + if (status == ERROR_SUCCESS) RegCloseKey(key); } private: @@ -105,13 +105,17 @@ namespace UnitTest1 // if we're at the max depth, we only want to build non-directories std::uint64_t file_type; - if (depth < max_depth) { + if (depth < max_depth) + { file_type = uid{directory_min_tag, regular_symlink_tag}(urbg); - } else { + } + else + { file_type = uid{regular_file_tag, regular_symlink_tag}(urbg); } - if (!ALLOW_SYMLINKS && file_type > regular_file_tag) { + if (!ALLOW_SYMLINKS && file_type > regular_file_tag) + { file_type = regular_file_tag; } diff --git a/toolsrc/src/tests.strings.cpp b/toolsrc/src/tests.strings.cpp index 6301ea05d..f541a203d 100644 --- a/toolsrc/src/tests.strings.cpp +++ b/toolsrc/src/tests.strings.cpp @@ -8,8 +8,10 @@ using namespace Microsoft::VisualStudio::CppUnitTestFramework; -namespace UnitTest1 { - class StringsTest : public TestClass { +namespace UnitTest1 +{ + class StringsTest : public TestClass + { TEST_METHOD(b64url_encode) { using u64 = std::uint64_t; @@ -29,7 +31,8 @@ namespace UnitTest1 { map.emplace_back(0xFFFF'FFFF'FFFF'FFFF, "777777777777P"); std::string result; - for (const auto& pr : map) { + for (const auto& pr : map) + { result = vcpkg::Strings::b32_encode(pr.first); Assert::AreEqual(result, pr.second); } diff --git a/toolsrc/src/vcpkg/base/strings.cpp b/toolsrc/src/vcpkg/base/strings.cpp index 7970e1b46..46e78a363 100644 --- a/toolsrc/src/vcpkg/base/strings.cpp +++ b/toolsrc/src/vcpkg/base/strings.cpp @@ -301,7 +301,8 @@ namespace vcpkg::Strings auto value = static_cast(x); // 32 values, plus the implicit \0 - constexpr static char map[33] = "ABCDEFGHIJKLMNOP" "QRSTUVWXYZ234567"; + constexpr static char map[33] = "ABCDEFGHIJKLMNOP" + "QRSTUVWXYZ234567"; // log2(32) constexpr static int shift = 5; diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index c50acce7e..66d8dae2c 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -363,8 +363,7 @@ namespace vcpkg::Build const Triplet& triplet = spec.triplet(); const auto& triplet_file_path = paths.get_triplet_file_path(spec.triplet()).u8string(); - if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, - paths.triplets.u8string())) + if (!Strings::case_insensitive_ascii_starts_with(triplet_file_path, paths.triplets.u8string())) { System::printf("-- Loading triplet configuration from: %s\n", triplet_file_path); } @@ -431,12 +430,11 @@ namespace vcpkg::Build } command.append(cmd_launch_cmake); const auto timer = Chrono::ElapsedTimer::create_started(); - const int return_code = System::cmd_execute_clean( - command, - {} + const int return_code = System::cmd_execute_clean(command, + {} #ifdef _WIN32 - , - powershell_exe_path.parent_path().u8string() + ";" + , + powershell_exe_path.parent_path().u8string() + ";" #endif ); const auto buildtimeus = timer.microseconds(); @@ -1020,8 +1018,7 @@ namespace vcpkg::Build hash += "-"; hash += Hash::get_file_hash(fs, *p, "SHA1"); } - else if (pre_build_info.cmake_system_name.empty() || - pre_build_info.cmake_system_name == "WindowsStore") + else if (pre_build_info.cmake_system_name.empty() || pre_build_info.cmake_system_name == "WindowsStore") { hash += "-"; hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "windows.cmake", "SHA1"); -- cgit v1.2.3 From 825055378998ae6bc24e8cb0bce2e1fbf9a425da Mon Sep 17 00:00:00 2001 From: nicole mazzuca Date: Thu, 18 Jul 2019 19:07:00 -0700 Subject: Rewrite the tests! now they're cross-platform! (#7315) * begin exploratory rewriting of tests * continue working on tests * more test work! holy butts vcpkg-tests/plan.cpp was a bunch of work * finish writing new tests - [x] write catch2 tests - [ ] rewrite/at least delete the VS project files - [ ] document running tests * Fix tests to work on WSL, rewrite test vcxproj still need to test on macOS also, delete tests.pch.h * Condense add_test calls --- toolsrc/src/tests.arguments.cpp | 104 --- toolsrc/src/tests.chrono.cpp | 41 - toolsrc/src/tests.dependencies.cpp | 110 --- toolsrc/src/tests.packagespec.cpp | 136 --- toolsrc/src/tests.paragraph.cpp | 441 --------- toolsrc/src/tests.pch.cpp | 1 - toolsrc/src/tests.plan.cpp | 1261 -------------------------- toolsrc/src/tests.statusparagraphs.cpp | 115 --- toolsrc/src/tests.update.cpp | 106 --- toolsrc/src/tests.utils.cpp | 42 - toolsrc/src/vcpkg-tests/arguments.cpp | 109 +++ toolsrc/src/vcpkg-tests/catch.cpp | 11 + toolsrc/src/vcpkg-tests/chrono.cpp | 34 + toolsrc/src/vcpkg-tests/dependencies.cpp | 28 + toolsrc/src/vcpkg-tests/paragraph.cpp | 445 +++++++++ toolsrc/src/vcpkg-tests/plan.cpp | 1241 +++++++++++++++++++++++++ toolsrc/src/vcpkg-tests/specifier.cpp | 134 +++ toolsrc/src/vcpkg-tests/statusparagraphs.cpp | 110 +++ toolsrc/src/vcpkg-tests/supports.cpp | 79 ++ toolsrc/src/vcpkg-tests/update.cpp | 102 +++ toolsrc/src/vcpkg-tests/util.cpp | 47 + 21 files changed, 2340 insertions(+), 2357 deletions(-) delete mode 100644 toolsrc/src/tests.arguments.cpp delete mode 100644 toolsrc/src/tests.chrono.cpp delete mode 100644 toolsrc/src/tests.dependencies.cpp delete mode 100644 toolsrc/src/tests.packagespec.cpp delete mode 100644 toolsrc/src/tests.paragraph.cpp delete mode 100644 toolsrc/src/tests.pch.cpp delete mode 100644 toolsrc/src/tests.plan.cpp delete mode 100644 toolsrc/src/tests.statusparagraphs.cpp delete mode 100644 toolsrc/src/tests.update.cpp delete mode 100644 toolsrc/src/tests.utils.cpp create mode 100644 toolsrc/src/vcpkg-tests/arguments.cpp create mode 100644 toolsrc/src/vcpkg-tests/catch.cpp create mode 100644 toolsrc/src/vcpkg-tests/chrono.cpp create mode 100644 toolsrc/src/vcpkg-tests/dependencies.cpp create mode 100644 toolsrc/src/vcpkg-tests/paragraph.cpp create mode 100644 toolsrc/src/vcpkg-tests/plan.cpp create mode 100644 toolsrc/src/vcpkg-tests/specifier.cpp create mode 100644 toolsrc/src/vcpkg-tests/statusparagraphs.cpp create mode 100644 toolsrc/src/vcpkg-tests/supports.cpp create mode 100644 toolsrc/src/vcpkg-tests/update.cpp create mode 100644 toolsrc/src/vcpkg-tests/util.cpp (limited to 'toolsrc/src') diff --git a/toolsrc/src/tests.arguments.cpp b/toolsrc/src/tests.arguments.cpp deleted file mode 100644 index e108b983a..000000000 --- a/toolsrc/src/tests.arguments.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "tests.pch.h" - -#if defined(_WIN32) -#pragma comment(lib, "version") -#pragma comment(lib, "winhttp") -#endif - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - -using namespace vcpkg; - -namespace UnitTest1 -{ - class ArgumentTests : public TestClass - { - TEST_METHOD(create_from_arg_sequence_options_lower) - { - std::vector t = { - "--vcpkg-root", "C:\\vcpkg", - "--scripts-root=C:\\scripts", - "--debug", - "--sendmetrics", - "--printmetrics", - "--overlay-ports=C:\\ports1", - "--overlay-ports=C:\\ports2", - "--overlay-triplets=C:\\tripletsA", - "--overlay-triplets=C:\\tripletsB" - }; - auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); - Assert::AreEqual("C:\\vcpkg", v.vcpkg_root_dir.get()->c_str()); - Assert::AreEqual("C:\\scripts", v.scripts_root_dir.get()->c_str()); - Assert::IsTrue(v.debug && *v.debug.get()); - Assert::IsTrue(v.sendmetrics && v.sendmetrics.get()); - Assert::IsTrue(v.printmetrics && *v.printmetrics.get()); - - Assert::IsTrue(v.overlay_ports.get()->size() == 2); - Assert::AreEqual("C:\\ports1", v.overlay_ports.get()->at(0).c_str()); - Assert::AreEqual("C:\\ports2", v.overlay_ports.get()->at(1).c_str()); - - Assert::IsTrue(v.overlay_triplets.get()->size() == 2); - Assert::AreEqual("C:\\tripletsA", v.overlay_triplets.get()->at(0).c_str()); - Assert::AreEqual("C:\\tripletsB", v.overlay_triplets.get()->at(1).c_str()); - } - - TEST_METHOD(create_from_arg_sequence_options_upper) - { - std::vector t = { - "--VCPKG-ROOT", "C:\\vcpkg", - "--SCRIPTS-ROOT=C:\\scripts", - "--DEBUG", - "--SENDMETRICS", - "--PRINTMETRICS", - "--OVERLAY-PORTS=C:\\ports1", - "--OVERLAY-PORTS=C:\\ports2", - "--OVERLAY-TRIPLETS=C:\\tripletsA", - "--OVERLAY-TRIPLETS=C:\\tripletsB" - }; - auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); - Assert::AreEqual("C:\\vcpkg", v.vcpkg_root_dir.get()->c_str()); - Assert::AreEqual("C:\\scripts", v.scripts_root_dir.get()->c_str()); - Assert::IsTrue(v.debug && *v.debug.get()); - Assert::IsTrue(v.sendmetrics && v.sendmetrics.get()); - Assert::IsTrue(v.printmetrics && *v.printmetrics.get()); - - Assert::IsTrue(v.overlay_ports.get()->size() == 2); - Assert::AreEqual("C:\\ports1", v.overlay_ports.get()->at(0).c_str()); - Assert::AreEqual("C:\\ports2", v.overlay_ports.get()->at(1).c_str()); - - Assert::IsTrue(v.overlay_triplets.get()->size() == 2); - Assert::AreEqual("C:\\tripletsA", v.overlay_triplets.get()->at(0).c_str()); - Assert::AreEqual("C:\\tripletsB", v.overlay_triplets.get()->at(1).c_str()); - } - - TEST_METHOD(create_from_arg_sequence_valued_options) - { - std::array settings = {{{"--a", ""}}}; - CommandStructure cmdstruct = {"", 0, SIZE_MAX, {{}, settings}, nullptr}; - - std::vector t = {"--a=b", "command", "argument"}; - auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); - auto opts = v.parse_arguments(cmdstruct); - Assert::AreEqual("b", opts.settings["--a"].c_str()); - Assert::AreEqual(size_t{1}, v.command_arguments.size()); - Assert::AreEqual("argument", v.command_arguments[0].c_str()); - Assert::AreEqual("command", v.command.c_str()); - } - - TEST_METHOD(create_from_arg_sequence_valued_options2) - { - std::array switches = {{{"--a", ""}, {"--c", ""}}}; - std::array settings = {{{"--b", ""}, {"--d", ""}}}; - CommandStructure cmdstruct = {"", 0, SIZE_MAX, {switches, settings}, nullptr}; - - std::vector t = {"--a", "--b=c"}; - auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); - auto opts = v.parse_arguments(cmdstruct); - Assert::AreEqual("c", opts.settings["--b"].c_str()); - Assert::IsTrue(opts.settings.find("--d") == opts.settings.end()); - Assert::IsTrue(opts.switches.find("--a") != opts.switches.end()); - Assert::IsTrue(opts.settings.find("--c") == opts.settings.end()); - Assert::AreEqual(size_t{0}, v.command_arguments.size()); - } - }; -} diff --git a/toolsrc/src/tests.chrono.cpp b/toolsrc/src/tests.chrono.cpp deleted file mode 100644 index 269cdca58..000000000 --- a/toolsrc/src/tests.chrono.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "tests.pch.h" - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - -namespace Chrono = vcpkg::Chrono; - -namespace UnitTest1 -{ - class ChronoTests : public TestClass - { - TEST_METHOD(parse_time) - { - auto timestring = "1990-02-03T04:05:06.0Z"; - auto maybe_time = Chrono::CTime::parse(timestring); - - Assert::IsTrue(maybe_time.has_value()); - - Assert::AreEqual(timestring, maybe_time.get()->to_string().c_str()); - } - - TEST_METHOD(parse_time_blank) - { - auto maybe_time = Chrono::CTime::parse(""); - - Assert::IsFalse(maybe_time.has_value()); - } - - TEST_METHOD(time_difference) - { - auto maybe_time1 = Chrono::CTime::parse("1990-02-03T04:05:06.0Z"); - auto maybe_time2 = Chrono::CTime::parse("1990-02-10T04:05:06.0Z"); - - Assert::IsTrue(maybe_time1.has_value()); - Assert::IsTrue(maybe_time2.has_value()); - - auto delta = maybe_time2.get()->to_time_point() - maybe_time1.get()->to_time_point(); - - Assert::AreEqual(24 * 7, std::chrono::duration_cast(delta).count()); - } - }; -} diff --git a/toolsrc/src/tests.dependencies.cpp b/toolsrc/src/tests.dependencies.cpp deleted file mode 100644 index 7d8283ed6..000000000 --- a/toolsrc/src/tests.dependencies.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "tests.pch.h" - -#if defined(_WIN32) -#pragma comment(lib, "version") -#pragma comment(lib, "winhttp") -#endif - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - -using namespace vcpkg; -using Parse::parse_comma_list; - -namespace UnitTest1 -{ - class DependencyTests : public TestClass - { - TEST_METHOD(parse_depends_one) - { - auto v = expand_qualified_dependencies(parse_comma_list("libA (windows)")); - Assert::AreEqual(size_t(1), v.size()); - Assert::AreEqual("libA", v[0].depend.name.c_str()); - Assert::AreEqual("windows", v[0].qualifier.c_str()); - } - - TEST_METHOD(filter_depends) - { - auto deps = expand_qualified_dependencies(parse_comma_list("libA (windows), libB, libC (uwp)")); - auto v = filter_dependencies(deps, Triplet::X64_WINDOWS); - Assert::AreEqual(size_t(2), v.size()); - Assert::AreEqual("libA", v[0].c_str()); - Assert::AreEqual("libB", v[1].c_str()); - - auto v2 = filter_dependencies(deps, Triplet::ARM_UWP); - Assert::AreEqual(size_t(2), v.size()); - Assert::AreEqual("libB", v2[0].c_str()); - Assert::AreEqual("libC", v2[1].c_str()); - } - }; - - class SupportsTests : public TestClass - { - TEST_METHOD(parse_supports_all) - { - auto v = Supports::parse({ - "x64", - "x86", - "arm", - "windows", - "uwp", - "v140", - "v141", - "crt-static", - "crt-dynamic", - }); - Assert::AreNotEqual(uintptr_t(0), uintptr_t(v.get())); - - Assert::IsTrue(v.get()->is_supported(System::CPUArchitecture::X64, - Supports::Platform::UWP, - Supports::Linkage::DYNAMIC, - Supports::ToolsetVersion::V140)); - Assert::IsTrue(v.get()->is_supported(System::CPUArchitecture::ARM, - Supports::Platform::WINDOWS, - Supports::Linkage::STATIC, - Supports::ToolsetVersion::V141)); - } - - TEST_METHOD(parse_supports_invalid) - { - auto v = Supports::parse({"arm64"}); - Assert::AreEqual(uintptr_t(0), uintptr_t(v.get())); - Assert::AreEqual(size_t(1), v.error().size()); - Assert::AreEqual("arm64", v.error()[0].c_str()); - } - - TEST_METHOD(parse_supports_case_sensitive) - { - auto v = Supports::parse({"Windows"}); - Assert::AreEqual(uintptr_t(0), uintptr_t(v.get())); - Assert::AreEqual(size_t(1), v.error().size()); - Assert::AreEqual("Windows", v.error()[0].c_str()); - } - - TEST_METHOD(parse_supports_some) - { - auto v = Supports::parse({ - "x64", - "x86", - "windows", - }); - Assert::AreNotEqual(uintptr_t(0), uintptr_t(v.get())); - - Assert::IsTrue(v.get()->is_supported(System::CPUArchitecture::X64, - Supports::Platform::WINDOWS, - Supports::Linkage::DYNAMIC, - Supports::ToolsetVersion::V140)); - Assert::IsFalse(v.get()->is_supported(System::CPUArchitecture::ARM, - Supports::Platform::WINDOWS, - Supports::Linkage::DYNAMIC, - Supports::ToolsetVersion::V140)); - Assert::IsFalse(v.get()->is_supported(System::CPUArchitecture::X64, - Supports::Platform::UWP, - Supports::Linkage::DYNAMIC, - Supports::ToolsetVersion::V140)); - Assert::IsTrue(v.get()->is_supported(System::CPUArchitecture::X64, - Supports::Platform::WINDOWS, - Supports::Linkage::STATIC, - Supports::ToolsetVersion::V141)); - } - }; -} diff --git a/toolsrc/src/tests.packagespec.cpp b/toolsrc/src/tests.packagespec.cpp deleted file mode 100644 index d3bc18c79..000000000 --- a/toolsrc/src/tests.packagespec.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "tests.pch.h" - -#include - -#if defined(_WIN32) -#pragma comment(lib, "version") -#pragma comment(lib, "winhttp") -#endif - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - -namespace UnitTest1 -{ - using namespace vcpkg; - - class SpecifierConversion : public TestClass - { - TEST_METHOD(full_package_spec_to_feature_specs) - { - auto a_spec = PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - auto b_spec = PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - - auto fspecs = FullPackageSpec::to_feature_specs({{a_spec, {"0", "1"}}, {b_spec, {"2", "3"}}}); - - Assert::AreEqual(size_t(6), fspecs.size()); - - std::array features = {"", "0", "1", "", "2", "3"}; - std::array specs = {&a_spec, &a_spec, &a_spec, &b_spec, &b_spec, &b_spec}; - - for (size_t i = 0; i < features.size(); ++i) - { - Assert::AreEqual(features[i], fspecs[i].feature().c_str()); - Assert::AreEqual(*specs[i], fspecs[i].spec()); - } - } - }; - - class SpecifierParsing : public TestClass - { - TEST_METHOD(parsed_specifier_from_string) - { - auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib"); - Assert::AreEqual(vcpkg::PackageSpecParseResult::SUCCESS, maybe_spec.error()); - auto spec = maybe_spec.get(); - Assert::AreEqual("zlib", spec->name.c_str()); - Assert::AreEqual(size_t(0), spec->features.size()); - Assert::AreEqual("", spec->triplet.c_str()); - } - - TEST_METHOD(parsed_specifier_from_string_with_triplet) - { - auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib:x64-uwp"); - Assert::AreEqual(vcpkg::PackageSpecParseResult::SUCCESS, maybe_spec.error()); - auto spec = maybe_spec.get(); - Assert::AreEqual("zlib", spec->name.c_str()); - Assert::AreEqual("x64-uwp", spec->triplet.c_str()); - } - - TEST_METHOD(parsed_specifier_from_string_with_colons) - { - auto ec = vcpkg::ParsedSpecifier::from_string("zlib:x86-uwp:").error(); - Assert::AreEqual(vcpkg::PackageSpecParseResult::TOO_MANY_COLONS, ec); - } - - TEST_METHOD(parsed_specifier_from_string_with_feature) - { - auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[feature]:x64-uwp"); - Assert::AreEqual(vcpkg::PackageSpecParseResult::SUCCESS, maybe_spec.error()); - auto spec = maybe_spec.get(); - Assert::AreEqual("zlib", spec->name.c_str()); - Assert::IsTrue(spec->features.size() == 1); - Assert::AreEqual("feature", spec->features.front().c_str()); - Assert::AreEqual("x64-uwp", spec->triplet.c_str()); - } - - TEST_METHOD(parsed_specifier_from_string_with_many_features) - { - auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[0, 1,2]"); - Assert::AreEqual(vcpkg::PackageSpecParseResult::SUCCESS, maybe_spec.error()); - auto spec = maybe_spec.get(); - Assert::AreEqual("zlib", spec->name.c_str()); - Assert::IsTrue(spec->features.size() == 3); - Assert::AreEqual("0", spec->features[0].c_str()); - Assert::AreEqual("1", spec->features[1].c_str()); - Assert::AreEqual("2", spec->features[2].c_str()); - Assert::AreEqual("", spec->triplet.c_str()); - } - - TEST_METHOD(parsed_specifier_wildcard_feature) - { - auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[*]"); - Assert::AreEqual(vcpkg::PackageSpecParseResult::SUCCESS, maybe_spec.error()); - auto spec = maybe_spec.get(); - Assert::AreEqual("zlib", spec->name.c_str()); - Assert::IsTrue(spec->features.size() == 1); - Assert::AreEqual("*", spec->features[0].c_str()); - Assert::AreEqual("", spec->triplet.c_str()); - } - - TEST_METHOD(expand_wildcards) - { - auto zlib = - vcpkg::FullPackageSpec::from_string("zlib[0,1]", Triplet::X86_UWP).value_or_exit(VCPKG_LINE_INFO); - auto openssl = - vcpkg::FullPackageSpec::from_string("openssl[*]", Triplet::X86_UWP).value_or_exit(VCPKG_LINE_INFO); - auto specs = FullPackageSpec::to_feature_specs({zlib, openssl}); - Util::sort(specs); - auto spectargets = FeatureSpec::from_strings_and_triplet( - { - "openssl", - "zlib", - "openssl[*]", - "zlib[0]", - "zlib[1]", - }, - Triplet::X86_UWP); - Util::sort(spectargets); - Assert::IsTrue(specs.size() == spectargets.size()); - Assert::IsTrue(Util::all_equal(specs, spectargets)); - } - - TEST_METHOD(utf8_to_utf16) - { - auto str = vcpkg::Strings::to_utf16("abc"); - Assert::AreEqual(L"abc", str.c_str()); - } - - TEST_METHOD(utf8_to_utf16_with_whitespace) - { - auto str = vcpkg::Strings::to_utf16("abc -x86-windows"); - Assert::AreEqual(L"abc -x86-windows", str.c_str()); - } - }; - - TEST_CLASS(Metrics){}; -} diff --git a/toolsrc/src/tests.paragraph.cpp b/toolsrc/src/tests.paragraph.cpp deleted file mode 100644 index e99d07694..000000000 --- a/toolsrc/src/tests.paragraph.cpp +++ /dev/null @@ -1,441 +0,0 @@ -#include "tests.pch.h" - -#if defined(_WIN32) -#pragma comment(lib, "version") -#pragma comment(lib, "winhttp") -#endif - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - -namespace Strings = vcpkg::Strings; - -namespace UnitTest1 -{ - class ControlParsing : public TestClass - { - TEST_METHOD(SourceParagraph_Construct_Minimum) - { - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - }}); - - Assert::IsTrue(m_pgh.has_value()); - auto& pgh = *m_pgh.get(); - - Assert::AreEqual("zlib", pgh->core_paragraph->name.c_str()); - Assert::AreEqual("1.2.8", pgh->core_paragraph->version.c_str()); - Assert::AreEqual("", pgh->core_paragraph->maintainer.c_str()); - Assert::AreEqual("", pgh->core_paragraph->description.c_str()); - Assert::AreEqual(size_t(0), pgh->core_paragraph->depends.size()); - } - - TEST_METHOD(SourceParagraph_Construct_Maximum) - { - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "s"}, - {"Version", "v"}, - {"Maintainer", "m"}, - {"Description", "d"}, - {"Build-Depends", "bd"}, - {"Default-Features", "df"}, - {"Supports", "x64"}, - }}); - Assert::IsTrue(m_pgh.has_value()); - auto& pgh = *m_pgh.get(); - - Assert::AreEqual("s", pgh->core_paragraph->name.c_str()); - Assert::AreEqual("v", pgh->core_paragraph->version.c_str()); - Assert::AreEqual("m", pgh->core_paragraph->maintainer.c_str()); - Assert::AreEqual("d", pgh->core_paragraph->description.c_str()); - Assert::AreEqual(size_t(1), pgh->core_paragraph->depends.size()); - Assert::AreEqual("bd", pgh->core_paragraph->depends[0].name().c_str()); - Assert::AreEqual(size_t(1), pgh->core_paragraph->default_features.size()); - Assert::AreEqual("df", pgh->core_paragraph->default_features[0].c_str()); - Assert::AreEqual(size_t(1), pgh->core_paragraph->supports.size()); - Assert::AreEqual("x64", pgh->core_paragraph->supports[0].c_str()); - } - - TEST_METHOD(SourceParagraph_Two_Depends) - { - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - {"Build-Depends", "z, openssl"}, - }}); - Assert::IsTrue(m_pgh.has_value()); - auto& pgh = *m_pgh.get(); - - Assert::AreEqual(size_t(2), pgh->core_paragraph->depends.size()); - Assert::AreEqual("z", pgh->core_paragraph->depends[0].name().c_str()); - Assert::AreEqual("openssl", pgh->core_paragraph->depends[1].name().c_str()); - } - - TEST_METHOD(SourceParagraph_Three_Depends) - { - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - {"Build-Depends", "z, openssl, xyz"}, - }}); - Assert::IsTrue(m_pgh.has_value()); - auto& pgh = *m_pgh.get(); - - Assert::AreEqual(size_t(3), pgh->core_paragraph->depends.size()); - Assert::AreEqual("z", pgh->core_paragraph->depends[0].name().c_str()); - Assert::AreEqual("openssl", pgh->core_paragraph->depends[1].name().c_str()); - Assert::AreEqual("xyz", pgh->core_paragraph->depends[2].name().c_str()); - } - - TEST_METHOD(SourceParagraph_Three_Supports) - { - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - {"Supports", "x64, windows, uwp"}, - }}); - Assert::IsTrue(m_pgh.has_value()); - auto& pgh = *m_pgh.get(); - - Assert::AreEqual(size_t(3), pgh->core_paragraph->supports.size()); - Assert::AreEqual("x64", pgh->core_paragraph->supports[0].c_str()); - Assert::AreEqual("windows", pgh->core_paragraph->supports[1].c_str()); - Assert::AreEqual("uwp", pgh->core_paragraph->supports[2].c_str()); - } - - TEST_METHOD(SourceParagraph_Construct_Qualified_Depends) - { - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - {"Build-Depends", "libA (windows), libB (uwp)"}, - }}); - Assert::IsTrue(m_pgh.has_value()); - auto& pgh = *m_pgh.get(); - - Assert::AreEqual("zlib", pgh->core_paragraph->name.c_str()); - Assert::AreEqual("1.2.8", pgh->core_paragraph->version.c_str()); - Assert::AreEqual("", pgh->core_paragraph->maintainer.c_str()); - Assert::AreEqual("", pgh->core_paragraph->description.c_str()); - Assert::AreEqual(size_t(2), pgh->core_paragraph->depends.size()); - Assert::AreEqual("libA", pgh->core_paragraph->depends[0].name().c_str()); - Assert::AreEqual("windows", pgh->core_paragraph->depends[0].qualifier.c_str()); - Assert::AreEqual("libB", pgh->core_paragraph->depends[1].name().c_str()); - Assert::AreEqual("uwp", pgh->core_paragraph->depends[1].qualifier.c_str()); - } - - TEST_METHOD(SourceParagraph_Default_Features) - { - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "a"}, - {"Version", "1.0"}, - {"Default-Features", "a1"}, - }}); - Assert::IsTrue(m_pgh.has_value()); - auto& pgh = *m_pgh.get(); - - Assert::AreEqual(size_t(1), pgh->core_paragraph->default_features.size()); - Assert::AreEqual("a1", pgh->core_paragraph->default_features[0].c_str()); - } - - TEST_METHOD(BinaryParagraph_Construct_Minimum) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - }); - - Assert::AreEqual("zlib", pgh.spec.name().c_str()); - Assert::AreEqual("1.2.8", pgh.version.c_str()); - Assert::AreEqual("", pgh.maintainer.c_str()); - Assert::AreEqual("", pgh.description.c_str()); - Assert::AreEqual("x86-windows", pgh.spec.triplet().canonical_name().c_str()); - Assert::AreEqual(size_t(0), pgh.depends.size()); - } - - TEST_METHOD(BinaryParagraph_Construct_Maximum) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "s"}, - {"Version", "v"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Maintainer", "m"}, - {"Description", "d"}, - {"Depends", "bd"}, - }); - Assert::AreEqual("s", pgh.spec.name().c_str()); - Assert::AreEqual("v", pgh.version.c_str()); - Assert::AreEqual("m", pgh.maintainer.c_str()); - Assert::AreEqual("d", pgh.description.c_str()); - Assert::AreEqual(size_t(1), pgh.depends.size()); - Assert::AreEqual("bd", pgh.depends[0].c_str()); - } - - TEST_METHOD(BinaryParagraph_Three_Depends) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Depends", "a, b, c"}, - }); - - Assert::AreEqual(size_t(3), pgh.depends.size()); - Assert::AreEqual("a", pgh.depends[0].c_str()); - Assert::AreEqual("b", pgh.depends[1].c_str()); - Assert::AreEqual("c", pgh.depends[2].c_str()); - } - - TEST_METHOD(BinaryParagraph_Abi) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Abi", "abcd123"}, - }); - - Assert::AreEqual(size_t(0), pgh.depends.size()); - Assert::IsTrue(pgh.abi == "abcd123"); - } - - TEST_METHOD(BinaryParagraph_Default_Features) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "a"}, - {"Version", "1.0"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Default-Features", "a1"}, - }); - - Assert::AreEqual(size_t(0), pgh.depends.size()); - Assert::AreEqual(size_t(1), pgh.default_features.size()); - Assert::IsTrue(pgh.default_features[0] == "a1"); - } - - TEST_METHOD(parse_paragraphs_empty) - { - const char* str = ""; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - Assert::IsTrue(pghs.empty()); - } - - TEST_METHOD(parse_paragraphs_one_field) - { - const char* str = "f1: v1"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(1), pghs[0].size()); - Assert::AreEqual("v1", pghs[0]["f1"].c_str()); - } - - TEST_METHOD(parse_paragraphs_one_pgh) - { - const char* str = "f1: v1\n" - "f2: v2"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(2), pghs[0].size()); - Assert::AreEqual("v1", pghs[0]["f1"].c_str()); - Assert::AreEqual("v2", pghs[0]["f2"].c_str()); - } - - TEST_METHOD(parse_paragraphs_two_pgh) - { - const char* str = "f1: v1\n" - "f2: v2\n" - "\n" - "f3: v3\n" - "f4: v4"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(2), pghs.size()); - Assert::AreEqual(size_t(2), pghs[0].size()); - Assert::AreEqual("v1", pghs[0]["f1"].c_str()); - Assert::AreEqual("v2", pghs[0]["f2"].c_str()); - Assert::AreEqual(size_t(2), pghs[1].size()); - Assert::AreEqual("v3", pghs[1]["f3"].c_str()); - Assert::AreEqual("v4", pghs[1]["f4"].c_str()); - } - - TEST_METHOD(parse_paragraphs_field_names) - { - const char* str = "1:\n" - "f:\n" - "F:\n" - "0:\n" - "F-2:\n"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(5), pghs[0].size()); - } - - TEST_METHOD(parse_paragraphs_multiple_blank_lines) - { - const char* str = "f1: v1\n" - "f2: v2\n" - "\n" - "\n" - "f3: v3\n" - "f4: v4"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(2), pghs.size()); - } - - TEST_METHOD(parse_paragraphs_empty_fields) - { - const char* str = "f1:\n" - "f2: "; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(2), pghs[0].size()); - Assert::AreEqual("", pghs[0]["f1"].c_str()); - Assert::AreEqual("", pghs[0]["f2"].c_str()); - Assert::AreEqual(size_t(2), pghs[0].size()); - } - - TEST_METHOD(parse_paragraphs_multiline_fields) - { - const char* str = "f1: simple\n" - " f1\r\n" - "f2:\r\n" - " f2\r\n" - " continue\r\n"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual("simple\n f1", pghs[0]["f1"].c_str()); - Assert::AreEqual("\n f2\n continue", pghs[0]["f2"].c_str()); - } - - TEST_METHOD(parse_paragraphs_crlfs) - { - const char* str = "f1: v1\r\n" - "f2: v2\r\n" - "\r\n" - "f3: v3\r\n" - "f4: v4"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(2), pghs.size()); - Assert::AreEqual(size_t(2), pghs[0].size()); - Assert::AreEqual("v1", pghs[0]["f1"].c_str()); - Assert::AreEqual("v2", pghs[0]["f2"].c_str()); - Assert::AreEqual(size_t(2), pghs[1].size()); - Assert::AreEqual("v3", pghs[1]["f3"].c_str()); - Assert::AreEqual("v4", pghs[1]["f4"].c_str()); - } - - TEST_METHOD(parse_paragraphs_comment) - { - const char* str = "f1: v1\r\n" - "#comment\r\n" - "f2: v2\r\n" - "#comment\r\n" - "\r\n" - "#comment\r\n" - "f3: v3\r\n" - "#comment\r\n" - "f4: v4"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(2), pghs.size()); - Assert::AreEqual(size_t(2), pghs[0].size()); - Assert::AreEqual("v1", pghs[0]["f1"].c_str()); - Assert::AreEqual("v2", pghs[0]["f2"].c_str()); - Assert::AreEqual(size_t(2), pghs[1].size()); - Assert::AreEqual("v3", pghs[1]["f3"].c_str()); - Assert::AreEqual("v4", pghs[1]["f4"].c_str()); - } - - TEST_METHOD(parse_comment_before_single_slashN) - { - const char* str = "f1: v1\r\n" - "#comment\n"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(1), pghs[0].size()); - Assert::AreEqual("v1", pghs[0]["f1"].c_str()); - } - - TEST_METHOD(BinaryParagraph_serialize_min) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - }); - std::string ss = Strings::serialize(pgh); - auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(4), pghs[0].size()); - Assert::AreEqual("zlib", pghs[0]["Package"].c_str()); - Assert::AreEqual("1.2.8", pghs[0]["Version"].c_str()); - Assert::AreEqual("x86-windows", pghs[0]["Architecture"].c_str()); - Assert::AreEqual("same", pghs[0]["Multi-Arch"].c_str()); - } - - TEST_METHOD(BinaryParagraph_serialize_max) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Description", "first line\n second line"}, - {"Maintainer", "abc "}, - {"Depends", "dep"}, - {"Multi-Arch", "same"}, - }); - std::string ss = Strings::serialize(pgh); - auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(7), pghs[0].size()); - Assert::AreEqual("zlib", pghs[0]["Package"].c_str()); - Assert::AreEqual("1.2.8", pghs[0]["Version"].c_str()); - Assert::AreEqual("x86-windows", pghs[0]["Architecture"].c_str()); - Assert::AreEqual("same", pghs[0]["Multi-Arch"].c_str()); - Assert::AreEqual("first line\n second line", pghs[0]["Description"].c_str()); - Assert::AreEqual("dep", pghs[0]["Depends"].c_str()); - } - - TEST_METHOD(BinaryParagraph_serialize_multiple_deps) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Depends", "a, b, c"}, - }); - std::string ss = Strings::serialize(pgh); - auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual("a, b, c", pghs[0]["Depends"].c_str()); - } - - TEST_METHOD(BinaryParagraph_serialize_abi) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Depends", "a, b, c"}, - {"Abi", "123abc"}, - }); - std::string ss = Strings::serialize(pgh); - auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual("123abc", pghs[0]["Abi"].c_str()); - } - }; -} diff --git a/toolsrc/src/tests.pch.cpp b/toolsrc/src/tests.pch.cpp deleted file mode 100644 index bdddab76a..000000000 --- a/toolsrc/src/tests.pch.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "tests.pch.h" diff --git a/toolsrc/src/tests.plan.cpp b/toolsrc/src/tests.plan.cpp deleted file mode 100644 index 9d8717878..000000000 --- a/toolsrc/src/tests.plan.cpp +++ /dev/null @@ -1,1261 +0,0 @@ -#include "tests.pch.h" - -#include - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - -using namespace vcpkg; - -namespace UnitTest1 -{ - static std::unique_ptr make_control_file( - const char* name, - const char* depends, - const std::vector>& features = {}, - const std::vector& default_features = {}) - { - using Pgh = std::unordered_map; - std::vector scf_pghs; - scf_pghs.push_back(Pgh{{"Source", name}, - {"Version", "0"}, - {"Build-Depends", depends}, - {"Default-Features", Strings::join(", ", default_features)}}); - for (auto&& feature : features) - { - scf_pghs.push_back(Pgh{ - {"Feature", feature.first}, - {"Description", "feature"}, - {"Build-Depends", feature.second}, - }); - } - auto m_pgh = vcpkg::SourceControlFile::parse_control_file(std::move(scf_pghs)); - Assert::IsTrue(m_pgh.has_value()); - return std::move(*m_pgh.get()); - } - - /// - /// Assert that the given action an install of given features from given package. - /// - static void features_check(Dependencies::AnyAction* install_action, - std::string pkg_name, - std::vector vec, - const Triplet& triplet = Triplet::X86_WINDOWS) - { - Assert::IsTrue(install_action->install_action.has_value()); - const auto& plan = install_action->install_action.value_or_exit(VCPKG_LINE_INFO); - const auto& feature_list = plan.feature_list; - - Assert::AreEqual(plan.spec.triplet().to_string().c_str(), triplet.to_string().c_str()); - - auto* scfl = plan.source_control_file_location.get(); - Assert::AreEqual(pkg_name.c_str(), scfl->source_control_file->core_paragraph->name.c_str()); - Assert::AreEqual(size_t(vec.size()), feature_list.size()); - - for (auto&& feature_name : vec) - { - if (feature_name == "core" || feature_name == "") - { - Assert::IsTrue(Util::find(feature_list, "core") != feature_list.end() || - Util::find(feature_list, "") != feature_list.end()); - continue; - } - Assert::IsTrue(Util::find(feature_list, feature_name) != feature_list.end()); - } - } - - /// - /// Assert that the given action is a remove of given package. - /// - static void remove_plan_check(Dependencies::AnyAction* remove_action, - std::string pkg_name, - const Triplet& triplet = Triplet::X86_WINDOWS) - { - const auto& plan = remove_action->remove_action.value_or_exit(VCPKG_LINE_INFO); - Assert::AreEqual(plan.spec.triplet().to_string().c_str(), triplet.to_string().c_str()); - Assert::AreEqual(pkg_name.c_str(), plan.spec.name().c_str()); - } - - /// - /// Map of source control files by their package name. - /// - struct PackageSpecMap - { - std::unordered_map map; - Triplet triplet; - PackageSpecMap(const Triplet& t = Triplet::X86_WINDOWS) noexcept { triplet = t; } - - PackageSpec emplace(const char* name, - const char* depends = "", - const std::vector>& features = {}, - const std::vector& default_features = {}) - { - auto scfl = SourceControlFileLocation { make_control_file(name, depends, features, default_features), "" }; - return emplace(std::move(scfl)); - } - - PackageSpec emplace(vcpkg::SourceControlFileLocation&& scfl) - { - auto spec = PackageSpec::from_name_and_triplet(scfl.source_control_file->core_paragraph->name, triplet); - Assert::IsTrue(spec.has_value()); - map.emplace(scfl.source_control_file->core_paragraph->name, std::move(scfl)); - return PackageSpec{*spec.get()}; - } - }; - - class InstallPlanTests : public TestClass - { - TEST_METHOD(basic_install_scheme) - { - std::vector> status_paragraphs; - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "b"); - auto spec_b = spec_map.emplace("b", "c"); - auto spec_c = spec_map.emplace("c"); - - Dependencies::MapPortFileProvider map_port(spec_map.map); - auto install_plan = Dependencies::create_feature_install_plan( - map_port, {FeatureSpec{spec_a, ""}}, StatusParagraphs(std::move(status_paragraphs))); - - Assert::AreEqual(size_t(3), install_plan.size()); - Assert::AreEqual("c", install_plan[0].spec().name().c_str()); - Assert::AreEqual("b", install_plan[1].spec().name().c_str()); - Assert::AreEqual("a", install_plan[2].spec().name().c_str()); - } - - TEST_METHOD(multiple_install_scheme) - { - std::vector> status_paragraphs; - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "d"); - auto spec_b = spec_map.emplace("b", "d, e"); - auto spec_c = spec_map.emplace("c", "e, h"); - auto spec_d = spec_map.emplace("d", "f, g, h"); - auto spec_e = spec_map.emplace("e", "g"); - auto spec_f = spec_map.emplace("f"); - auto spec_g = spec_map.emplace("g"); - auto spec_h = spec_map.emplace("h"); - - Dependencies::MapPortFileProvider map_port(spec_map.map); - auto install_plan = Dependencies::create_feature_install_plan( - map_port, - {FeatureSpec{spec_a, ""}, FeatureSpec{spec_b, ""}, FeatureSpec{spec_c, ""}}, - StatusParagraphs(std::move(status_paragraphs))); - - auto iterator_pos = [&](const PackageSpec& spec) -> int { - auto it = std::find_if( - install_plan.begin(), install_plan.end(), [&](auto& action) { return action.spec() == spec; }); - Assert::IsTrue(it != install_plan.end()); - return (int)(it - install_plan.begin()); - }; - - int a_pos = iterator_pos(spec_a), b_pos = iterator_pos(spec_b), c_pos = iterator_pos(spec_c), - d_pos = iterator_pos(spec_d), e_pos = iterator_pos(spec_e), f_pos = iterator_pos(spec_f), - g_pos = iterator_pos(spec_g), h_pos = iterator_pos(spec_h); - - Assert::IsTrue(a_pos > d_pos); - Assert::IsTrue(b_pos > e_pos); - Assert::IsTrue(b_pos > d_pos); - Assert::IsTrue(c_pos > e_pos); - Assert::IsTrue(c_pos > h_pos); - Assert::IsTrue(d_pos > f_pos); - Assert::IsTrue(d_pos > g_pos); - Assert::IsTrue(d_pos > h_pos); - Assert::IsTrue(e_pos > g_pos); - } - - TEST_METHOD(existing_package_scheme) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - - PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a")}; - - auto install_plan = - Dependencies::create_feature_install_plan(spec_map.map, - FullPackageSpec::to_feature_specs({spec_a}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::AreEqual(size_t(1), install_plan.size()); - auto p = install_plan[0].install_action.get(); - Assert::IsNotNull(p); - Assert::AreEqual("a", p->spec.name().c_str()); - Assert::AreEqual(Dependencies::InstallPlanType::ALREADY_INSTALLED, p->plan_type); - Assert::AreEqual(Dependencies::RequestType::USER_REQUESTED, p->request_type); - } - - TEST_METHOD(user_requested_package_scheme) - { - std::vector> status_paragraphs; - - PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b")}; - auto spec_b = FullPackageSpec{spec_map.emplace("b")}; - - auto install_plan = - Dependencies::create_feature_install_plan(spec_map.map, - FullPackageSpec::to_feature_specs({spec_a}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::AreEqual(size_t(2), install_plan.size()); - auto p = install_plan[0].install_action.get(); - Assert::IsNotNull(p); - Assert::AreEqual("b", p->spec.name().c_str()); - Assert::AreEqual(Dependencies::InstallPlanType::BUILD_AND_INSTALL, p->plan_type); - Assert::AreEqual(Dependencies::RequestType::AUTO_SELECTED, p->request_type); - - auto p2 = install_plan[1].install_action.get(); - Assert::IsNotNull(p2); - Assert::AreEqual("a", p2->spec.name().c_str()); - Assert::AreEqual(Dependencies::InstallPlanType::BUILD_AND_INSTALL, p2->plan_type); - Assert::AreEqual(Dependencies::RequestType::USER_REQUESTED, p2->request_type); - } - - TEST_METHOD(long_install_scheme) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("j", "k")); - status_paragraphs.push_back(make_status_pgh("k")); - - PackageSpecMap spec_map; - - auto spec_a = spec_map.emplace("a", "b, c, d, e, f, g, h, j, k"); - auto spec_b = spec_map.emplace("b", "c, d, e, f, g, h, j, k"); - auto spec_c = spec_map.emplace("c", "d, e, f, g, h, j, k"); - auto spec_d = spec_map.emplace("d", "e, f, g, h, j, k"); - auto spec_e = spec_map.emplace("e", "f, g, h, j, k"); - auto spec_f = spec_map.emplace("f", "g, h, j, k"); - auto spec_g = spec_map.emplace("g", "h, j, k"); - auto spec_h = spec_map.emplace("h", "j, k"); - auto spec_j = spec_map.emplace("j", "k"); - auto spec_k = spec_map.emplace("k"); - - Dependencies::MapPortFileProvider map_port(spec_map.map); - auto install_plan = Dependencies::create_feature_install_plan( - map_port, {FeatureSpec{spec_a, ""}}, StatusParagraphs(std::move(status_paragraphs))); - - Assert::AreEqual(size_t(8), install_plan.size()); - Assert::AreEqual("h", install_plan[0].spec().name().c_str()); - Assert::AreEqual("g", install_plan[1].spec().name().c_str()); - Assert::AreEqual("f", install_plan[2].spec().name().c_str()); - Assert::AreEqual("e", install_plan[3].spec().name().c_str()); - Assert::AreEqual("d", install_plan[4].spec().name().c_str()); - Assert::AreEqual("c", install_plan[5].spec().name().c_str()); - Assert::AreEqual("b", install_plan[6].spec().name().c_str()); - Assert::AreEqual("a", install_plan[7].spec().name().c_str()); - } - - TEST_METHOD(basic_feature_test_1) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a", "b, b[b1]")); - status_paragraphs.push_back(make_status_pgh("b")); - status_paragraphs.push_back(make_status_feature_pgh("b", "b1")); - - PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b, b[b1]", {{"a1", "b[b2]"}}), {"a1"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})}; - - auto install_plan = - Dependencies::create_feature_install_plan(spec_map.map, - FullPackageSpec::to_feature_specs({spec_a}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::AreEqual(size_t(4), install_plan.size()); - remove_plan_check(&install_plan[0], "a"); - remove_plan_check(&install_plan[1], "b"); - features_check(&install_plan[2], "b", {"b1", "core", "b1"}); - features_check(&install_plan[3], "a", {"a1", "core"}); - } - - TEST_METHOD(basic_feature_test_2) - { - std::vector> status_paragraphs; - - PackageSpecMap spec_map; - - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[b1]", {{"a1", "b[b2]"}}), {"a1"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})}; - - auto install_plan = - Dependencies::create_feature_install_plan(spec_map.map, - FullPackageSpec::to_feature_specs({spec_a}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::AreEqual(size_t(2), install_plan.size()); - features_check(&install_plan[0], "b", {"b1", "b2", "core"}); - features_check(&install_plan[1], "a", {"a1", "core"}); - } - - TEST_METHOD(basic_feature_test_3) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - - PackageSpecMap spec_map; - - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b")}; - auto spec_c = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; - - auto install_plan = - Dependencies::create_feature_install_plan(spec_map.map, - FullPackageSpec::to_feature_specs({spec_c, spec_a}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::AreEqual(size_t(4), install_plan.size()); - remove_plan_check(&install_plan[0], "a"); - features_check(&install_plan[1], "b", {"core"}); - features_check(&install_plan[2], "a", {"a1", "core"}); - features_check(&install_plan[3], "c", {"core"}); - } - - TEST_METHOD(basic_feature_test_4) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.push_back(make_status_feature_pgh("a", "a1", "")); - - PackageSpecMap spec_map; - - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}})}; - auto spec_b = FullPackageSpec{spec_map.emplace("b")}; - auto spec_c = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; - - auto install_plan = - Dependencies::create_feature_install_plan(spec_map.map, - FullPackageSpec::to_feature_specs({spec_c}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::AreEqual(size_t(1), install_plan.size()); - features_check(&install_plan[0], "c", {"core"}); - } - - TEST_METHOD(basic_feature_test_5) - { - std::vector> status_paragraphs; - - PackageSpecMap spec_map; - - auto spec_a = - FullPackageSpec{spec_map.emplace("a", "", {{"a1", "b[b1]"}, {"a2", "b[b2]"}, {"a3", "a[a2]"}}), {"a3"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}})}; - - auto install_plan = - Dependencies::create_feature_install_plan(spec_map.map, - FullPackageSpec::to_feature_specs({spec_a}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::AreEqual(size_t(2), install_plan.size()); - features_check(&install_plan[0], "b", {"core", "b2"}); - features_check(&install_plan[1], "a", {"core", "a3", "a2"}); - } - - TEST_METHOD(basic_feature_test_6) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("b")); - - PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[core]"), {"core"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {"b1"}}; - - auto install_plan = - Dependencies::create_feature_install_plan(spec_map.map, - FullPackageSpec::to_feature_specs({spec_a, spec_b}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::AreEqual(size_t(3), install_plan.size()); - remove_plan_check(&install_plan[0], "b"); - features_check(&install_plan[1], "b", {"core", "b1"}); - features_check(&install_plan[2], "a", {"core"}); - } - - TEST_METHOD(basic_feature_test_7) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("x", "b")); - status_paragraphs.push_back(make_status_pgh("b")); - - PackageSpecMap spec_map; - - auto spec_a = FullPackageSpec{spec_map.emplace("a")}; - auto spec_x = FullPackageSpec{spec_map.emplace("x", "a"), {"core"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {"b1"}}; - - auto install_plan = - Dependencies::create_feature_install_plan(spec_map.map, - FullPackageSpec::to_feature_specs({spec_b}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::AreEqual(size_t(5), install_plan.size()); - remove_plan_check(&install_plan[0], "x"); - remove_plan_check(&install_plan[1], "b"); - - // TODO: order here may change but A < X, and B anywhere - features_check(&install_plan[2], "b", {"core", "b1"}); - features_check(&install_plan[3], "a", {"core"}); - features_check(&install_plan[4], "x", {"core"}); - } - - TEST_METHOD(basic_feature_test_8) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.spec = - PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b")}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; - - spec_map.triplet = Triplet::X86_WINDOWS; - auto spec_a_86 = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; - auto spec_b_86 = FullPackageSpec{spec_map.emplace("b")}; - auto spec_c_86 = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; - - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({spec_c_64, spec_a_86, spec_a_64, spec_c_86}), - StatusParagraphs(std::move(status_paragraphs))); - - remove_plan_check(&install_plan[0], "a", Triplet::X64_WINDOWS); - remove_plan_check(&install_plan[1], "a"); - features_check(&install_plan[2], "b", {"core"}, Triplet::X64_WINDOWS); - features_check(&install_plan[3], "a", {"a1", "core"}, Triplet::X64_WINDOWS); - features_check(&install_plan[4], "c", {"core"}, Triplet::X64_WINDOWS); - features_check(&install_plan[5], "b", {"core"}); - features_check(&install_plan[6], "a", {"a1", "core"}); - features_check(&install_plan[7], "c", {"core"}); - } - - TEST_METHOD(install_all_features_test) - { - std::vector> status_paragraphs; - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}), {"core"}}; - - auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); - Assert::IsTrue(install_specs.has_value()); - if (!install_specs.has_value()) return; - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::IsTrue(install_plan.size() == 1); - features_check(&install_plan[0], "a", {"0", "1", "core"}, Triplet::X64_WINDOWS); - } - - TEST_METHOD(install_default_features_test_1) - { - std::vector> status_paragraphs; - - // Add a port "a" with default features "1" and features "0" and "1". - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}, {"1"}); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect the default feature "1" to be installed, but not "0" - Assert::IsTrue(install_plan.size() == 1); - features_check(&install_plan[0], "a", {"1", "core"}, Triplet::X64_WINDOWS); - } - - TEST_METHOD(install_default_features_test_2) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.spec = - PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - - // Add a port "a" of which "core" is already installed, but we will - // install the default features "explicitly" - // "a" has two features, of which "a1" is default. - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "", {{"a0", ""}, {"a1", ""}}, {"a1"}); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect "a" to get removed for rebuild and then installed with default - // features. - Assert::IsTrue(install_plan.size() == 2); - remove_plan_check(&install_plan[0], "a", Triplet::X64_WINDOWS); - features_check(&install_plan[1], "a", {"a1", "core"}, Triplet::X64_WINDOWS); - } - - TEST_METHOD(install_default_features_test_3) - { - std::vector> status_paragraphs; - - // "a" has two features, of which "a1" is default. - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "", {{"a0", ""}, {"a1", ""}}, {"a1"}); - - // Explicitly install "a" without default features - auto install_specs = FullPackageSpec::from_string("a[core]", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect the default feature not to get installed. - Assert::IsTrue(install_plan.size() == 1); - features_check(&install_plan[0], "a", {"core"}, Triplet::X64_WINDOWS); - } - - TEST_METHOD(install_default_features_of_dependency_test_1) - { - std::vector> status_paragraphs; - - // Add a port "a" which depends on the core of "b" - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "b[core]"); - // "b" has two features, of which "b1" is default. - spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect "a" to get installed and defaults of "b" through the dependency, - // as no explicit features of "b" are installed by the user. - Assert::IsTrue(install_plan.size() == 2); - features_check(&install_plan[0], "b", {"b1", "core"}, Triplet::X64_WINDOWS); - features_check(&install_plan[1], "a", {"core"}, Triplet::X64_WINDOWS); - } - - TEST_METHOD(do_not_install_default_features_of_existing_dependency) - { - // Add a port "a" which depends on the core of "b" - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "b[core]"); - // "b" has two features, of which "b1" is default. - spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); - - std::vector> status_paragraphs; - // "b[core]" is already installed - status_paragraphs.push_back(make_status_pgh("b")); - status_paragraphs.back()->package.spec = - PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect "a" to get installed, but not require rebuilding "b" - Assert::IsTrue(install_plan.size() == 1); - features_check(&install_plan[0], "a", {"core"}, Triplet::X64_WINDOWS); - } - - TEST_METHOD(install_default_features_of_dependency_test_2) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("b")); - status_paragraphs.back()->package.spec = - PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - - // Add a port "a" which depends on the core of "b", which was already - // installed explicitly - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "b[core]"); - // "b" has two features, of which "b1" is default. - spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect "a" to get installed, not the defaults of "b", as the required - // dependencies are already there, installed explicitly by the user. - Assert::IsTrue(install_plan.size() == 1); - features_check(&install_plan[0], "a", {"core"}, Triplet::X64_WINDOWS); - } - - TEST_METHOD(install_plan_action_dependencies) - { - std::vector> status_paragraphs; - - // Add a port "a" which depends on the core of "b", which was already - // installed explicitly - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_c = spec_map.emplace("c"); - auto spec_b = spec_map.emplace("b", "c"); - spec_map.emplace("a", "b"); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::IsTrue(install_plan.size() == 3); - features_check(&install_plan[0], "c", {"core"}, Triplet::X64_WINDOWS); - - features_check(&install_plan[1], "b", {"core"}, Triplet::X64_WINDOWS); - Assert::IsTrue(install_plan[1].install_action.get()->computed_dependencies == - std::vector{spec_c}); - - features_check(&install_plan[2], "a", {"core"}, Triplet::X64_WINDOWS); - Assert::IsTrue(install_plan[2].install_action.get()->computed_dependencies == - std::vector{spec_b}); - } - - TEST_METHOD(install_plan_action_dependencies_2) - { - std::vector> status_paragraphs; - - // Add a port "a" which depends on the core of "b", which was already - // installed explicitly - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_c = spec_map.emplace("c"); - auto spec_b = spec_map.emplace("b", "c"); - spec_map.emplace("a", "c, b"); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::IsTrue(install_plan.size() == 3); - features_check(&install_plan[0], "c", {"core"}, Triplet::X64_WINDOWS); - - features_check(&install_plan[1], "b", {"core"}, Triplet::X64_WINDOWS); - Assert::IsTrue(install_plan[1].install_action.get()->computed_dependencies == - std::vector{spec_c}); - - features_check(&install_plan[2], "a", {"core"}, Triplet::X64_WINDOWS); - Assert::IsTrue(install_plan[2].install_action.get()->computed_dependencies == - std::vector{spec_b, spec_c}); - } - - TEST_METHOD(install_plan_action_dependencies_3) - { - std::vector> status_paragraphs; - - // Add a port "a" which depends on the core of "b", which was already - // installed explicitly - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "", {{"0", ""}, {"1", "a[0]"}}, {"1"}); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::IsTrue(install_plan.size() == 1); - features_check(&install_plan[0], "a", {"1", "0", "core"}, Triplet::X64_WINDOWS); - Assert::IsTrue(install_plan[0].install_action.get()->computed_dependencies == std::vector{}); - } - - TEST_METHOD(install_with_default_features) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a", "")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto b_spec = spec_map.emplace("b", "", {{"0", ""}}, {"0"}); - auto a_spec = spec_map.emplace("a", "b[core]", {{"0", ""}}); - - // Install "a" and indicate that "b" should not install default features - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, {FeatureSpec{a_spec, "0"}, FeatureSpec{b_spec, "core"}}, status_db); - - Assert::IsTrue(install_plan.size() == 3); - remove_plan_check(&install_plan[0], "a"); - features_check(&install_plan[1], "b", {"core"}); - features_check(&install_plan[2], "a", {"0", "core"}); - } - - TEST_METHOD(upgrade_with_default_features_1) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a", "", "1")); - pghs.push_back(make_status_feature_pgh("a", "0")); - StatusParagraphs status_db(std::move(pghs)); - - // Add a port "a" of which "core" and "0" are already installed. - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}, {"1"}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - auto plan = graph.serialize(); - - // The upgrade should not install the default feature - Assert::AreEqual(size_t(2), plan.size()); - - Assert::AreEqual("a", plan[0].spec().name().c_str()); - remove_plan_check(&plan[0], "a"); - features_check(&plan[1], "a", {"core", "0"}); - } - - TEST_METHOD(upgrade_with_default_features_2) - { - std::vector> pghs; - // B is currently installed _without_ default feature b0 - pghs.push_back(make_status_pgh("b", "", "b0", "x64-windows")); - pghs.push_back(make_status_pgh("a", "b[core]", "", "x64-windows")); - - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a = spec_map.emplace("a", "b[core]"); - auto spec_b = spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b0", "b1"}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - graph.upgrade(spec_b); - auto plan = graph.serialize(); - - // The upgrade should install the new default feature b1 but not b0 - Assert::AreEqual(size_t(4), plan.size()); - remove_plan_check(&plan[0], "a", Triplet::X64_WINDOWS); - remove_plan_check(&plan[1], "b", Triplet::X64_WINDOWS); - features_check(&plan[2], "b", {"core", "b1"}, Triplet::X64_WINDOWS); - features_check(&plan[3], "a", {"core"}, Triplet::X64_WINDOWS); - } - - TEST_METHOD(upgrade_with_default_features_3) - { - std::vector> pghs; - // note: unrelated package due to x86 triplet - pghs.push_back(make_status_pgh("b", "", "", "x86-windows")); - pghs.push_back(make_status_pgh("a", "", "", "x64-windows")); - - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a = spec_map.emplace("a", "b[core]"); - spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b0"}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - auto plan = graph.serialize(); - - // The upgrade should install the default feature - Assert::AreEqual(size_t(3), plan.size()); - remove_plan_check(&plan[0], "a", Triplet::X64_WINDOWS); - features_check(&plan[1], "b", {"b0", "core"}, Triplet::X64_WINDOWS); - features_check(&plan[2], "a", {"core"}, Triplet::X64_WINDOWS); - } - - TEST_METHOD(upgrade_with_new_default_feature) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a", "", "0", "x86-windows")); - - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"0", ""}, {"1", ""}, {"2", ""}}, {"0", "1"}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - auto plan = graph.serialize(); - - // The upgrade should install the new default feature but not the old default feature 0 - Assert::AreEqual(size_t(2), plan.size()); - remove_plan_check(&plan[0], "a", Triplet::X86_WINDOWS); - features_check(&plan[1], "a", {"core", "1"}, Triplet::X86_WINDOWS); - } - - TEST_METHOD(transitive_features_test) - { - std::vector> status_paragraphs; - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"0", "b[0]"}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "c", {{"0", "c[0]"}}), {"core"}}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; - - auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); - Assert::IsTrue(install_specs.has_value()); - if (!install_specs.has_value()) return; - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::IsTrue(install_plan.size() == 3); - features_check(&install_plan[0], "c", {"0", "core"}, Triplet::X64_WINDOWS); - features_check(&install_plan[1], "b", {"0", "core"}, Triplet::X64_WINDOWS); - features_check(&install_plan[2], "a", {"0", "core"}, Triplet::X64_WINDOWS); - } - - TEST_METHOD(no_transitive_features_test) - { - std::vector> status_paragraphs; - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"0", ""}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "c", {{"0", ""}}), {"core"}}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; - - auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); - Assert::IsTrue(install_specs.has_value()); - if (!install_specs.has_value()) return; - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::IsTrue(install_plan.size() == 3); - features_check(&install_plan[0], "c", {"core"}, Triplet::X64_WINDOWS); - features_check(&install_plan[1], "b", {"core"}, Triplet::X64_WINDOWS); - features_check(&install_plan[2], "a", {"0", "core"}, Triplet::X64_WINDOWS); - } - - TEST_METHOD(only_transitive_features_test) - { - std::vector> status_paragraphs; - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "", {{"0", "b[0]"}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "", {{"0", "c[0]"}}), {"core"}}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; - - auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); - Assert::IsTrue(install_specs.has_value()); - if (!install_specs.has_value()) return; - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - Assert::IsTrue(install_plan.size() == 3); - features_check(&install_plan[0], "c", {"0", "core"}, Triplet::X64_WINDOWS); - features_check(&install_plan[1], "b", {"0", "core"}, Triplet::X64_WINDOWS); - features_check(&install_plan[2], "a", {"0", "core"}, Triplet::X64_WINDOWS); - } - }; - - class RemovePlanTests : public TestClass - { - TEST_METHOD(basic_remove_scheme) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); - - Assert::AreEqual(size_t(1), remove_plan.size()); - Assert::AreEqual("a", remove_plan[0].spec.name().c_str()); - } - - TEST_METHOD(recurse_remove_scheme) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b", "a")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); - - Assert::AreEqual(size_t(2), remove_plan.size()); - Assert::AreEqual("b", remove_plan[0].spec.name().c_str()); - Assert::AreEqual("a", remove_plan[1].spec.name().c_str()); - } - - TEST_METHOD(features_depend_remove_scheme) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b")); - pghs.push_back(make_status_feature_pgh("b", "0", "a")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); - - Assert::AreEqual(size_t(2), remove_plan.size()); - Assert::AreEqual("b", remove_plan[0].spec.name().c_str()); - Assert::AreEqual("a", remove_plan[1].spec.name().c_str()); - } - - TEST_METHOD(features_depend_remove_scheme_once_removed) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("expat")); - pghs.push_back(make_status_pgh("vtk", "expat")); - pghs.push_back(make_status_pgh("opencv")); - pghs.push_back(make_status_feature_pgh("opencv", "vtk", "vtk")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("expat")}, status_db); - - Assert::AreEqual(size_t(3), remove_plan.size()); - Assert::AreEqual("opencv", remove_plan[0].spec.name().c_str()); - Assert::AreEqual("vtk", remove_plan[1].spec.name().c_str()); - Assert::AreEqual("expat", remove_plan[2].spec.name().c_str()); - } - - TEST_METHOD(features_depend_remove_scheme_once_removed_x64) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("expat", "", "", "x64")); - pghs.push_back(make_status_pgh("vtk", "expat", "", "x64")); - pghs.push_back(make_status_pgh("opencv", "", "", "x64")); - pghs.push_back(make_status_feature_pgh("opencv", "vtk", "vtk", "x64")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = Dependencies::create_remove_plan( - {unsafe_pspec("expat", Triplet::from_canonical_name("x64"))}, status_db); - - Assert::AreEqual(size_t(3), remove_plan.size()); - Assert::AreEqual("opencv", remove_plan[0].spec.name().c_str()); - Assert::AreEqual("vtk", remove_plan[1].spec.name().c_str()); - Assert::AreEqual("expat", remove_plan[2].spec.name().c_str()); - } - - TEST_METHOD(features_depend_core_remove_scheme) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("curl", "", "", "x64")); - pghs.push_back(make_status_pgh("cpr", "curl[core]", "", "x64")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = Dependencies::create_remove_plan( - {unsafe_pspec("curl", Triplet::from_canonical_name("x64"))}, status_db); - - Assert::AreEqual(size_t(2), remove_plan.size()); - Assert::AreEqual("cpr", remove_plan[0].spec.name().c_str()); - Assert::AreEqual("curl", remove_plan[1].spec.name().c_str()); - } - - TEST_METHOD(features_depend_core_remove_scheme_2) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("curl", "", "", "x64")); - pghs.push_back(make_status_feature_pgh("curl", "a", "", "x64")); - pghs.push_back(make_status_feature_pgh("curl", "b", "curl[a]", "x64")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = Dependencies::create_remove_plan( - {unsafe_pspec("curl", Triplet::from_canonical_name("x64"))}, status_db); - - Assert::AreEqual(size_t(1), remove_plan.size()); - Assert::AreEqual("curl", remove_plan[0].spec.name().c_str()); - } - }; - - class UpgradePlanTests : public TestClass - { - TEST_METHOD(basic_upgrade_scheme) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - Assert::AreEqual(size_t(2), plan.size()); - Assert::AreEqual("a", plan[0].spec().name().c_str()); - Assert::IsTrue(plan[0].remove_action.has_value()); - Assert::AreEqual("a", plan[1].spec().name().c_str()); - Assert::IsTrue(plan[1].install_action.has_value()); - } - - TEST_METHOD(basic_upgrade_scheme_with_recurse) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b", "a")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - spec_map.emplace("b", "a"); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - Assert::AreEqual(size_t(4), plan.size()); - Assert::AreEqual("b", plan[0].spec().name().c_str()); - Assert::IsTrue(plan[0].remove_action.has_value()); - - Assert::AreEqual("a", plan[1].spec().name().c_str()); - Assert::IsTrue(plan[1].remove_action.has_value()); - - Assert::AreEqual("a", plan[2].spec().name().c_str()); - Assert::IsTrue(plan[2].install_action.has_value()); - - Assert::AreEqual("b", plan[3].spec().name().c_str()); - Assert::IsTrue(plan[3].install_action.has_value()); - } - - TEST_METHOD(basic_upgrade_scheme_with_bystander) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - spec_map.emplace("b", "a"); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - Assert::AreEqual(size_t(2), plan.size()); - Assert::AreEqual("a", plan[0].spec().name().c_str()); - Assert::IsTrue(plan[0].remove_action.has_value()); - Assert::AreEqual("a", plan[1].spec().name().c_str()); - Assert::IsTrue(plan[1].install_action.has_value()); - } - - TEST_METHOD(basic_upgrade_scheme_with_new_dep) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "b"); - spec_map.emplace("b"); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - Assert::AreEqual(size_t(3), plan.size()); - Assert::AreEqual("a", plan[0].spec().name().c_str()); - Assert::IsTrue(plan[0].remove_action.has_value()); - Assert::AreEqual("b", plan[1].spec().name().c_str()); - Assert::IsTrue(plan[1].install_action.has_value()); - Assert::AreEqual("a", plan[2].spec().name().c_str()); - Assert::IsTrue(plan[2].install_action.has_value()); - } - - TEST_METHOD(basic_upgrade_scheme_with_features) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_feature_pgh("a", "a1")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - Assert::AreEqual(size_t(2), plan.size()); - - Assert::AreEqual("a", plan[0].spec().name().c_str()); - Assert::IsTrue(plan[0].remove_action.has_value()); - - features_check(&plan[1], "a", {"core", "a1"}); - } - - TEST_METHOD(basic_upgrade_scheme_with_new_default_feature) - { - // only core of package "a" is installed - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - StatusParagraphs status_db(std::move(pghs)); - - // a1 was added as a default feature and should be installed in upgrade - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}, {"a1"}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - Assert::AreEqual(size_t(2), plan.size()); - - Assert::AreEqual("a", plan[0].spec().name().c_str()); - Assert::IsTrue(plan[0].remove_action.has_value()); - - features_check(&plan[1], "a", {"core", "a1"}); - } - - TEST_METHOD(basic_upgrade_scheme_with_self_features) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_feature_pgh("a", "a1", "")); - pghs.push_back(make_status_feature_pgh("a", "a2", "a[a1]")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"a1", ""}, {"a2", "a[a1]"}}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - Assert::AreEqual(size_t(2), plan.size()); - - Assert::AreEqual("a", plan[0].spec().name().c_str()); - Assert::IsTrue(plan[0].remove_action.has_value()); - - Assert::AreEqual("a", plan[1].spec().name().c_str()); - Assert::IsTrue(plan[1].install_action.has_value()); - Assert::IsTrue(plan[1].install_action.get()->feature_list == std::set{"core", "a1", "a2"}); - } - }; - - class ExportPlanTests : public TestClass - { - TEST_METHOD(basic_export_scheme) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - - auto plan = Dependencies::create_export_plan({spec_a}, status_db); - - Assert::AreEqual(size_t(1), plan.size()); - Assert::AreEqual("a", plan[0].spec.name().c_str()); - Assert::IsTrue(plan[0].plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); - } - - TEST_METHOD(basic_export_scheme_with_recurse) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b", "a")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - auto spec_b = spec_map.emplace("b", "a"); - - auto plan = Dependencies::create_export_plan({spec_b}, status_db); - - Assert::AreEqual(size_t(2), plan.size()); - Assert::AreEqual("a", plan[0].spec.name().c_str()); - Assert::IsTrue(plan[0].plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); - - Assert::AreEqual("b", plan[1].spec.name().c_str()); - Assert::IsTrue(plan[1].plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); - } - - TEST_METHOD(basic_export_scheme_with_bystander) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - auto spec_b = spec_map.emplace("b", "a"); - - auto plan = Dependencies::create_export_plan({spec_a}, status_db); - - Assert::AreEqual(size_t(1), plan.size()); - Assert::AreEqual("a", plan[0].spec.name().c_str()); - Assert::IsTrue(plan[0].plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); - } - - TEST_METHOD(basic_export_scheme_with_missing) - { - StatusParagraphs status_db; - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - - auto plan = Dependencies::create_export_plan({spec_a}, status_db); - - Assert::AreEqual(size_t(1), plan.size()); - Assert::AreEqual("a", plan[0].spec.name().c_str()); - Assert::IsTrue(plan[0].plan_type == Dependencies::ExportPlanType::NOT_BUILT); - } - - TEST_METHOD(basic_export_scheme_with_features) - { - std::vector> pghs; - pghs.push_back(make_status_pgh("b")); - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_feature_pgh("a", "a1", "b[core]")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}); - - auto plan = Dependencies::create_export_plan({spec_a}, status_db); - - Assert::AreEqual(size_t(2), plan.size()); - - Assert::AreEqual("b", plan[0].spec.name().c_str()); - Assert::IsTrue(plan[0].plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); - - Assert::AreEqual("a", plan[1].spec.name().c_str()); - Assert::IsTrue(plan[1].plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); - } - }; -} diff --git a/toolsrc/src/tests.statusparagraphs.cpp b/toolsrc/src/tests.statusparagraphs.cpp deleted file mode 100644 index fa0d54fac..000000000 --- a/toolsrc/src/tests.statusparagraphs.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "tests.pch.h" - -#include - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - -using namespace vcpkg; -using namespace vcpkg::Paragraphs; - -namespace UnitTest1 -{ - class StatusParagraphsTests : public TestClass - { - TEST_METHOD(find_installed) - { - auto pghs = parse_paragraphs(R"( -Package: ffmpeg -Version: 3.3.3 -Architecture: x64-windows -Multi-Arch: same -Description: -Status: install ok installed -)"); - Assert::IsTrue(!!pghs); - if (!pghs) return; - - StatusParagraphs status_db(Util::fmap( - *pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); - - auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); - Assert::IsTrue(it != status_db.end()); - } - - TEST_METHOD(find_not_installed) - { - auto pghs = parse_paragraphs(R"( -Package: ffmpeg -Version: 3.3.3 -Architecture: x64-windows -Multi-Arch: same -Description: -Status: purge ok not-installed -)"); - Assert::IsTrue(!!pghs); - if (!pghs) return; - - StatusParagraphs status_db(Util::fmap( - *pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); - - auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); - Assert::IsTrue(it == status_db.end()); - } - - TEST_METHOD(find_with_feature_packages) - { - auto pghs = parse_paragraphs(R"( -Package: ffmpeg -Version: 3.3.3 -Architecture: x64-windows -Multi-Arch: same -Description: -Status: install ok installed - -Package: ffmpeg -Feature: openssl -Depends: openssl -Architecture: x64-windows -Multi-Arch: same -Description: -Status: purge ok not-installed -)"); - Assert::IsTrue(!!pghs); - if (!pghs) return; - - StatusParagraphs status_db(Util::fmap( - *pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); - - auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); - Assert::IsTrue(it != status_db.end()); - - // Feature "openssl" is not installed and should not be found - auto it1 = status_db.find_installed({unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS), "openssl"}); - Assert::IsTrue(it1 == status_db.end()); - } - - TEST_METHOD(find_for_feature_packages) - { - auto pghs = parse_paragraphs(R"( -Package: ffmpeg -Version: 3.3.3 -Architecture: x64-windows -Multi-Arch: same -Description: -Status: install ok installed - -Package: ffmpeg -Feature: openssl -Depends: openssl -Architecture: x64-windows -Multi-Arch: same -Description: -Status: install ok installed -)"); - Assert::IsTrue(!!pghs); - if (!pghs) return; - - StatusParagraphs status_db(Util::fmap( - *pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); - - // Feature "openssl" is installed and should therefore be found - auto it = status_db.find_installed({unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS), "openssl"}); - Assert::IsTrue(it != status_db.end()); - } - }; -} diff --git a/toolsrc/src/tests.update.cpp b/toolsrc/src/tests.update.cpp deleted file mode 100644 index 5e3f9f3e2..000000000 --- a/toolsrc/src/tests.update.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "tests.pch.h" - -#include - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - -using namespace vcpkg; -using namespace vcpkg::Update; - -namespace UnitTest1 -{ - using Pgh = std::vector>; - - class UpdateTests : public TestClass - { - TEST_METHOD(find_outdated_packages_basic) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.version = "2"; - - StatusParagraphs status_db(std::move(status_paragraphs)); - - std::unordered_map map; - auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); - map.emplace("a", SourceControlFileLocation { std::move(scf), "" }); - Dependencies::MapPortFileProvider provider(map); - - auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), - &OutdatedPackage::compare_by_name); - - Assert::AreEqual(size_t(1), pkgs.size()); - Assert::AreEqual("2", pkgs[0].version_diff.left.to_string().c_str()); - Assert::AreEqual("0", pkgs[0].version_diff.right.to_string().c_str()); - } - - TEST_METHOD(find_outdated_packages_features) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.version = "2"; - - status_paragraphs.push_back(make_status_feature_pgh("a", "b")); - status_paragraphs.back()->package.version = "2"; - - StatusParagraphs status_db(std::move(status_paragraphs)); - - std::unordered_map map; - auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); - map.emplace("a", SourceControlFileLocation { std::move(scf), "" }); - Dependencies::MapPortFileProvider provider(map); - - auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), - &OutdatedPackage::compare_by_name); - - Assert::AreEqual(size_t(1), pkgs.size()); - Assert::AreEqual("2", pkgs[0].version_diff.left.to_string().c_str()); - Assert::AreEqual("0", pkgs[0].version_diff.right.to_string().c_str()); - } - - TEST_METHOD(find_outdated_packages_features_2) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.version = "2"; - - status_paragraphs.push_back(make_status_feature_pgh("a", "b")); - status_paragraphs.back()->package.version = "0"; - status_paragraphs.back()->state = InstallState::NOT_INSTALLED; - status_paragraphs.back()->want = Want::PURGE; - - StatusParagraphs status_db(std::move(status_paragraphs)); - - std::unordered_map map; - auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); - map.emplace("a", SourceControlFileLocation{ std::move(scf), "" }); - Dependencies::MapPortFileProvider provider(map); - - auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), - &OutdatedPackage::compare_by_name); - - Assert::AreEqual(size_t(1), pkgs.size()); - Assert::AreEqual("2", pkgs[0].version_diff.left.to_string().c_str()); - Assert::AreEqual("0", pkgs[0].version_diff.right.to_string().c_str()); - } - - TEST_METHOD(find_outdated_packages_none) - { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.version = "2"; - - StatusParagraphs status_db(std::move(status_paragraphs)); - - std::unordered_map map; - auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "2"}}})); - map.emplace("a", SourceControlFileLocation{ std::move(scf), "" }); - Dependencies::MapPortFileProvider provider(map); - - auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), - &OutdatedPackage::compare_by_name); - - Assert::AreEqual(size_t(0), pkgs.size()); - } - }; -} diff --git a/toolsrc/src/tests.utils.cpp b/toolsrc/src/tests.utils.cpp deleted file mode 100644 index ac391f559..000000000 --- a/toolsrc/src/tests.utils.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "tests.pch.h" - -#include "tests.utils.h" - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; -using namespace vcpkg; - -std::unique_ptr make_status_pgh(const char* name, - const char* depends, - const char* default_features, - const char* triplet) -{ - using Pgh = std::unordered_map; - return std::make_unique(Pgh{{"Package", name}, - {"Version", "1"}, - {"Architecture", triplet}, - {"Multi-Arch", "same"}, - {"Depends", depends}, - {"Default-Features", default_features}, - {"Status", "install ok installed"}}); -} -std::unique_ptr make_status_feature_pgh(const char* name, - const char* feature, - const char* depends, - const char* triplet) -{ - using Pgh = std::unordered_map; - return std::make_unique(Pgh{{"Package", name}, - {"Version", "1"}, - {"Feature", feature}, - {"Architecture", triplet}, - {"Multi-Arch", "same"}, - {"Depends", depends}, - {"Status", "install ok installed"}}); -} - -PackageSpec unsafe_pspec(std::string name, Triplet t) -{ - auto m_ret = PackageSpec::from_name_and_triplet(name, t); - Assert::IsTrue(m_ret.has_value()); - return m_ret.value_or_exit(VCPKG_LINE_INFO); -} diff --git a/toolsrc/src/vcpkg-tests/arguments.cpp b/toolsrc/src/vcpkg-tests/arguments.cpp new file mode 100644 index 000000000..8c625be0f --- /dev/null +++ b/toolsrc/src/vcpkg-tests/arguments.cpp @@ -0,0 +1,109 @@ +#include + +#include + +#include + +using vcpkg::CommandSetting; +using vcpkg::CommandStructure; +using vcpkg::CommandSwitch; +using vcpkg::VcpkgCmdArguments; + +TEST_CASE ("VcpkgCmdArguments from lowercase argument sequence", "[arguments]") +{ + std::vector t = {"--vcpkg-root", + "C:\\vcpkg", + "--scripts-root=C:\\scripts", + "--debug", + "--sendmetrics", + "--printmetrics", + "--overlay-ports=C:\\ports1", + "--overlay-ports=C:\\ports2", + "--overlay-triplets=C:\\tripletsA", + "--overlay-triplets=C:\\tripletsB"}; + auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); + + REQUIRE(*v.vcpkg_root_dir == "C:\\vcpkg"); + REQUIRE(*v.scripts_root_dir == "C:\\scripts"); + REQUIRE(v.debug); + REQUIRE(*v.debug.get()); + REQUIRE(v.sendmetrics); + REQUIRE(*v.sendmetrics.get()); + REQUIRE(v.printmetrics); + REQUIRE(*v.printmetrics.get()); + + REQUIRE(v.overlay_ports->size() == 2); + REQUIRE(v.overlay_ports->at(0) == "C:\\ports1"); + REQUIRE(v.overlay_ports->at(1) == "C:\\ports2"); + + REQUIRE(v.overlay_triplets->size() == 2); + REQUIRE(v.overlay_triplets->at(0) == "C:\\tripletsA"); + REQUIRE(v.overlay_triplets->at(1) == "C:\\tripletsB"); +} + +TEST_CASE ("VcpkgCmdArguments from uppercase argument sequence", "[arguments]") +{ + std::vector t = {"--VCPKG-ROOT", + "C:\\vcpkg", + "--SCRIPTS-ROOT=C:\\scripts", + "--DEBUG", + "--SENDMETRICS", + "--PRINTMETRICS", + "--OVERLAY-PORTS=C:\\ports1", + "--OVERLAY-PORTS=C:\\ports2", + "--OVERLAY-TRIPLETS=C:\\tripletsA", + "--OVERLAY-TRIPLETS=C:\\tripletsB"}; + auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); + + REQUIRE(*v.vcpkg_root_dir == "C:\\vcpkg"); + REQUIRE(*v.scripts_root_dir == "C:\\scripts"); + REQUIRE(v.debug); + REQUIRE(*v.debug.get()); + REQUIRE(v.sendmetrics); + REQUIRE(*v.sendmetrics.get()); + REQUIRE(v.printmetrics); + REQUIRE(*v.printmetrics.get()); + + REQUIRE(v.overlay_ports->size() == 2); + REQUIRE(v.overlay_ports->at(0) == "C:\\ports1"); + REQUIRE(v.overlay_ports->at(1) == "C:\\ports2"); + + REQUIRE(v.overlay_triplets->size() == 2); + REQUIRE(v.overlay_triplets->at(0) == "C:\\tripletsA"); + REQUIRE(v.overlay_triplets->at(1) == "C:\\tripletsB"); +} + +TEST_CASE ("VcpkgCmdArguments from argument sequence with valued options", "[arguments]") +{ + SECTION ("case 1") + { + std::array settings = {{{"--a", ""}}}; + CommandStructure cmdstruct = {"", 0, SIZE_MAX, {{}, settings}, nullptr}; + + std::vector t = {"--a=b", "command", "argument"}; + auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); + auto opts = v.parse_arguments(cmdstruct); + + REQUIRE(opts.settings["--a"] == "b"); + REQUIRE(v.command_arguments.size() == 1); + REQUIRE(v.command_arguments[0] == "argument"); + REQUIRE(v.command == "command"); + } + + SECTION ("case 2") + { + std::array switches = {{{"--a", ""}, {"--c", ""}}}; + std::array settings = {{{"--b", ""}, {"--d", ""}}}; + CommandStructure cmdstruct = {"", 0, SIZE_MAX, {switches, settings}, nullptr}; + + std::vector t = {"--a", "--b=c"}; + auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); + auto opts = v.parse_arguments(cmdstruct); + + REQUIRE(opts.settings["--b"] == "c"); + REQUIRE(opts.settings.find("--d") == opts.settings.end()); + REQUIRE(opts.switches.find("--a") != opts.switches.end()); + REQUIRE(opts.settings.find("--c") == opts.settings.end()); + REQUIRE(v.command_arguments.size() == 0); + } +} diff --git a/toolsrc/src/vcpkg-tests/catch.cpp b/toolsrc/src/vcpkg-tests/catch.cpp new file mode 100644 index 000000000..701dcb39a --- /dev/null +++ b/toolsrc/src/vcpkg-tests/catch.cpp @@ -0,0 +1,11 @@ +#define CATCH_CONFIG_RUNNER +#include + +#include + +int main(int argc, char** argv) +{ + vcpkg::Debug::g_debugging = true; + + return Catch::Session().run(argc, argv); +} diff --git a/toolsrc/src/vcpkg-tests/chrono.cpp b/toolsrc/src/vcpkg-tests/chrono.cpp new file mode 100644 index 000000000..c164753f9 --- /dev/null +++ b/toolsrc/src/vcpkg-tests/chrono.cpp @@ -0,0 +1,34 @@ +#include + +#include + +namespace Chrono = vcpkg::Chrono; + +TEST_CASE ("parse time", "[chrono]") +{ + auto timestring = "1990-02-03T04:05:06.0Z"; + auto maybe_time = Chrono::CTime::parse(timestring); + + REQUIRE(maybe_time.has_value()); + REQUIRE(maybe_time.get()->to_string() == timestring); +} + +TEST_CASE ("parse blank time", "[chrono]") +{ + auto maybe_time = Chrono::CTime::parse(""); + + REQUIRE_FALSE(maybe_time.has_value()); +} + +TEST_CASE ("difference of times", "[chrono]") +{ + auto maybe_time1 = Chrono::CTime::parse("1990-02-03T04:05:06.0Z"); + auto maybe_time2 = Chrono::CTime::parse("1990-02-10T04:05:06.0Z"); + + REQUIRE(maybe_time1.has_value()); + REQUIRE(maybe_time2.has_value()); + + auto delta = maybe_time2.get()->to_time_point() - maybe_time1.get()->to_time_point(); + + REQUIRE(std::chrono::duration_cast(delta).count() == 24 * 7); +} diff --git a/toolsrc/src/vcpkg-tests/dependencies.cpp b/toolsrc/src/vcpkg-tests/dependencies.cpp new file mode 100644 index 000000000..0dee6f296 --- /dev/null +++ b/toolsrc/src/vcpkg-tests/dependencies.cpp @@ -0,0 +1,28 @@ +#include + +#include + +using namespace vcpkg; +using Parse::parse_comma_list; + +TEST_CASE ("parse depends", "[dependencies]") +{ + auto v = expand_qualified_dependencies(parse_comma_list("libA (windows)")); + REQUIRE(v.size() == 1); + REQUIRE(v.at(0).depend.name == "libA"); + REQUIRE(v.at(0).qualifier == "windows"); +} + +TEST_CASE ("filter depends", "[dependencies]") +{ + auto deps = expand_qualified_dependencies(parse_comma_list("libA (windows), libB, libC (uwp)")); + auto v = filter_dependencies(deps, Triplet::X64_WINDOWS); + REQUIRE(v.size() == 2); + REQUIRE(v.at(0) == "libA"); + REQUIRE(v.at(1) == "libB"); + + auto v2 = filter_dependencies(deps, Triplet::ARM_UWP); + REQUIRE(v.size() == 2); + REQUIRE(v2.at(0) == "libB"); + REQUIRE(v2.at(1) == "libC"); +} diff --git a/toolsrc/src/vcpkg-tests/paragraph.cpp b/toolsrc/src/vcpkg-tests/paragraph.cpp new file mode 100644 index 000000000..0fb85ec69 --- /dev/null +++ b/toolsrc/src/vcpkg-tests/paragraph.cpp @@ -0,0 +1,445 @@ +#include +#include + +#include + +#include + +namespace Strings = vcpkg::Strings; + +TEST_CASE ("SourceParagraph construct minimum", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + }}); + + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->name == "zlib"); + REQUIRE(pgh.core_paragraph->version == "1.2.8"); + REQUIRE(pgh.core_paragraph->maintainer == ""); + REQUIRE(pgh.core_paragraph->description == ""); + REQUIRE(pgh.core_paragraph->depends.size() == 0); +} + +TEST_CASE ("SourceParagraph construct maximum", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "s"}, + {"Version", "v"}, + {"Maintainer", "m"}, + {"Description", "d"}, + {"Build-Depends", "bd"}, + {"Default-Features", "df"}, + {"Supports", "x64"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->name == "s"); + REQUIRE(pgh.core_paragraph->version == "v"); + REQUIRE(pgh.core_paragraph->maintainer == "m"); + REQUIRE(pgh.core_paragraph->description == "d"); + REQUIRE(pgh.core_paragraph->depends.size() == 1); + REQUIRE(pgh.core_paragraph->depends[0].name() == "bd"); + REQUIRE(pgh.core_paragraph->default_features.size() == 1); + REQUIRE(pgh.core_paragraph->default_features[0] == "df"); + REQUIRE(pgh.core_paragraph->supports.size() == 1); + REQUIRE(pgh.core_paragraph->supports[0] == "x64"); +} + +TEST_CASE ("SourceParagraph two depends", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + {"Build-Depends", "z, openssl"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->depends.size() == 2); + REQUIRE(pgh.core_paragraph->depends[0].name() == "z"); + REQUIRE(pgh.core_paragraph->depends[1].name() == "openssl"); +} + +TEST_CASE ("SourceParagraph three depends", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + {"Build-Depends", "z, openssl, xyz"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->depends.size() == 3); + REQUIRE(pgh.core_paragraph->depends[0].name() == "z"); + REQUIRE(pgh.core_paragraph->depends[1].name() == "openssl"); + REQUIRE(pgh.core_paragraph->depends[2].name() == "xyz"); +} + +TEST_CASE ("SourceParagraph three supports", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + {"Supports", "x64, windows, uwp"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->supports.size() == 3); + REQUIRE(pgh.core_paragraph->supports[0] == "x64"); + REQUIRE(pgh.core_paragraph->supports[1] == "windows"); + REQUIRE(pgh.core_paragraph->supports[2] == "uwp"); +} + +TEST_CASE ("SourceParagraph construct qualified depends", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + {"Build-Depends", "libA (windows), libB (uwp)"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->name == "zlib"); + REQUIRE(pgh.core_paragraph->version == "1.2.8"); + REQUIRE(pgh.core_paragraph->maintainer == ""); + REQUIRE(pgh.core_paragraph->description == ""); + REQUIRE(pgh.core_paragraph->depends.size() == 2); + REQUIRE(pgh.core_paragraph->depends[0].name() == "libA"); + REQUIRE(pgh.core_paragraph->depends[0].qualifier == "windows"); + REQUIRE(pgh.core_paragraph->depends[1].name() == "libB"); + REQUIRE(pgh.core_paragraph->depends[1].qualifier == "uwp"); +} + +TEST_CASE ("SourceParagraph default features", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "a"}, + {"Version", "1.0"}, + {"Default-Features", "a1"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->default_features.size() == 1); + REQUIRE(pgh.core_paragraph->default_features[0] == "a1"); +} + +TEST_CASE ("BinaryParagraph construct minimum", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + }); + + REQUIRE(pgh.spec.name() == "zlib"); + REQUIRE(pgh.version == "1.2.8"); + REQUIRE(pgh.maintainer == ""); + REQUIRE(pgh.description == ""); + REQUIRE(pgh.spec.triplet().canonical_name() == "x86-windows"); + REQUIRE(pgh.depends.size() == 0); +} + +TEST_CASE ("BinaryParagraph construct maximum", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "s"}, + {"Version", "v"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Maintainer", "m"}, + {"Description", "d"}, + {"Depends", "bd"}, + }); + + REQUIRE(pgh.spec.name() == "s"); + REQUIRE(pgh.version == "v"); + REQUIRE(pgh.maintainer == "m"); + REQUIRE(pgh.description == "d"); + REQUIRE(pgh.depends.size() == 1); + REQUIRE(pgh.depends[0] == "bd"); +} + +TEST_CASE ("BinaryParagraph three depends", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Depends", "a, b, c"}, + }); + + REQUIRE(pgh.depends.size() == 3); + REQUIRE(pgh.depends[0] == "a"); + REQUIRE(pgh.depends[1] == "b"); + REQUIRE(pgh.depends[2] == "c"); +} + +TEST_CASE ("BinaryParagraph abi", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Abi", "abcd123"}, + }); + + REQUIRE(pgh.depends.size() == 0); + REQUIRE(pgh.abi == "abcd123"); +} + +TEST_CASE ("BinaryParagraph default features", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "a"}, + {"Version", "1.0"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Default-Features", "a1"}, + }); + + REQUIRE(pgh.depends.size() == 0); + REQUIRE(pgh.default_features.size() == 1); + REQUIRE(pgh.default_features[0] == "a1"); +} + +TEST_CASE ("parse paragraphs empty", "[paragraph]") +{ + const char* str = ""; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + REQUIRE(pghs.empty()); +} + +TEST_CASE ("parse paragraphs one field", "[paragraph]") +{ + const char* str = "f1: v1"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 1); + REQUIRE(pghs[0]["f1"] == "v1"); +} + +TEST_CASE ("parse paragraphs one pgh", "[paragraph]") +{ + const char* str = "f1: v1\n" + "f2: v2"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 2); + REQUIRE(pghs[0]["f1"] == "v1"); + REQUIRE(pghs[0]["f2"] == "v2"); +} + +TEST_CASE ("parse paragraphs two pgh", "[paragraph]") +{ + const char* str = "f1: v1\n" + "f2: v2\n" + "\n" + "f3: v3\n" + "f4: v4"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 2); + REQUIRE(pghs[0].size() == 2); + REQUIRE(pghs[0]["f1"] == "v1"); + REQUIRE(pghs[0]["f2"] == "v2"); + REQUIRE(pghs[1].size() == 2); + REQUIRE(pghs[1]["f3"] == "v3"); + REQUIRE(pghs[1]["f4"] == "v4"); +} + +TEST_CASE ("parse paragraphs field names", "[paragraph]") +{ + const char* str = "1:\n" + "f:\n" + "F:\n" + "0:\n" + "F-2:\n"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 5); +} + +TEST_CASE ("parse paragraphs multiple blank lines", "[paragraph]") +{ + const char* str = "f1: v1\n" + "f2: v2\n" + "\n" + "\n" + "f3: v3\n" + "f4: v4"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 2); +} + +TEST_CASE ("parse paragraphs empty fields", "[paragraph]") +{ + const char* str = "f1:\n" + "f2: "; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 2); + REQUIRE(pghs[0]["f1"] == ""); + REQUIRE(pghs[0]["f2"] == ""); + REQUIRE(pghs[0].size() == 2); +} + +TEST_CASE ("parse paragraphs multiline fields", "[paragraph]") +{ + const char* str = "f1: simple\n" + " f1\r\n" + "f2:\r\n" + " f2\r\n" + " continue\r\n"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0]["f1"] == "simple\n f1"); + REQUIRE(pghs[0]["f2"] == "\n f2\n continue"); +} + +TEST_CASE ("parse paragraphs crlfs", "[paragraph]") +{ + const char* str = "f1: v1\r\n" + "f2: v2\r\n" + "\r\n" + "f3: v3\r\n" + "f4: v4"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 2); + REQUIRE(pghs[0].size() == 2); + REQUIRE(pghs[0]["f1"] == "v1"); + REQUIRE(pghs[0]["f2"] == "v2"); + REQUIRE(pghs[1].size() == 2); + REQUIRE(pghs[1]["f3"] == "v3"); + REQUIRE(pghs[1]["f4"] == "v4"); +} + +TEST_CASE ("parse paragraphs comment", "[paragraph]") +{ + const char* str = "f1: v1\r\n" + "#comment\r\n" + "f2: v2\r\n" + "#comment\r\n" + "\r\n" + "#comment\r\n" + "f3: v3\r\n" + "#comment\r\n" + "f4: v4"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 2); + REQUIRE(pghs[0].size() == 2); + REQUIRE(pghs[0]["f1"] == "v1"); + REQUIRE(pghs[0]["f2"] == "v2"); + REQUIRE(pghs[1].size()); + REQUIRE(pghs[1]["f3"] == "v3"); + REQUIRE(pghs[1]["f4"] == "v4"); +} + +TEST_CASE ("parse comment before single line feed", "[paragraph]") +{ + const char* str = "f1: v1\r\n" + "#comment\n"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + REQUIRE(pghs[0].size() == 1); + REQUIRE(pghs[0]["f1"] == "v1"); +} + +TEST_CASE ("BinaryParagraph serialize min", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + }); + std::string ss = Strings::serialize(pgh); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 4); + REQUIRE(pghs[0]["Package"] == "zlib"); + REQUIRE(pghs[0]["Version"] == "1.2.8"); + REQUIRE(pghs[0]["Architecture"] == "x86-windows"); + REQUIRE(pghs[0]["Multi-Arch"] == "same"); +} + +TEST_CASE ("BinaryParagraph serialize max", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Description", "first line\n second line"}, + {"Maintainer", "abc "}, + {"Depends", "dep"}, + {"Multi-Arch", "same"}, + }); + std::string ss = Strings::serialize(pgh); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 7); + REQUIRE(pghs[0]["Package"] == "zlib"); + REQUIRE(pghs[0]["Version"] == "1.2.8"); + REQUIRE(pghs[0]["Architecture"] == "x86-windows"); + REQUIRE(pghs[0]["Multi-Arch"] == "same"); + REQUIRE(pghs[0]["Description"] == "first line\n second line"); + REQUIRE(pghs[0]["Depends"] == "dep"); +} + +TEST_CASE ("BinaryParagraph serialize multiple deps", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Depends", "a, b, c"}, + }); + std::string ss = Strings::serialize(pgh); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0]["Depends"] == "a, b, c"); +} + +TEST_CASE ("BinaryParagraph serialize abi", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Depends", "a, b, c"}, + {"Abi", "123abc"}, + }); + std::string ss = Strings::serialize(pgh); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0]["Abi"] == "123abc"); +} diff --git a/toolsrc/src/vcpkg-tests/plan.cpp b/toolsrc/src/vcpkg-tests/plan.cpp new file mode 100644 index 000000000..7ecab460b --- /dev/null +++ b/toolsrc/src/vcpkg-tests/plan.cpp @@ -0,0 +1,1241 @@ +#include +#include + +#include +#include +#include + +#include +#include +#include + +using namespace vcpkg; + +using Test::make_status_feature_pgh; +using Test::make_status_pgh; +using Test::unsafe_pspec; + +static std::unique_ptr make_control_file( + const char* name, + const char* depends, + const std::vector>& features = {}, + const std::vector& default_features = {}) +{ + using Pgh = std::unordered_map; + std::vector scf_pghs; + scf_pghs.push_back(Pgh{{"Source", name}, + {"Version", "0"}, + {"Build-Depends", depends}, + {"Default-Features", Strings::join(", ", default_features)}}); + for (auto&& feature : features) + { + scf_pghs.push_back(Pgh{ + {"Feature", feature.first}, + {"Description", "feature"}, + {"Build-Depends", feature.second}, + }); + } + auto m_pgh = vcpkg::SourceControlFile::parse_control_file(std::move(scf_pghs)); + REQUIRE(m_pgh.has_value()); + return std::move(*m_pgh.get()); +} + +/// +/// Assert that the given action an install of given features from given package. +/// +static void features_check(Dependencies::AnyAction& install_action, + std::string pkg_name, + std::vector vec, + const Triplet& triplet = Triplet::X86_WINDOWS) +{ + REQUIRE(install_action.install_action.has_value()); + const auto& plan = install_action.install_action.value_or_exit(VCPKG_LINE_INFO); + const auto& feature_list = plan.feature_list; + + REQUIRE(plan.spec.triplet().to_string() == triplet.to_string()); + + auto& scfl = *plan.source_control_file_location.get(); + REQUIRE(pkg_name == scfl.source_control_file->core_paragraph->name); + REQUIRE(feature_list.size() == vec.size()); + + for (auto&& feature_name : vec) + { + // TODO: see if this can be simplified + if (feature_name == "core" || feature_name == "") + { + REQUIRE((Util::find(feature_list, "core") != feature_list.end() || + Util::find(feature_list, "") != feature_list.end())); + continue; + } + REQUIRE(Util::find(feature_list, feature_name) != feature_list.end()); + } +} + +/// +/// Assert that the given action is a remove of given package. +/// +static void remove_plan_check(Dependencies::AnyAction& remove_action, + std::string pkg_name, + const Triplet& triplet = Triplet::X86_WINDOWS) +{ + const auto& plan = remove_action.remove_action.value_or_exit(VCPKG_LINE_INFO); + REQUIRE(plan.spec.triplet().to_string() == triplet.to_string()); + REQUIRE(pkg_name == plan.spec.name()); +} + +/// +/// Map of source control files by their package name. +/// +struct PackageSpecMap +{ + std::unordered_map map; + Triplet triplet; + PackageSpecMap(const Triplet& t = Triplet::X86_WINDOWS) noexcept { triplet = t; } + + PackageSpec emplace(const char* name, + const char* depends = "", + const std::vector>& features = {}, + const std::vector& default_features = {}) + { + auto scfl = SourceControlFileLocation{make_control_file(name, depends, features, default_features), ""}; + return emplace(std::move(scfl)); + } + + PackageSpec emplace(vcpkg::SourceControlFileLocation&& scfl) + { + auto spec = PackageSpec::from_name_and_triplet(scfl.source_control_file->core_paragraph->name, triplet); + REQUIRE(spec.has_value()); + map.emplace(scfl.source_control_file->core_paragraph->name, std::move(scfl)); + return PackageSpec{*spec.get()}; + } +}; + +TEST_CASE ("basic install scheme", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "b"); + auto spec_b = spec_map.emplace("b", "c"); + auto spec_c = spec_map.emplace("c"); + + Dependencies::MapPortFileProvider map_port(spec_map.map); + auto install_plan = Dependencies::create_feature_install_plan( + map_port, {FeatureSpec{spec_a, ""}}, StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + REQUIRE(install_plan.at(0).spec().name() == "c"); + REQUIRE(install_plan.at(1).spec().name() == "b"); + REQUIRE(install_plan.at(2).spec().name() == "a"); +} + +TEST_CASE ("multiple install scheme", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "d"); + auto spec_b = spec_map.emplace("b", "d, e"); + auto spec_c = spec_map.emplace("c", "e, h"); + auto spec_d = spec_map.emplace("d", "f, g, h"); + auto spec_e = spec_map.emplace("e", "g"); + auto spec_f = spec_map.emplace("f"); + auto spec_g = spec_map.emplace("g"); + auto spec_h = spec_map.emplace("h"); + + Dependencies::MapPortFileProvider map_port(spec_map.map); + auto install_plan = Dependencies::create_feature_install_plan( + map_port, + {FeatureSpec{spec_a, ""}, FeatureSpec{spec_b, ""}, FeatureSpec{spec_c, ""}}, + StatusParagraphs(std::move(status_paragraphs))); + + auto iterator_pos = [&](const PackageSpec& spec) { + auto it = + std::find_if(install_plan.begin(), install_plan.end(), [&](auto& action) { return action.spec() == spec; }); + REQUIRE(it != install_plan.end()); + return it - install_plan.begin(); + }; + + const auto a_pos = iterator_pos(spec_a); + const auto b_pos = iterator_pos(spec_b); + const auto c_pos = iterator_pos(spec_c); + const auto d_pos = iterator_pos(spec_d); + const auto e_pos = iterator_pos(spec_e); + const auto f_pos = iterator_pos(spec_f); + const auto g_pos = iterator_pos(spec_g); + const auto h_pos = iterator_pos(spec_h); + + REQUIRE(a_pos > d_pos); + REQUIRE(b_pos > e_pos); + REQUIRE(b_pos > d_pos); + REQUIRE(c_pos > e_pos); + REQUIRE(c_pos > h_pos); + REQUIRE(d_pos > f_pos); + REQUIRE(d_pos > g_pos); + REQUIRE(d_pos > h_pos); + REQUIRE(e_pos > g_pos); +} + +TEST_CASE ("existing package scheme", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(vcpkg::Test::make_status_pgh("a")); + + PackageSpecMap spec_map; + auto spec_a = FullPackageSpec{spec_map.emplace("a")}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 1); + const auto p = install_plan.at(0).install_action.get(); + REQUIRE(p); + REQUIRE(p->spec.name() == "a"); + REQUIRE(p->plan_type == Dependencies::InstallPlanType::ALREADY_INSTALLED); + REQUIRE(p->request_type == Dependencies::RequestType::USER_REQUESTED); +} + +TEST_CASE ("user requested package scheme", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map; + const auto spec_a = FullPackageSpec{spec_map.emplace("a", "b")}; + const auto spec_b = FullPackageSpec{spec_map.emplace("b")}; + + const auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 2); + const auto p = install_plan.at(0).install_action.get(); + REQUIRE(p); + REQUIRE(p->spec.name() == "b"); + REQUIRE(p->plan_type == Dependencies::InstallPlanType::BUILD_AND_INSTALL); + REQUIRE(p->request_type == Dependencies::RequestType::AUTO_SELECTED); + + const auto p2 = install_plan.at(1).install_action.get(); + REQUIRE(p2); + REQUIRE(p2->spec.name() == "a"); + REQUIRE(p2->plan_type == Dependencies::InstallPlanType::BUILD_AND_INSTALL); + REQUIRE(p2->request_type == Dependencies::RequestType::USER_REQUESTED); +} + +TEST_CASE ("long install scheme", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("j", "k")); + status_paragraphs.push_back(make_status_pgh("k")); + + PackageSpecMap spec_map; + + auto spec_a = spec_map.emplace("a", "b, c, d, e, f, g, h, j, k"); + auto spec_b = spec_map.emplace("b", "c, d, e, f, g, h, j, k"); + auto spec_c = spec_map.emplace("c", "d, e, f, g, h, j, k"); + auto spec_d = spec_map.emplace("d", "e, f, g, h, j, k"); + auto spec_e = spec_map.emplace("e", "f, g, h, j, k"); + auto spec_f = spec_map.emplace("f", "g, h, j, k"); + auto spec_g = spec_map.emplace("g", "h, j, k"); + auto spec_h = spec_map.emplace("h", "j, k"); + auto spec_j = spec_map.emplace("j", "k"); + auto spec_k = spec_map.emplace("k"); + + Dependencies::MapPortFileProvider map_port(spec_map.map); + auto install_plan = Dependencies::create_feature_install_plan( + map_port, {FeatureSpec{spec_a, ""}}, StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 8); + REQUIRE(install_plan.at(0).spec().name() == "h"); + REQUIRE(install_plan.at(1).spec().name() == "g"); + REQUIRE(install_plan.at(2).spec().name() == "f"); + REQUIRE(install_plan.at(3).spec().name() == "e"); + REQUIRE(install_plan.at(4).spec().name() == "d"); + REQUIRE(install_plan.at(5).spec().name() == "c"); + REQUIRE(install_plan.at(6).spec().name() == "b"); + REQUIRE(install_plan.at(7).spec().name() == "a"); +} + +TEST_CASE ("basic feature test 1", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a", "b, b[b1]")); + status_paragraphs.push_back(make_status_pgh("b")); + status_paragraphs.push_back(make_status_feature_pgh("b", "b1")); + + PackageSpecMap spec_map; + auto spec_a = FullPackageSpec{spec_map.emplace("a", "b, b[b1]", {{"a1", "b[b2]"}}), {"a1"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 4); + remove_plan_check(install_plan.at(0), "a"); + remove_plan_check(install_plan.at(1), "b"); + features_check(install_plan.at(2), "b", {"b1", "core", "b1"}); + features_check(install_plan.at(3), "a", {"a1", "core"}); +} + +TEST_CASE ("basic feature test 2", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map; + + auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[b1]", {{"a1", "b[b2]"}}), {"a1"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 2); + features_check(install_plan.at(0), "b", {"b1", "b2", "core"}); + features_check(install_plan.at(1), "a", {"a1", "core"}); +} + +TEST_CASE ("basic feature test 3", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + + PackageSpecMap spec_map; + + auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b")}; + auto spec_c = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; + + auto install_plan = Dependencies::create_feature_install_plan(spec_map.map, + FullPackageSpec::to_feature_specs({spec_c, spec_a}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 4); + remove_plan_check(install_plan.at(0), "a"); + features_check(install_plan.at(1), "b", {"core"}); + features_check(install_plan.at(2), "a", {"a1", "core"}); + features_check(install_plan.at(3), "c", {"core"}); +} + +TEST_CASE ("basic feature test 4", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.push_back(make_status_feature_pgh("a", "a1", "")); + + PackageSpecMap spec_map; + + auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}})}; + auto spec_b = FullPackageSpec{spec_map.emplace("b")}; + auto spec_c = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_c}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "c", {"core"}); +} + +TEST_CASE ("basic feature test 5", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map; + + auto spec_a = + FullPackageSpec{spec_map.emplace("a", "", {{"a1", "b[b1]"}, {"a2", "b[b2]"}, {"a3", "a[a2]"}}), {"a3"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}})}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 2); + features_check(install_plan.at(0), "b", {"core", "b2"}); + features_check(install_plan.at(1), "a", {"core", "a3", "a2"}); +} + +TEST_CASE ("basic feature test 6", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("b")); + + PackageSpecMap spec_map; + auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[core]"), {"core"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {"b1"}}; + + auto install_plan = Dependencies::create_feature_install_plan(spec_map.map, + FullPackageSpec::to_feature_specs({spec_a, spec_b}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + remove_plan_check(install_plan.at(0), "b"); + features_check(install_plan.at(1), "b", {"core", "b1"}); + features_check(install_plan.at(2), "a", {"core"}); +} + +TEST_CASE ("basic feature test 7", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("x", "b")); + status_paragraphs.push_back(make_status_pgh("b")); + + PackageSpecMap spec_map; + + auto spec_a = FullPackageSpec{spec_map.emplace("a")}; + auto spec_x = FullPackageSpec{spec_map.emplace("x", "a"), {"core"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {"b1"}}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_b}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 5); + remove_plan_check(install_plan.at(0), "x"); + remove_plan_check(install_plan.at(1), "b"); + + // TODO: order here may change but A < X, and B anywhere + features_check(install_plan.at(2), "b", {"core", "b1"}); + features_check(install_plan.at(3), "a", {"core"}); + features_check(install_plan.at(4), "x", {"core"}); +} + +TEST_CASE ("basic feature test 8", "[plan][!mayfail]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.spec = + PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; + auto spec_b_64 = FullPackageSpec{spec_map.emplace("b")}; + auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; + + spec_map.triplet = Triplet::X86_WINDOWS; + auto spec_a_86 = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; + auto spec_b_86 = FullPackageSpec{spec_map.emplace("b")}; + auto spec_c_86 = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({spec_c_64, spec_a_86, spec_a_64, spec_c_86}), + StatusParagraphs(std::move(status_paragraphs))); + + remove_plan_check(install_plan.at(0), "a", Triplet::X64_WINDOWS); + remove_plan_check(install_plan.at(1), "a"); + features_check(install_plan.at(2), "b", {"core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(3), "a", {"a1", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(4), "c", {"core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(5), "b", {"core"}); + features_check(install_plan.at(6), "a", {"a1", "core"}); + features_check(install_plan.at(7), "c", {"core"}); +} + +TEST_CASE ("install all features test", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}), {"core"}}; + + auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); + REQUIRE(install_specs.has_value()); + if (!install_specs.has_value()) return; + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"0", "1", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install default features test 1", "[plan]") +{ + std::vector> status_paragraphs; + + // Add a port "a" with default features "1" and features "0" and "1". + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}, {"1"}); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect the default feature "1" to be installed, but not "0" + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"1", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install default features test 2", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.spec = + PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + + // Add a port "a" of which "core" is already installed, but we will + // install the default features "explicitly" + // "a" has two features, of which "a1" is default. + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "", {{"a0", ""}, {"a1", ""}}, {"a1"}); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect "a" to get removed for rebuild and then installed with default + // features. + REQUIRE(install_plan.size() == 2); + remove_plan_check(install_plan.at(0), "a", Triplet::X64_WINDOWS); + features_check(install_plan.at(1), "a", {"a1", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install default features test 3", "[plan]") +{ + std::vector> status_paragraphs; + + // "a" has two features, of which "a1" is default. + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "", {{"a0", ""}, {"a1", ""}}, {"a1"}); + + // Explicitly install "a" without default features + auto install_specs = FullPackageSpec::from_string("a[core]", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect the default feature not to get installed. + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install default features of dependency test 1", "[plan]") +{ + std::vector> status_paragraphs; + + // Add a port "a" which depends on the core of "b" + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "b[core]"); + // "b" has two features, of which "b1" is default. + spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect "a" to get installed and defaults of "b" through the dependency, + // as no explicit features of "b" are installed by the user. + REQUIRE(install_plan.size() == 2); + features_check(install_plan.at(0), "b", {"b1", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(1), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("do not install default features of existing dependency", "[plan]") +{ + // Add a port "a" which depends on the core of "b" + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "b[core]"); + // "b" has two features, of which "b1" is default. + spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); + + std::vector> status_paragraphs; + // "b[core]" is already installed + status_paragraphs.push_back(make_status_pgh("b")); + status_paragraphs.back()->package.spec = + PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect "a" to get installed, but not require rebuilding "b" + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install default features of dependency test 2", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("b")); + status_paragraphs.back()->package.spec = + PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + + // Add a port "a" which depends on the core of "b", which was already + // installed explicitly + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "b[core]"); + // "b" has two features, of which "b1" is default. + spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect "a" to get installed, not the defaults of "b", as the required + // dependencies are already there, installed explicitly by the user. + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install plan action dependencies", "[plan]") +{ + std::vector> status_paragraphs; + + // Add a port "a" which depends on the core of "b", which was already + // installed explicitly + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_c = spec_map.emplace("c"); + auto spec_b = spec_map.emplace("b", "c"); + spec_map.emplace("a", "b"); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + features_check(install_plan.at(0), "c", {"core"}, Triplet::X64_WINDOWS); + + features_check(install_plan.at(1), "b", {"core"}, Triplet::X64_WINDOWS); + REQUIRE(install_plan.at(1).install_action.get()->computed_dependencies == std::vector{spec_c}); + + features_check(install_plan.at(2), "a", {"core"}, Triplet::X64_WINDOWS); + REQUIRE(install_plan.at(2).install_action.get()->computed_dependencies == std::vector{spec_b}); +} + +TEST_CASE ("install plan action dependencies 2", "[plan]") +{ + std::vector> status_paragraphs; + + // Add a port "a" which depends on the core of "b", which was already + // installed explicitly + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_c = spec_map.emplace("c"); + auto spec_b = spec_map.emplace("b", "c"); + spec_map.emplace("a", "c, b"); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + features_check(install_plan.at(0), "c", {"core"}, Triplet::X64_WINDOWS); + + features_check(install_plan.at(1), "b", {"core"}, Triplet::X64_WINDOWS); + REQUIRE(install_plan.at(1).install_action.get()->computed_dependencies == std::vector{spec_c}); + + features_check(install_plan.at(2), "a", {"core"}, Triplet::X64_WINDOWS); + REQUIRE(install_plan.at(2).install_action.get()->computed_dependencies == std::vector{spec_b, spec_c}); +} + +TEST_CASE ("install plan action dependencies 3", "[plan]") +{ + std::vector> status_paragraphs; + + // Add a port "a" which depends on the core of "b", which was already + // installed explicitly + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "", {{"0", ""}, {"1", "a[0]"}}, {"1"}); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"1", "0", "core"}, Triplet::X64_WINDOWS); + REQUIRE(install_plan.at(0).install_action.get()->computed_dependencies == std::vector{}); +} + +TEST_CASE ("install with default features", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a", "")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto b_spec = spec_map.emplace("b", "", {{"0", ""}}, {"0"}); + auto a_spec = spec_map.emplace("a", "b[core]", {{"0", ""}}); + + // Install "a" and indicate that "b" should not install default features + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, {FeatureSpec{a_spec, "0"}, FeatureSpec{b_spec, "core"}}, status_db); + + REQUIRE(install_plan.size() == 3); + remove_plan_check(install_plan.at(0), "a"); + features_check(install_plan.at(1), "b", {"core"}); + features_check(install_plan.at(2), "a", {"0", "core"}); +} + +TEST_CASE ("upgrade with default features 1", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a", "", "1")); + pghs.push_back(make_status_feature_pgh("a", "0")); + StatusParagraphs status_db(std::move(pghs)); + + // Add a port "a" of which "core" and "0" are already installed. + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}, {"1"}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + auto plan = graph.serialize(); + + // The upgrade should not install the default feature + REQUIRE(plan.size() == 2); + + REQUIRE(plan.at(0).spec().name() == "a"); + remove_plan_check(plan.at(0), "a"); + features_check(plan.at(1), "a", {"core", "0"}); +} + +TEST_CASE ("upgrade with default features 2", "[plan]") +{ + std::vector> pghs; + // B is currently installed _without_ default feature b0 + pghs.push_back(make_status_pgh("b", "", "b0", "x64-windows")); + pghs.push_back(make_status_pgh("a", "b[core]", "", "x64-windows")); + + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a = spec_map.emplace("a", "b[core]"); + auto spec_b = spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b0", "b1"}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + graph.upgrade(spec_b); + auto plan = graph.serialize(); + + // The upgrade should install the new default feature b1 but not b0 + REQUIRE(plan.size() == 4); + remove_plan_check(plan.at(0), "a", Triplet::X64_WINDOWS); + remove_plan_check(plan.at(1), "b", Triplet::X64_WINDOWS); + features_check(plan.at(2), "b", {"core", "b1"}, Triplet::X64_WINDOWS); + features_check(plan.at(3), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("upgrade with default features 3", "[plan]") +{ + std::vector> pghs; + // note: unrelated package due to x86 triplet + pghs.push_back(make_status_pgh("b", "", "", "x86-windows")); + pghs.push_back(make_status_pgh("a", "", "", "x64-windows")); + + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a = spec_map.emplace("a", "b[core]"); + spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b0"}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + auto plan = graph.serialize(); + + // The upgrade should install the default feature + REQUIRE(plan.size() == 3); + remove_plan_check(plan.at(0), "a", Triplet::X64_WINDOWS); + features_check(plan.at(1), "b", {"b0", "core"}, Triplet::X64_WINDOWS); + features_check(plan.at(2), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("upgrade with new default feature", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a", "", "0", "x86-windows")); + + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"0", ""}, {"1", ""}, {"2", ""}}, {"0", "1"}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + auto plan = graph.serialize(); + + // The upgrade should install the new default feature but not the old default feature 0 + REQUIRE(plan.size() == 2); + remove_plan_check(plan.at(0), "a", Triplet::X86_WINDOWS); + features_check(plan.at(1), "a", {"core", "1"}, Triplet::X86_WINDOWS); +} + +TEST_CASE ("transitive features test", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"0", "b[0]"}}), {"core"}}; + auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "c", {{"0", "c[0]"}}), {"core"}}; + auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; + + auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); + REQUIRE(install_specs.has_value()); + if (!install_specs.has_value()) return; + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + features_check(install_plan.at(0), "c", {"0", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(1), "b", {"0", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(2), "a", {"0", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("no transitive features test", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"0", ""}}), {"core"}}; + auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "c", {{"0", ""}}), {"core"}}; + auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; + + auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); + REQUIRE(install_specs.has_value()); + if (!install_specs.has_value()) return; + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + features_check(install_plan.at(0), "c", {"core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(1), "b", {"core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(2), "a", {"0", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("only transitive features test", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "", {{"0", "b[0]"}}), {"core"}}; + auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "", {{"0", "c[0]"}}), {"core"}}; + auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; + + auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); + REQUIRE(install_specs.has_value()); + if (!install_specs.has_value()) return; + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + features_check(install_plan.at(0), "c", {"0", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(1), "b", {"0", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(2), "a", {"0", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("basic remove scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); + + REQUIRE(remove_plan.size() == 1); + REQUIRE(remove_plan.at(0).spec.name() == "a"); +} + +TEST_CASE ("recurse remove scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b", "a")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); + + REQUIRE(remove_plan.size() == 2); + REQUIRE(remove_plan.at(0).spec.name() == "b"); + REQUIRE(remove_plan.at(1).spec.name() == "a"); +} + +TEST_CASE ("features depend remove scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b")); + pghs.push_back(make_status_feature_pgh("b", "0", "a")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); + + REQUIRE(remove_plan.size() == 2); + REQUIRE(remove_plan.at(0).spec.name() == "b"); + REQUIRE(remove_plan.at(1).spec.name() == "a"); +} + +TEST_CASE ("features depend remove scheme once removed", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("expat")); + pghs.push_back(make_status_pgh("vtk", "expat")); + pghs.push_back(make_status_pgh("opencv")); + pghs.push_back(make_status_feature_pgh("opencv", "vtk", "vtk")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("expat")}, status_db); + + REQUIRE(remove_plan.size() == 3); + REQUIRE(remove_plan.at(0).spec.name() == "opencv"); + REQUIRE(remove_plan.at(1).spec.name() == "vtk"); + REQUIRE(remove_plan.at(2).spec.name() == "expat"); +} + +TEST_CASE ("features depend remove scheme once removed x64", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("expat", "", "", "x64")); + pghs.push_back(make_status_pgh("vtk", "expat", "", "x64")); + pghs.push_back(make_status_pgh("opencv", "", "", "x64")); + pghs.push_back(make_status_feature_pgh("opencv", "vtk", "vtk", "x64")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = + Dependencies::create_remove_plan({unsafe_pspec("expat", Triplet::from_canonical_name("x64"))}, status_db); + + REQUIRE(remove_plan.size() == 3); + REQUIRE(remove_plan.at(0).spec.name() == "opencv"); + REQUIRE(remove_plan.at(1).spec.name() == "vtk"); + REQUIRE(remove_plan.at(2).spec.name() == "expat"); +} + +TEST_CASE ("features depend core remove scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("curl", "", "", "x64")); + pghs.push_back(make_status_pgh("cpr", "curl[core]", "", "x64")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = + Dependencies::create_remove_plan({unsafe_pspec("curl", Triplet::from_canonical_name("x64"))}, status_db); + + REQUIRE(remove_plan.size() == 2); + REQUIRE(remove_plan.at(0).spec.name() == "cpr"); + REQUIRE(remove_plan.at(1).spec.name() == "curl"); +} + +TEST_CASE ("features depend core remove scheme 2", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("curl", "", "", "x64")); + pghs.push_back(make_status_feature_pgh("curl", "a", "", "x64")); + pghs.push_back(make_status_feature_pgh("curl", "b", "curl[a]", "x64")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = + Dependencies::create_remove_plan({unsafe_pspec("curl", Triplet::from_canonical_name("x64"))}, status_db); + + REQUIRE(remove_plan.size() == 1); + REQUIRE(remove_plan.at(0).spec.name() == "curl"); +} + +TEST_CASE ("basic upgrade scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 2); + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + REQUIRE(plan.at(1).spec().name() == "a"); + REQUIRE(plan.at(1).install_action.has_value()); +} + +TEST_CASE ("basic upgrade scheme with recurse", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b", "a")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + spec_map.emplace("b", "a"); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 4); + REQUIRE(plan.at(0).spec().name() == "b"); + REQUIRE(plan.at(0).remove_action.has_value()); + + REQUIRE(plan.at(1).spec().name() == "a"); + REQUIRE(plan.at(1).remove_action.has_value()); + + REQUIRE(plan.at(2).spec().name() == "a"); + REQUIRE(plan.at(2).install_action.has_value()); + + REQUIRE(plan.at(3).spec().name() == "b"); + REQUIRE(plan.at(3).install_action.has_value()); +} + +TEST_CASE ("basic upgrade scheme with bystander", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + spec_map.emplace("b", "a"); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 2); + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + REQUIRE(plan.at(1).spec().name() == "a"); + REQUIRE(plan.at(1).install_action.has_value()); +} + +TEST_CASE ("basic upgrade scheme with new dep", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "b"); + spec_map.emplace("b"); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 3); + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + REQUIRE(plan.at(1).spec().name() == "b"); + REQUIRE(plan.at(1).install_action.has_value()); + REQUIRE(plan.at(2).spec().name() == "a"); + REQUIRE(plan.at(2).install_action.has_value()); +} + +TEST_CASE ("basic upgrade scheme with features", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_feature_pgh("a", "a1")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 2); + + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + + features_check(plan.at(1), "a", {"core", "a1"}); +} + +TEST_CASE ("basic upgrade scheme with new default feature", "[plan]") +{ + // only core of package "a" is installed + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + StatusParagraphs status_db(std::move(pghs)); + + // a1 was added as a default feature and should be installed in upgrade + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}, {"a1"}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 2); + + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + + features_check(plan.at(1), "a", {"core", "a1"}); +} + +TEST_CASE ("basic upgrade scheme with self features", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_feature_pgh("a", "a1", "")); + pghs.push_back(make_status_feature_pgh("a", "a2", "a[a1]")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"a1", ""}, {"a2", "a[a1]"}}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 2); + + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + + REQUIRE(plan.at(1).spec().name() == "a"); + REQUIRE(plan.at(1).install_action.has_value()); + REQUIRE(plan.at(1).install_action.get()->feature_list == std::set{"core", "a1", "a2"}); +} + +TEST_CASE ("basic export scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + + auto plan = Dependencies::create_export_plan({spec_a}, status_db); + + REQUIRE(plan.size() == 1); + REQUIRE(plan.at(0).spec.name() == "a"); + REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); +} + +TEST_CASE ("basic export scheme with recurse", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b", "a")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + auto spec_b = spec_map.emplace("b", "a"); + + auto plan = Dependencies::create_export_plan({spec_b}, status_db); + + REQUIRE(plan.size() == 2); + REQUIRE(plan.at(0).spec.name() == "a"); + REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); + + REQUIRE(plan.at(1).spec.name() == "b"); + REQUIRE(plan.at(1).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); +} + +TEST_CASE ("basic export scheme with bystander", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + auto spec_b = spec_map.emplace("b", "a"); + + auto plan = Dependencies::create_export_plan({spec_a}, status_db); + + REQUIRE(plan.size() == 1); + REQUIRE(plan.at(0).spec.name() == "a"); + REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); +} + +TEST_CASE ("basic export scheme with missing", "[plan]") +{ + StatusParagraphs status_db; + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + + auto plan = Dependencies::create_export_plan({spec_a}, status_db); + + REQUIRE(plan.size() == 1); + REQUIRE(plan.at(0).spec.name() == "a"); + REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::NOT_BUILT); +} + +TEST_CASE ("basic export scheme with features", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("b")); + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_feature_pgh("a", "a1", "b[core]")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}); + + auto plan = Dependencies::create_export_plan({spec_a}, status_db); + + REQUIRE(plan.size() == 2); + + REQUIRE(plan.at(0).spec.name() == "b"); + REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); + + REQUIRE(plan.at(1).spec.name() == "a"); + REQUIRE(plan.at(1).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); +} diff --git a/toolsrc/src/vcpkg-tests/specifier.cpp b/toolsrc/src/vcpkg-tests/specifier.cpp new file mode 100644 index 000000000..52ef044e7 --- /dev/null +++ b/toolsrc/src/vcpkg-tests/specifier.cpp @@ -0,0 +1,134 @@ +#include + +#include +#include + +using namespace vcpkg; + +TEST_CASE ("specifier conversion", "[specifier]") +{ + SECTION ("full package spec to feature specs") + { + constexpr std::size_t SPEC_SIZE = 6; + + auto a_spec = PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + auto b_spec = PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + + auto fspecs = FullPackageSpec::to_feature_specs({{a_spec, {"0", "1"}}, {b_spec, {"2", "3"}}}); + + REQUIRE(fspecs.size() == SPEC_SIZE); + + std::array features = {"", "0", "1", "", "2", "3"}; + std::array specs = {&a_spec, &a_spec, &a_spec, &b_spec, &b_spec, &b_spec}; + + for (std::size_t i = 0; i < SPEC_SIZE; ++i) + { + REQUIRE(features.at(i) == fspecs.at(i).feature()); + REQUIRE(*specs.at(i) == fspecs.at(i).spec()); + } + } +} + +TEST_CASE ("specifier parsing", "[specifier]") +{ + SECTION ("parsed specifier from string") + { + auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib"); + REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); + + auto& spec = *maybe_spec.get(); + REQUIRE(spec.name == "zlib"); + REQUIRE(spec.features.size() == 0); + REQUIRE(spec.triplet == ""); + } + + SECTION ("parsed specifier from string with triplet") + { + auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib:x64-uwp"); + REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); + + auto& spec = *maybe_spec.get(); + REQUIRE(spec.name == "zlib"); + REQUIRE(spec.triplet == "x64-uwp"); + } + + SECTION ("parsed specifier from string with colons") + { + auto ec = vcpkg::ParsedSpecifier::from_string("zlib:x86-uwp:").error(); + REQUIRE(ec == vcpkg::PackageSpecParseResult::TOO_MANY_COLONS); + } + + SECTION ("parsed specifier from string with feature") + { + auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[feature]:x64-uwp"); + REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); + + auto& spec = *maybe_spec.get(); + REQUIRE(spec.name == "zlib"); + REQUIRE(spec.features.size() == 1); + REQUIRE(spec.features.at(0) == "feature"); + REQUIRE(spec.triplet == "x64-uwp"); + } + + SECTION ("parsed specifier from string with many features") + { + auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[0, 1,2]"); + REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); + + auto& spec = *maybe_spec.get(); + REQUIRE(spec.name == "zlib"); + REQUIRE(spec.features.size() == 3); + REQUIRE(spec.features.at(0) == "0"); + REQUIRE(spec.features.at(1) == "1"); + REQUIRE(spec.features.at(2) == "2"); + REQUIRE(spec.triplet == ""); + } + + SECTION ("parsed specifier wildcard feature") + { + auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[*]"); + REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); + + auto& spec = *maybe_spec.get(); + REQUIRE(spec.name == "zlib"); + REQUIRE(spec.features.size() == 1); + REQUIRE(spec.features.at(0) == "*"); + REQUIRE(spec.triplet == ""); + } + + SECTION ("expand wildcards") + { + auto zlib = vcpkg::FullPackageSpec::from_string("zlib[0,1]", Triplet::X86_UWP).value_or_exit(VCPKG_LINE_INFO); + auto openssl = + vcpkg::FullPackageSpec::from_string("openssl[*]", Triplet::X86_UWP).value_or_exit(VCPKG_LINE_INFO); + auto specs = FullPackageSpec::to_feature_specs({zlib, openssl}); + Util::sort(specs); + auto spectargets = FeatureSpec::from_strings_and_triplet( + { + "openssl", + "zlib", + "openssl[*]", + "zlib[0]", + "zlib[1]", + }, + Triplet::X86_UWP); + Util::sort(spectargets); + + REQUIRE(specs.size() == spectargets.size()); + REQUIRE(Util::all_equal(specs, spectargets)); + } + +#if defined(_WIN32) + SECTION ("ASCII to utf16") + { + auto str = vcpkg::Strings::to_utf16("abc"); + REQUIRE(str == L"abc"); + } + + SECTION ("ASCII to utf16 with whitespace") + { + auto str = vcpkg::Strings::to_utf16("abc -x86-windows"); + REQUIRE(str == L"abc -x86-windows"); + } +#endif +}; diff --git a/toolsrc/src/vcpkg-tests/statusparagraphs.cpp b/toolsrc/src/vcpkg-tests/statusparagraphs.cpp new file mode 100644 index 000000000..df52ccb87 --- /dev/null +++ b/toolsrc/src/vcpkg-tests/statusparagraphs.cpp @@ -0,0 +1,110 @@ +#include +#include + +#include +#include +#include + +using namespace vcpkg; +using namespace vcpkg::Paragraphs; +using namespace vcpkg::Test; + +TEST_CASE ("find installed", "[statusparagraphs]") +{ + auto pghs = parse_paragraphs(R"( +Package: ffmpeg +Version: 3.3.3 +Architecture: x64-windows +Multi-Arch: same +Description: +Status: install ok installed +)"); + + REQUIRE(pghs); + + StatusParagraphs status_db( + Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); + + auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); + REQUIRE(it != status_db.end()); +} + +TEST_CASE ("find not installed", "[statusparagraphs]") +{ + auto pghs = parse_paragraphs(R"( +Package: ffmpeg +Version: 3.3.3 +Architecture: x64-windows +Multi-Arch: same +Description: +Status: purge ok not-installed +)"); + + REQUIRE(pghs); + + StatusParagraphs status_db( + Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); + + auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); + REQUIRE(it == status_db.end()); +} + +TEST_CASE ("find with feature packages", "[statusparagraphs]") +{ + auto pghs = parse_paragraphs(R"( +Package: ffmpeg +Version: 3.3.3 +Architecture: x64-windows +Multi-Arch: same +Description: +Status: install ok installed + +Package: ffmpeg +Feature: openssl +Depends: openssl +Architecture: x64-windows +Multi-Arch: same +Description: +Status: purge ok not-installed +)"); + + REQUIRE(pghs); + + StatusParagraphs status_db( + Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); + + auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); + REQUIRE(it != status_db.end()); + + // Feature "openssl" is not installed and should not be found + auto it1 = status_db.find_installed({unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS), "openssl"}); + REQUIRE(it1 == status_db.end()); +} + +TEST_CASE ("find for feature packages", "[statusparagraphs]") +{ + auto pghs = parse_paragraphs(R"( +Package: ffmpeg +Version: 3.3.3 +Architecture: x64-windows +Multi-Arch: same +Description: +Status: install ok installed + +Package: ffmpeg +Feature: openssl +Depends: openssl +Architecture: x64-windows +Multi-Arch: same +Description: +Status: install ok installed +)"); + REQUIRE(pghs); + + StatusParagraphs status_db( + Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); + + // Feature "openssl" is installed and should therefore be found + auto it = status_db.find_installed({unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS), "openssl"}); + REQUIRE(it != status_db.end()); +} diff --git a/toolsrc/src/vcpkg-tests/supports.cpp b/toolsrc/src/vcpkg-tests/supports.cpp new file mode 100644 index 000000000..c6c88bdbc --- /dev/null +++ b/toolsrc/src/vcpkg-tests/supports.cpp @@ -0,0 +1,79 @@ +#include + +#include + +using namespace vcpkg; +using Parse::parse_comma_list; + +TEST_CASE ("parse supports all", "[supports]") +{ + auto v = Supports::parse({ + "x64", + "x86", + "arm", + "windows", + "uwp", + "v140", + "v141", + "crt-static", + "crt-dynamic", + }); + + REQUIRE(v.has_value()); + + REQUIRE(v.get()->is_supported(System::CPUArchitecture::X64, + Supports::Platform::UWP, + Supports::Linkage::DYNAMIC, + Supports::ToolsetVersion::V140)); + REQUIRE(v.get()->is_supported(System::CPUArchitecture::ARM, + Supports::Platform::WINDOWS, + Supports::Linkage::STATIC, + Supports::ToolsetVersion::V141)); +} + +TEST_CASE ("parse supports invalid", "[supports]") +{ + auto v = Supports::parse({"arm64"}); + + REQUIRE_FALSE(v.has_value()); + + REQUIRE(v.error().size() == 1); + REQUIRE(v.error().at(0) == "arm64"); +} + +TEST_CASE ("parse supports case sensitive", "[supports]") +{ + auto v = Supports::parse({"Windows"}); + + REQUIRE_FALSE(v.has_value()); + REQUIRE(v.error().size() == 1); + REQUIRE(v.error().at(0) == "Windows"); +} + +TEST_CASE ("parse supports some", "[supports]") +{ + auto v = Supports::parse({ + "x64", + "x86", + "windows", + }); + + REQUIRE(v.has_value()); + + REQUIRE(v.get()->is_supported(System::CPUArchitecture::X64, + Supports::Platform::WINDOWS, + Supports::Linkage::DYNAMIC, + Supports::ToolsetVersion::V140)); + REQUIRE_FALSE(v.get()->is_supported(System::CPUArchitecture::ARM, + Supports::Platform::WINDOWS, + Supports::Linkage::DYNAMIC, + Supports::ToolsetVersion::V140)); + REQUIRE_FALSE(v.get()->is_supported(System::CPUArchitecture::X64, + Supports::Platform::UWP, + Supports::Linkage::DYNAMIC, + Supports::ToolsetVersion::V140)); + REQUIRE(v.get()->is_supported(System::CPUArchitecture::X64, + Supports::Platform::WINDOWS, + Supports::Linkage::STATIC, + Supports::ToolsetVersion::V141)); +} diff --git a/toolsrc/src/vcpkg-tests/update.cpp b/toolsrc/src/vcpkg-tests/update.cpp new file mode 100644 index 000000000..93a8f74a9 --- /dev/null +++ b/toolsrc/src/vcpkg-tests/update.cpp @@ -0,0 +1,102 @@ +#include +#include + +#include + +#include + +using namespace vcpkg; +using namespace vcpkg::Update; +using namespace vcpkg::Test; + +using Pgh = std::vector>; + +TEST_CASE ("find outdated packages basic", "[update]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.version = "2"; + + StatusParagraphs status_db(std::move(status_paragraphs)); + + std::unordered_map map; + auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); + map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); + Dependencies::MapPortFileProvider provider(map); + + auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), + &OutdatedPackage::compare_by_name); + + REQUIRE(pkgs.size() == 1); + REQUIRE(pkgs[0].version_diff.left.to_string() == "2"); + REQUIRE(pkgs[0].version_diff.right.to_string() == "0"); +} + +TEST_CASE ("find outdated packages features", "[update]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.version = "2"; + + status_paragraphs.push_back(make_status_feature_pgh("a", "b")); + status_paragraphs.back()->package.version = "2"; + + StatusParagraphs status_db(std::move(status_paragraphs)); + + std::unordered_map map; + auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); + map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); + Dependencies::MapPortFileProvider provider(map); + + auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), + &OutdatedPackage::compare_by_name); + + REQUIRE(pkgs.size() == 1); + REQUIRE(pkgs[0].version_diff.left.to_string() == "2"); + REQUIRE(pkgs[0].version_diff.right.to_string() == "0"); +} + +TEST_CASE ("find outdated packages features 2", "[update]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.version = "2"; + + status_paragraphs.push_back(make_status_feature_pgh("a", "b")); + status_paragraphs.back()->package.version = "0"; + status_paragraphs.back()->state = InstallState::NOT_INSTALLED; + status_paragraphs.back()->want = Want::PURGE; + + StatusParagraphs status_db(std::move(status_paragraphs)); + + std::unordered_map map; + auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); + map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); + Dependencies::MapPortFileProvider provider(map); + + auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), + &OutdatedPackage::compare_by_name); + + REQUIRE(pkgs.size() == 1); + REQUIRE(pkgs[0].version_diff.left.to_string() == "2"); + REQUIRE(pkgs[0].version_diff.right.to_string() == "0"); +} + +TEST_CASE ("find outdated packages none", "[update]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.version = "2"; + + StatusParagraphs status_db(std::move(status_paragraphs)); + + std::unordered_map map; + auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "2"}}})); + map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); + Dependencies::MapPortFileProvider provider(map); + + auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), + &OutdatedPackage::compare_by_name); + + REQUIRE(pkgs.size() == 0); +} diff --git a/toolsrc/src/vcpkg-tests/util.cpp b/toolsrc/src/vcpkg-tests/util.cpp new file mode 100644 index 000000000..54102f1aa --- /dev/null +++ b/toolsrc/src/vcpkg-tests/util.cpp @@ -0,0 +1,47 @@ +#include +#include + +#include + +#include + +namespace vcpkg::Test +{ + std::unique_ptr make_status_pgh(const char* name, + const char* depends, + const char* default_features, + const char* triplet) + { + using Pgh = std::unordered_map; + return std::make_unique(Pgh{{"Package", name}, + {"Version", "1"}, + {"Architecture", triplet}, + {"Multi-Arch", "same"}, + {"Depends", depends}, + {"Default-Features", default_features}, + {"Status", "install ok installed"}}); + } + + std::unique_ptr make_status_feature_pgh(const char* name, + const char* feature, + const char* depends, + const char* triplet) + { + using Pgh = std::unordered_map; + return std::make_unique(Pgh{{"Package", name}, + {"Version", "1"}, + {"Feature", feature}, + {"Architecture", triplet}, + {"Multi-Arch", "same"}, + {"Depends", depends}, + {"Status", "install ok installed"}}); + } + + PackageSpec unsafe_pspec(std::string name, Triplet t) + { + auto m_ret = PackageSpec::from_name_and_triplet(name, t); + REQUIRE(m_ret.has_value()); + return m_ret.value_or_exit(VCPKG_LINE_INFO); + } + +} -- cgit v1.2.3 From 618fa203c13c30bd19826988cff66481bca0562f Mon Sep 17 00:00:00 2001 From: Curtis J Bezault Date: Fri, 19 Jul 2019 08:01:38 -0700 Subject: [vcpkg] Portfile Settings (#7292) --- toolsrc/src/vcpkg/build.cpp | 24 ++++++++++++++++++------ toolsrc/src/vcpkg/commands.ci.cpp | 12 +++++++++--- toolsrc/src/vcpkg/install.cpp | 3 +-- 3 files changed, 28 insertions(+), 11 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 2f58a3341..b99f300d3 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -64,7 +64,7 @@ namespace vcpkg::Build::Command features_as_set.emplace("core"); const Build::BuildPackageConfig build_config{ - scf, spec.triplet(), fs::path(scfl.source_location), build_package_options, features_as_set}; + scfl, spec.triplet(), build_package_options, features_as_set}; const auto build_timer = Chrono::ElapsedTimer::create_started(); const auto result = Build::build_package(paths, build_config, status_db); @@ -402,6 +402,7 @@ namespace vcpkg::Build {"CURRENT_PORT_DIR", config.port_dir}, {"TARGET_TRIPLET", triplet.canonical_name()}, {"TARGET_TRIPLET_FILE", paths.get_triplet_file_path(triplet).u8string()}, + {"ENV_OVERRIDES_FILE", config.port_dir / "environment-overrides.cmake"}, {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()}, {"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"}, {"DOWNLOADS", paths.downloads}, @@ -783,7 +784,8 @@ namespace vcpkg::Build AbiEntry{status_it->get()->package.spec.name(), status_it->get()->package.abi}); } - const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet); + const auto pre_build_info = + PreBuildInfo::from_triplet_file(paths, triplet, config.scfl); auto maybe_abi_tag_and_file = compute_abi_tag(paths, config, pre_build_info, dependency_abis); @@ -998,7 +1000,9 @@ namespace vcpkg::Build return inner_create_buildinfo(*pghs.get()); } - PreBuildInfo PreBuildInfo::from_triplet_file(const VcpkgPaths& paths, const Triplet& triplet) + PreBuildInfo PreBuildInfo::from_triplet_file(const VcpkgPaths& paths, + const Triplet& triplet, + Optional port) { static constexpr CStringView FLAG_GUID = "c35112b6-d1ba-415b-aa5d-81de856ef8eb"; @@ -1006,11 +1010,19 @@ namespace vcpkg::Build const fs::path ports_cmake_script_path = paths.scripts / "get_triplet_environment.cmake"; const fs::path triplet_file_path = paths.get_triplet_file_path(triplet); + std::vector args{{"CMAKE_TRIPLET_FILE", triplet_file_path}}; + + if (port) + { + args.emplace_back( + "CMAKE_ENV_OVERRIDES_FILE", + port.value_or_exit(VCPKG_LINE_INFO).source_location / "environment-overrides.cmake"); + } + const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, ports_cmake_script_path, - { - {"CMAKE_TRIPLET_FILE", triplet_file_path}, - }); + args); + const auto ec_data = System::cmd_execute_and_capture_output(cmd_launch_cmake); Checks::check_exit(VCPKG_LINE_INFO, ec_data.exit_code == 0, ec_data.output); diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index c12c26ff7..b4290baab 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -237,9 +237,8 @@ namespace vcpkg::Commands::CI auto triplet = p->spec.triplet(); const Build::BuildPackageConfig build_config{ - *scfl->source_control_file, + *scfl, triplet, - static_cast(scfl->source_location), build_options, p->feature_list }; @@ -254,7 +253,14 @@ namespace vcpkg::Commands::CI return {spec.name(), it->second}; }); const auto& pre_build_info = pre_build_info_cache.get_lazy( - triplet, [&]() { return Build::PreBuildInfo::from_triplet_file(paths, triplet); }); + triplet, + [&]() { + return Build::PreBuildInfo::from_triplet_file( + paths, + triplet, + *scfl); + } + ); auto maybe_tag_and_file = Build::compute_abi_tag(paths, build_config, pre_build_info, dependency_abis); diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index de19c360a..425a4cdbc 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -331,9 +331,8 @@ namespace vcpkg::Install auto result = [&]() -> Build::ExtendedBuildResult { const auto& scfl = action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO); - const Build::BuildPackageConfig build_config{*scfl.source_control_file, + const Build::BuildPackageConfig build_config{scfl, action.spec.triplet(), - static_cast(scfl.source_location), action.build_options, action.feature_list}; return Build::build_package(paths, build_config, status_db); -- cgit v1.2.3 From c55ea0a0d5229b9dd79aa8ea888f6c0408f9e5dd Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 19 Jul 2019 12:56:24 -0700 Subject: switch to new test framework --- toolsrc/src/tests.files.cpp | 158 ------------------------------------ toolsrc/src/tests.strings.cpp | 41 ---------- toolsrc/src/vcpkg-tests/files.cpp | 124 ++++++++++++++++++++++++++++ toolsrc/src/vcpkg-tests/strings.cpp | 33 ++++++++ toolsrc/src/vcpkg-tests/util.cpp | 54 ++++++++++++ toolsrc/src/vcpkg/build.cpp | 48 ----------- 6 files changed, 211 insertions(+), 247 deletions(-) delete mode 100644 toolsrc/src/tests.files.cpp delete mode 100644 toolsrc/src/tests.strings.cpp create mode 100644 toolsrc/src/vcpkg-tests/files.cpp create mode 100644 toolsrc/src/vcpkg-tests/strings.cpp (limited to 'toolsrc/src') diff --git a/toolsrc/src/tests.files.cpp b/toolsrc/src/tests.files.cpp deleted file mode 100644 index 482675c34..000000000 --- a/toolsrc/src/tests.files.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include "tests.pch.h" - -#include -#include - -#include // required for filesystem::create_{directory_}symlink -#include -#include - -#include - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - -namespace UnitTest1 -{ - class FilesTest : public TestClass - { - using uid = std::uniform_int_distribution; - - public: - FilesTest() - { - HKEY key; - const auto status = RegOpenKeyExW( - HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock)", 0, 0, &key); - - if (status == ERROR_FILE_NOT_FOUND) - { - ALLOW_SYMLINKS = false; - std::clog << "Symlinks are not allowed on this system\n"; - } - else - { - // if we get a permissions error, we still know that we're in developer mode - ALLOW_SYMLINKS = true; - } - - if (status == ERROR_SUCCESS) RegCloseKey(key); - } - - private: - TEST_METHOD(remove_all) - { - auto urbg = get_urbg(0); - - fs::path temp_dir; - - { - wchar_t* tmp = static_cast(calloc(32'767, 2)); - - if (!GetEnvironmentVariableW(L"TEMP", tmp, 32'767)) - { - Assert::Fail(L"GetEnvironmentVariable(\"TEMP\") failed"); - } - - temp_dir = tmp; - - std::string dir_name = "vcpkg-tmp-dir-"; - dir_name += get_random_filename(urbg); - - temp_dir /= dir_name; - } - - auto& fs = vcpkg::Files::get_real_filesystem(); - - std::clog << "temp dir is: " << temp_dir << '\n'; - - create_directory_tree(urbg, fs, 0, temp_dir); - - std::error_code ec; - fs::path fp; - fs.remove_all(temp_dir, ec, fp); - Assert::IsFalse(bool(ec)); - - Assert::IsFalse(fs.exists(temp_dir)); - } - - bool ALLOW_SYMLINKS; - - std::mt19937_64 get_urbg(std::uint64_t index) - { - // smallest prime > 2**63 - 1 - return std::mt19937_64{index + 9223372036854775837}; - } - - std::string get_random_filename(std::mt19937_64& urbg) { return vcpkg::Strings::b32_encode(uid{}(urbg)); } - - void create_directory_tree(std::mt19937_64& urbg, - vcpkg::Files::Filesystem& fs, - std::uint64_t depth, - const fs::path& base) - { - std::random_device rd; - constexpr std::uint64_t max_depth = 5; - constexpr std::uint64_t width = 5; - - // we want ~70% of our "files" to be directories, and then a third - // each of the remaining ~30% to be regular files, directory symlinks, - // and regular symlinks - constexpr std::uint64_t directory_min_tag = 0; - constexpr std::uint64_t directory_max_tag = 6; - constexpr std::uint64_t regular_file_tag = 7; - constexpr std::uint64_t regular_symlink_tag = 8; - constexpr std::uint64_t directory_symlink_tag = 9; - - // if we're at the max depth, we only want to build non-directories - std::uint64_t file_type; - if (depth < max_depth) - { - file_type = uid{directory_min_tag, regular_symlink_tag}(urbg); - } - else - { - file_type = uid{regular_file_tag, regular_symlink_tag}(urbg); - } - - if (!ALLOW_SYMLINKS && file_type > regular_file_tag) - { - file_type = regular_file_tag; - } - - std::error_code ec; - if (type <= directory_max_tag) - { - fs.create_directory(base, ec); - Assert::IsFalse(bool(ec)); - - for (int i = 0; i < width; ++i) - { - create_directory_tree(urbg, fs, depth + 1, base / get_random_filename(urbg)); - } - } - else if (type == regular_file_tag) - { - // regular file - fs.write_contents(base, "", ec); - } - else if (type == regular_symlink_tag) - { - // regular symlink - fs.write_contents(base, "", ec); - Assert::IsFalse(bool(ec)); - const std::filesystem::path basep = base.native(); - auto basep_link = basep; - basep_link.replace_filename(basep.filename().native() + L"-link"); - std::filesystem::create_symlink(basep, basep_link, ec); - } - else // type == directory_symlink_tag - { - // directory symlink - std::filesystem::path basep = base.native(); - std::filesystem::create_directory_symlink(basep / "..", basep, ec); - } - - Assert::IsFalse(bool(ec)); - } - }; -} diff --git a/toolsrc/src/tests.strings.cpp b/toolsrc/src/tests.strings.cpp deleted file mode 100644 index f541a203d..000000000 --- a/toolsrc/src/tests.strings.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "tests.pch.h" - -#include - -#include -#include -#include - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - -namespace UnitTest1 -{ - class StringsTest : public TestClass - { - TEST_METHOD(b64url_encode) - { - using u64 = std::uint64_t; - - std::vector> map; - - map.emplace_back(0, "AAAAAAAAAAAAA"); - map.emplace_back(1, "BAAAAAAAAAAAA"); - - map.emplace_back(u64(1) << 32, "AAAAAAEAAAAAA"); - map.emplace_back((u64(1) << 32) + 1, "BAAAAAEAAAAAA"); - - map.emplace_back(0xE4D0'1065'D11E'0229, "JRA4RIXMQAUJO"); - map.emplace_back(0xA626'FE45'B135'07FF, "77BKTYWI6XJMK"); - map.emplace_back(0xEE36'D228'0C31'D405, "FAVDDGAFSWN4O"); - map.emplace_back(0x1405'64E7'FE7E'A88C, "MEK5H774ELBIB"); - map.emplace_back(0xFFFF'FFFF'FFFF'FFFF, "777777777777P"); - - std::string result; - for (const auto& pr : map) - { - result = vcpkg::Strings::b32_encode(pr.first); - Assert::AreEqual(result, pr.second); - } - } - }; -} diff --git a/toolsrc/src/vcpkg-tests/files.cpp b/toolsrc/src/vcpkg-tests/files.cpp new file mode 100644 index 000000000..d2edffcff --- /dev/null +++ b/toolsrc/src/vcpkg-tests/files.cpp @@ -0,0 +1,124 @@ +#include +#include + +#include +#include + +#include // required for filesystem::create_{directory_}symlink +#include +#include + +#include + +using vcpkg::Test::SYMLINKS_ALLOWED; +using vcpkg::Test::TEMPORARY_DIRECTORY; + +namespace +{ + using uid = std::uniform_int_distribution; + + std::mt19937_64 get_urbg(std::uint64_t index) + { + // smallest prime > 2**63 - 1 + return std::mt19937_64{index + 9223372036854775837}; + } + + std::string get_random_filename(std::mt19937_64& urbg) { return vcpkg::Strings::b32_encode(uid{}(urbg)); } + + void create_directory_tree(std::mt19937_64& urbg, + vcpkg::Files::Filesystem& fs, + std::uint64_t depth, + const fs::path& base) + { + std::random_device rd; + constexpr std::uint64_t max_depth = 5; + constexpr std::uint64_t width = 5; + + // we want ~70% of our "files" to be directories, and then a third + // each of the remaining ~30% to be regular files, directory symlinks, + // and regular symlinks + constexpr std::uint64_t directory_min_tag = 0; + constexpr std::uint64_t directory_max_tag = 6; + constexpr std::uint64_t regular_file_tag = 7; + constexpr std::uint64_t regular_symlink_tag = 8; + constexpr std::uint64_t directory_symlink_tag = 9; + + // if we're at the max depth, we only want to build non-directories + std::uint64_t file_type; + if (depth < max_depth) + { + file_type = uid{directory_min_tag, regular_symlink_tag}(urbg); + } + else + { + file_type = uid{regular_file_tag, regular_symlink_tag}(urbg); + } + + if (!SYMLINKS_ALLOWED && file_type > regular_file_tag) + { + file_type = regular_file_tag; + } + + std::error_code ec; + if (file_type <= directory_max_tag) + { + fs.create_directory(base, ec); + if (ec) { + INFO("File that failed: " << base); + REQUIRE_FALSE(ec); + } + + for (int i = 0; i < width; ++i) + { + create_directory_tree(urbg, fs, depth + 1, base / get_random_filename(urbg)); + } + } + else if (file_type == regular_file_tag) + { + // regular file + fs.write_contents(base, "", ec); + } + else if (file_type == regular_symlink_tag) + { + // regular symlink + fs.write_contents(base, "", ec); + REQUIRE_FALSE(ec); + const std::filesystem::path basep = base.native(); + auto basep_link = basep; + basep_link.replace_filename(basep.filename().native() + L"-link"); + std::filesystem::create_symlink(basep, basep_link, ec); + } + else // type == directory_symlink_tag + { + // directory symlink + std::filesystem::path basep = base.native(); + std::filesystem::create_directory_symlink(basep / "..", basep, ec); + } + + REQUIRE_FALSE(ec); + } +} + +TEST_CASE ("remove all", "[files]") +{ + auto urbg = get_urbg(0); + + fs::path temp_dir = TEMPORARY_DIRECTORY / get_random_filename(urbg); + + auto& fs = vcpkg::Files::get_real_filesystem(); + + std::error_code ec; + fs.create_directory(TEMPORARY_DIRECTORY, ec); + + REQUIRE_FALSE(ec); + + INFO("temp dir is: " << temp_dir); + + create_directory_tree(urbg, fs, 0, temp_dir); + + fs::path fp; + fs.remove_all(temp_dir, ec, fp); + REQUIRE_FALSE(ec); + + REQUIRE_FALSE(fs.exists(temp_dir)); +} diff --git a/toolsrc/src/vcpkg-tests/strings.cpp b/toolsrc/src/vcpkg-tests/strings.cpp new file mode 100644 index 000000000..3168a7c95 --- /dev/null +++ b/toolsrc/src/vcpkg-tests/strings.cpp @@ -0,0 +1,33 @@ +#include + +#include + +#include +#include +#include + +TEST_CASE ("b32 encoding", "[strings]") +{ + using u64 = std::uint64_t; + + std::vector> map; + + map.emplace_back(0, "AAAAAAAAAAAAA"); + map.emplace_back(1, "BAAAAAAAAAAAA"); + + map.emplace_back(u64(1) << 32, "AAAAAAEAAAAAA"); + map.emplace_back((u64(1) << 32) + 1, "BAAAAAEAAAAAA"); + + map.emplace_back(0xE4D0'1065'D11E'0229, "JRA4RIXMQAUJO"); + map.emplace_back(0xA626'FE45'B135'07FF, "77BKTYWI6XJMK"); + map.emplace_back(0xEE36'D228'0C31'D405, "FAVDDGAFSWN4O"); + map.emplace_back(0x1405'64E7'FE7E'A88C, "MEK5H774ELBIB"); + map.emplace_back(0xFFFF'FFFF'FFFF'FFFF, "777777777777P"); + + std::string result; + for (const auto& pr : map) + { + result = vcpkg::Strings::b32_encode(pr.first); + REQUIRE(vcpkg::Strings::b32_encode(pr.first) == pr.second); + } +} diff --git a/toolsrc/src/vcpkg-tests/util.cpp b/toolsrc/src/vcpkg-tests/util.cpp index 54102f1aa..f14628379 100644 --- a/toolsrc/src/vcpkg-tests/util.cpp +++ b/toolsrc/src/vcpkg-tests/util.cpp @@ -1,10 +1,16 @@ #include #include +#include #include +#include #include +#if defined(_WIN32) +#include +#endif + namespace vcpkg::Test { std::unique_ptr make_status_pgh(const char* name, @@ -44,4 +50,52 @@ namespace vcpkg::Test return m_ret.value_or_exit(VCPKG_LINE_INFO); } + + #if defined(_WIN32) + + static bool system_allows_symlinks() { + HKEY key; + bool allow_symlinks = true; + + const auto status = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock)", 0, 0, &key); + + if (status == ERROR_FILE_NOT_FOUND) + { + allow_symlinks = false; + std::clog << "Symlinks are not allowed on this system\n"; + } + + if (status == ERROR_SUCCESS) RegCloseKey(key); + + return allow_symlinks; + } + + static fs::path internal_temporary_directory() { + wchar_t* tmp = static_cast(std::calloc(32'767, 2)); + + if (!GetEnvironmentVariableW(L"TEMP", tmp, 32'767)) { + std::cerr << "No temporary directory found.\n"; + std::abort(); + } + + fs::path result = tmp; + std::free(tmp); + + return result / L"vcpkg-test"; + } + + #else + + constexpr static bool system_allows_symlinks() { + return true; + } + static fs::path internal_temporary_directory() { + return "/tmp/vcpkg-test"; + } + + #endif + + const bool SYMLINKS_ALLOWED = system_allows_symlinks(); + const fs::path TEMPORARY_DIRECTORY = internal_temporary_directory(); } diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index d9305b271..235adb819 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -1097,56 +1097,8 @@ namespace vcpkg::Build } } -<<<<<<< HEAD - pre_build_info.triplet_abi_tag = [&]() { - const auto& fs = paths.get_filesystem(); - static std::map s_hash_cache; - - auto it_hash = s_hash_cache.find(triplet_file_path); - if (it_hash != s_hash_cache.end()) - { - return it_hash->second; - } - auto hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1"); - - if (auto p = pre_build_info.external_toolchain_file.get()) - { - hash += "-"; - hash += Hash::get_file_hash(fs, *p, "SHA1"); - } - else if (pre_build_info.cmake_system_name.empty() || pre_build_info.cmake_system_name == "WindowsStore") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "windows.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Linux") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Darwin") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "FreeBSD") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1"); - } - else if (pre_build_info.cmake_system_name == "Android") - { - hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1"); - } - - s_hash_cache.emplace(triplet_file_path, hash); - return hash; - }(); -======= pre_build_info.triplet_abi_tag = get_triplet_abi(paths, pre_build_info, triplet); ->>>>>>> trunk return pre_build_info; } -- cgit v1.2.3 From 0d8bba52e4c0a861b25f9d32006bfde9b749e09f Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 19 Jul 2019 23:20:28 -0700 Subject: allow tests to run on older standard libraries --- toolsrc/src/vcpkg-test/arguments.cpp | 109 +++ toolsrc/src/vcpkg-test/catch.cpp | 11 + toolsrc/src/vcpkg-test/chrono.cpp | 34 + toolsrc/src/vcpkg-test/dependencies.cpp | 28 + toolsrc/src/vcpkg-test/files.cpp | 121 +++ toolsrc/src/vcpkg-test/paragraph.cpp | 445 +++++++++ toolsrc/src/vcpkg-test/plan.cpp | 1241 ++++++++++++++++++++++++++ toolsrc/src/vcpkg-test/specifier.cpp | 134 +++ toolsrc/src/vcpkg-test/statusparagraphs.cpp | 110 +++ toolsrc/src/vcpkg-test/strings.cpp | 33 + toolsrc/src/vcpkg-test/supports.cpp | 79 ++ toolsrc/src/vcpkg-test/update.cpp | 102 +++ toolsrc/src/vcpkg-test/util.cpp | 158 ++++ toolsrc/src/vcpkg-tests/arguments.cpp | 109 --- toolsrc/src/vcpkg-tests/catch.cpp | 11 - toolsrc/src/vcpkg-tests/chrono.cpp | 34 - toolsrc/src/vcpkg-tests/dependencies.cpp | 28 - toolsrc/src/vcpkg-tests/files.cpp | 124 --- toolsrc/src/vcpkg-tests/paragraph.cpp | 445 --------- toolsrc/src/vcpkg-tests/plan.cpp | 1241 -------------------------- toolsrc/src/vcpkg-tests/specifier.cpp | 134 --- toolsrc/src/vcpkg-tests/statusparagraphs.cpp | 110 --- toolsrc/src/vcpkg-tests/strings.cpp | 33 - toolsrc/src/vcpkg-tests/supports.cpp | 79 -- toolsrc/src/vcpkg-tests/update.cpp | 102 --- toolsrc/src/vcpkg-tests/util.cpp | 101 --- 26 files changed, 2605 insertions(+), 2551 deletions(-) create mode 100644 toolsrc/src/vcpkg-test/arguments.cpp create mode 100644 toolsrc/src/vcpkg-test/catch.cpp create mode 100644 toolsrc/src/vcpkg-test/chrono.cpp create mode 100644 toolsrc/src/vcpkg-test/dependencies.cpp create mode 100644 toolsrc/src/vcpkg-test/files.cpp create mode 100644 toolsrc/src/vcpkg-test/paragraph.cpp create mode 100644 toolsrc/src/vcpkg-test/plan.cpp create mode 100644 toolsrc/src/vcpkg-test/specifier.cpp create mode 100644 toolsrc/src/vcpkg-test/statusparagraphs.cpp create mode 100644 toolsrc/src/vcpkg-test/strings.cpp create mode 100644 toolsrc/src/vcpkg-test/supports.cpp create mode 100644 toolsrc/src/vcpkg-test/update.cpp create mode 100644 toolsrc/src/vcpkg-test/util.cpp delete mode 100644 toolsrc/src/vcpkg-tests/arguments.cpp delete mode 100644 toolsrc/src/vcpkg-tests/catch.cpp delete mode 100644 toolsrc/src/vcpkg-tests/chrono.cpp delete mode 100644 toolsrc/src/vcpkg-tests/dependencies.cpp delete mode 100644 toolsrc/src/vcpkg-tests/files.cpp delete mode 100644 toolsrc/src/vcpkg-tests/paragraph.cpp delete mode 100644 toolsrc/src/vcpkg-tests/plan.cpp delete mode 100644 toolsrc/src/vcpkg-tests/specifier.cpp delete mode 100644 toolsrc/src/vcpkg-tests/statusparagraphs.cpp delete mode 100644 toolsrc/src/vcpkg-tests/strings.cpp delete mode 100644 toolsrc/src/vcpkg-tests/supports.cpp delete mode 100644 toolsrc/src/vcpkg-tests/update.cpp delete mode 100644 toolsrc/src/vcpkg-tests/util.cpp (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/arguments.cpp b/toolsrc/src/vcpkg-test/arguments.cpp new file mode 100644 index 000000000..3fe5fa420 --- /dev/null +++ b/toolsrc/src/vcpkg-test/arguments.cpp @@ -0,0 +1,109 @@ +#include + +#include + +#include + +using vcpkg::CommandSetting; +using vcpkg::CommandStructure; +using vcpkg::CommandSwitch; +using vcpkg::VcpkgCmdArguments; + +TEST_CASE ("VcpkgCmdArguments from lowercase argument sequence", "[arguments]") +{ + std::vector t = {"--vcpkg-root", + "C:\\vcpkg", + "--scripts-root=C:\\scripts", + "--debug", + "--sendmetrics", + "--printmetrics", + "--overlay-ports=C:\\ports1", + "--overlay-ports=C:\\ports2", + "--overlay-triplets=C:\\tripletsA", + "--overlay-triplets=C:\\tripletsB"}; + auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); + + REQUIRE(*v.vcpkg_root_dir == "C:\\vcpkg"); + REQUIRE(*v.scripts_root_dir == "C:\\scripts"); + REQUIRE(v.debug); + REQUIRE(*v.debug.get()); + REQUIRE(v.sendmetrics); + REQUIRE(*v.sendmetrics.get()); + REQUIRE(v.printmetrics); + REQUIRE(*v.printmetrics.get()); + + REQUIRE(v.overlay_ports->size() == 2); + REQUIRE(v.overlay_ports->at(0) == "C:\\ports1"); + REQUIRE(v.overlay_ports->at(1) == "C:\\ports2"); + + REQUIRE(v.overlay_triplets->size() == 2); + REQUIRE(v.overlay_triplets->at(0) == "C:\\tripletsA"); + REQUIRE(v.overlay_triplets->at(1) == "C:\\tripletsB"); +} + +TEST_CASE ("VcpkgCmdArguments from uppercase argument sequence", "[arguments]") +{ + std::vector t = {"--VCPKG-ROOT", + "C:\\vcpkg", + "--SCRIPTS-ROOT=C:\\scripts", + "--DEBUG", + "--SENDMETRICS", + "--PRINTMETRICS", + "--OVERLAY-PORTS=C:\\ports1", + "--OVERLAY-PORTS=C:\\ports2", + "--OVERLAY-TRIPLETS=C:\\tripletsA", + "--OVERLAY-TRIPLETS=C:\\tripletsB"}; + auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); + + REQUIRE(*v.vcpkg_root_dir == "C:\\vcpkg"); + REQUIRE(*v.scripts_root_dir == "C:\\scripts"); + REQUIRE(v.debug); + REQUIRE(*v.debug.get()); + REQUIRE(v.sendmetrics); + REQUIRE(*v.sendmetrics.get()); + REQUIRE(v.printmetrics); + REQUIRE(*v.printmetrics.get()); + + REQUIRE(v.overlay_ports->size() == 2); + REQUIRE(v.overlay_ports->at(0) == "C:\\ports1"); + REQUIRE(v.overlay_ports->at(1) == "C:\\ports2"); + + REQUIRE(v.overlay_triplets->size() == 2); + REQUIRE(v.overlay_triplets->at(0) == "C:\\tripletsA"); + REQUIRE(v.overlay_triplets->at(1) == "C:\\tripletsB"); +} + +TEST_CASE ("VcpkgCmdArguments from argument sequence with valued options", "[arguments]") +{ + SECTION ("case 1") + { + std::array settings = {{{"--a", ""}}}; + CommandStructure cmdstruct = {"", 0, SIZE_MAX, {{}, settings}, nullptr}; + + std::vector t = {"--a=b", "command", "argument"}; + auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); + auto opts = v.parse_arguments(cmdstruct); + + REQUIRE(opts.settings["--a"] == "b"); + REQUIRE(v.command_arguments.size() == 1); + REQUIRE(v.command_arguments[0] == "argument"); + REQUIRE(v.command == "command"); + } + + SECTION ("case 2") + { + std::array switches = {{{"--a", ""}, {"--c", ""}}}; + std::array settings = {{{"--b", ""}, {"--d", ""}}}; + CommandStructure cmdstruct = {"", 0, SIZE_MAX, {switches, settings}, nullptr}; + + std::vector t = {"--a", "--b=c"}; + auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); + auto opts = v.parse_arguments(cmdstruct); + + REQUIRE(opts.settings["--b"] == "c"); + REQUIRE(opts.settings.find("--d") == opts.settings.end()); + REQUIRE(opts.switches.find("--a") != opts.switches.end()); + REQUIRE(opts.settings.find("--c") == opts.settings.end()); + REQUIRE(v.command_arguments.size() == 0); + } +} diff --git a/toolsrc/src/vcpkg-test/catch.cpp b/toolsrc/src/vcpkg-test/catch.cpp new file mode 100644 index 000000000..8b5d1aa15 --- /dev/null +++ b/toolsrc/src/vcpkg-test/catch.cpp @@ -0,0 +1,11 @@ +#define CATCH_CONFIG_RUNNER +#include + +#include + +int main(int argc, char** argv) +{ + vcpkg::Debug::g_debugging = true; + + return Catch::Session().run(argc, argv); +} diff --git a/toolsrc/src/vcpkg-test/chrono.cpp b/toolsrc/src/vcpkg-test/chrono.cpp new file mode 100644 index 000000000..306217ad0 --- /dev/null +++ b/toolsrc/src/vcpkg-test/chrono.cpp @@ -0,0 +1,34 @@ +#include + +#include + +namespace Chrono = vcpkg::Chrono; + +TEST_CASE ("parse time", "[chrono]") +{ + auto timestring = "1990-02-03T04:05:06.0Z"; + auto maybe_time = Chrono::CTime::parse(timestring); + + REQUIRE(maybe_time.has_value()); + REQUIRE(maybe_time.get()->to_string() == timestring); +} + +TEST_CASE ("parse blank time", "[chrono]") +{ + auto maybe_time = Chrono::CTime::parse(""); + + REQUIRE_FALSE(maybe_time.has_value()); +} + +TEST_CASE ("difference of times", "[chrono]") +{ + auto maybe_time1 = Chrono::CTime::parse("1990-02-03T04:05:06.0Z"); + auto maybe_time2 = Chrono::CTime::parse("1990-02-10T04:05:06.0Z"); + + REQUIRE(maybe_time1.has_value()); + REQUIRE(maybe_time2.has_value()); + + auto delta = maybe_time2.get()->to_time_point() - maybe_time1.get()->to_time_point(); + + REQUIRE(std::chrono::duration_cast(delta).count() == 24 * 7); +} diff --git a/toolsrc/src/vcpkg-test/dependencies.cpp b/toolsrc/src/vcpkg-test/dependencies.cpp new file mode 100644 index 000000000..5ed05cc07 --- /dev/null +++ b/toolsrc/src/vcpkg-test/dependencies.cpp @@ -0,0 +1,28 @@ +#include + +#include + +using namespace vcpkg; +using Parse::parse_comma_list; + +TEST_CASE ("parse depends", "[dependencies]") +{ + auto v = expand_qualified_dependencies(parse_comma_list("libA (windows)")); + REQUIRE(v.size() == 1); + REQUIRE(v.at(0).depend.name == "libA"); + REQUIRE(v.at(0).qualifier == "windows"); +} + +TEST_CASE ("filter depends", "[dependencies]") +{ + auto deps = expand_qualified_dependencies(parse_comma_list("libA (windows), libB, libC (uwp)")); + auto v = filter_dependencies(deps, Triplet::X64_WINDOWS); + REQUIRE(v.size() == 2); + REQUIRE(v.at(0) == "libA"); + REQUIRE(v.at(1) == "libB"); + + auto v2 = filter_dependencies(deps, Triplet::ARM_UWP); + REQUIRE(v.size() == 2); + REQUIRE(v2.at(0) == "libB"); + REQUIRE(v2.at(1) == "libC"); +} diff --git a/toolsrc/src/vcpkg-test/files.cpp b/toolsrc/src/vcpkg-test/files.cpp new file mode 100644 index 000000000..9e14cec0c --- /dev/null +++ b/toolsrc/src/vcpkg-test/files.cpp @@ -0,0 +1,121 @@ +#include +#include + +#include +#include + +#include +#include + +#include + +using vcpkg::Test::SYMLINKS_ALLOWED; +using vcpkg::Test::TEMPORARY_DIRECTORY; + +namespace +{ + using uid = std::uniform_int_distribution; + + std::mt19937_64 get_urbg(std::uint64_t index) + { + // smallest prime > 2**63 - 1 + return std::mt19937_64{index + 9223372036854775837ULL}; + } + + std::string get_random_filename(std::mt19937_64& urbg) { return vcpkg::Strings::b32_encode(uid{}(urbg)); } + + void create_directory_tree(std::mt19937_64& urbg, + vcpkg::Files::Filesystem& fs, + std::uint64_t depth, + const fs::path& base) + { + std::random_device rd; + constexpr std::uint64_t max_depth = 5; + constexpr std::uint64_t width = 5; + + // we want ~70% of our "files" to be directories, and then a third + // each of the remaining ~30% to be regular files, directory symlinks, + // and regular symlinks + constexpr std::uint64_t directory_min_tag = 0; + constexpr std::uint64_t directory_max_tag = 6; + constexpr std::uint64_t regular_file_tag = 7; + constexpr std::uint64_t regular_symlink_tag = 8; + constexpr std::uint64_t directory_symlink_tag = 9; + + // if we're at the max depth, we only want to build non-directories + std::uint64_t file_type; + if (depth < max_depth) + { + file_type = uid{directory_min_tag, regular_symlink_tag}(urbg); + } + else + { + file_type = uid{regular_file_tag, regular_symlink_tag}(urbg); + } + + if (!SYMLINKS_ALLOWED && file_type > regular_file_tag) + { + file_type = regular_file_tag; + } + + std::error_code ec; + if (file_type <= directory_max_tag) + { + fs.create_directory(base, ec); + if (ec) { + INFO("File that failed: " << base); + REQUIRE_FALSE(ec); + } + + for (int i = 0; i < width; ++i) + { + create_directory_tree(urbg, fs, depth + 1, base / get_random_filename(urbg)); + } + } + else if (file_type == regular_file_tag) + { + // regular file + fs.write_contents(base, "", ec); + } + else if (file_type == regular_symlink_tag) + { + // regular symlink + fs.write_contents(base, "", ec); + REQUIRE_FALSE(ec); + auto base_link = base; + base_link.replace_filename(base.filename().u8string() + "-link"); + vcpkg::Test::create_symlink(base, base_link, ec); + } + else // type == directory_symlink_tag + { + // directory symlink + vcpkg::Test::create_directory_symlink(base / "..", base, ec); + } + + REQUIRE_FALSE(ec); + } +} + +TEST_CASE ("remove all", "[files]") +{ + auto urbg = get_urbg(0); + + fs::path temp_dir = TEMPORARY_DIRECTORY / get_random_filename(urbg); + + auto& fs = vcpkg::Files::get_real_filesystem(); + + std::error_code ec; + fs.create_directory(TEMPORARY_DIRECTORY, ec); + + REQUIRE_FALSE(ec); + + INFO("temp dir is: " << temp_dir); + + create_directory_tree(urbg, fs, 0, temp_dir); + + fs::path fp; + fs.remove_all(temp_dir, ec, fp); + REQUIRE_FALSE(ec); + + REQUIRE_FALSE(fs.exists(temp_dir)); +} diff --git a/toolsrc/src/vcpkg-test/paragraph.cpp b/toolsrc/src/vcpkg-test/paragraph.cpp new file mode 100644 index 000000000..a95879cfa --- /dev/null +++ b/toolsrc/src/vcpkg-test/paragraph.cpp @@ -0,0 +1,445 @@ +#include +#include + +#include + +#include + +namespace Strings = vcpkg::Strings; + +TEST_CASE ("SourceParagraph construct minimum", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + }}); + + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->name == "zlib"); + REQUIRE(pgh.core_paragraph->version == "1.2.8"); + REQUIRE(pgh.core_paragraph->maintainer == ""); + REQUIRE(pgh.core_paragraph->description == ""); + REQUIRE(pgh.core_paragraph->depends.size() == 0); +} + +TEST_CASE ("SourceParagraph construct maximum", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "s"}, + {"Version", "v"}, + {"Maintainer", "m"}, + {"Description", "d"}, + {"Build-Depends", "bd"}, + {"Default-Features", "df"}, + {"Supports", "x64"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->name == "s"); + REQUIRE(pgh.core_paragraph->version == "v"); + REQUIRE(pgh.core_paragraph->maintainer == "m"); + REQUIRE(pgh.core_paragraph->description == "d"); + REQUIRE(pgh.core_paragraph->depends.size() == 1); + REQUIRE(pgh.core_paragraph->depends[0].name() == "bd"); + REQUIRE(pgh.core_paragraph->default_features.size() == 1); + REQUIRE(pgh.core_paragraph->default_features[0] == "df"); + REQUIRE(pgh.core_paragraph->supports.size() == 1); + REQUIRE(pgh.core_paragraph->supports[0] == "x64"); +} + +TEST_CASE ("SourceParagraph two depends", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + {"Build-Depends", "z, openssl"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->depends.size() == 2); + REQUIRE(pgh.core_paragraph->depends[0].name() == "z"); + REQUIRE(pgh.core_paragraph->depends[1].name() == "openssl"); +} + +TEST_CASE ("SourceParagraph three depends", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + {"Build-Depends", "z, openssl, xyz"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->depends.size() == 3); + REQUIRE(pgh.core_paragraph->depends[0].name() == "z"); + REQUIRE(pgh.core_paragraph->depends[1].name() == "openssl"); + REQUIRE(pgh.core_paragraph->depends[2].name() == "xyz"); +} + +TEST_CASE ("SourceParagraph three supports", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + {"Supports", "x64, windows, uwp"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->supports.size() == 3); + REQUIRE(pgh.core_paragraph->supports[0] == "x64"); + REQUIRE(pgh.core_paragraph->supports[1] == "windows"); + REQUIRE(pgh.core_paragraph->supports[2] == "uwp"); +} + +TEST_CASE ("SourceParagraph construct qualified depends", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + {"Build-Depends", "libA (windows), libB (uwp)"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->name == "zlib"); + REQUIRE(pgh.core_paragraph->version == "1.2.8"); + REQUIRE(pgh.core_paragraph->maintainer == ""); + REQUIRE(pgh.core_paragraph->description == ""); + REQUIRE(pgh.core_paragraph->depends.size() == 2); + REQUIRE(pgh.core_paragraph->depends[0].name() == "libA"); + REQUIRE(pgh.core_paragraph->depends[0].qualifier == "windows"); + REQUIRE(pgh.core_paragraph->depends[1].name() == "libB"); + REQUIRE(pgh.core_paragraph->depends[1].qualifier == "uwp"); +} + +TEST_CASE ("SourceParagraph default features", "[paragraph]") +{ + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector>{{ + {"Source", "a"}, + {"Version", "1.0"}, + {"Default-Features", "a1"}, + }}); + REQUIRE(m_pgh.has_value()); + auto& pgh = **m_pgh.get(); + + REQUIRE(pgh.core_paragraph->default_features.size() == 1); + REQUIRE(pgh.core_paragraph->default_features[0] == "a1"); +} + +TEST_CASE ("BinaryParagraph construct minimum", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + }); + + REQUIRE(pgh.spec.name() == "zlib"); + REQUIRE(pgh.version == "1.2.8"); + REQUIRE(pgh.maintainer == ""); + REQUIRE(pgh.description == ""); + REQUIRE(pgh.spec.triplet().canonical_name() == "x86-windows"); + REQUIRE(pgh.depends.size() == 0); +} + +TEST_CASE ("BinaryParagraph construct maximum", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "s"}, + {"Version", "v"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Maintainer", "m"}, + {"Description", "d"}, + {"Depends", "bd"}, + }); + + REQUIRE(pgh.spec.name() == "s"); + REQUIRE(pgh.version == "v"); + REQUIRE(pgh.maintainer == "m"); + REQUIRE(pgh.description == "d"); + REQUIRE(pgh.depends.size() == 1); + REQUIRE(pgh.depends[0] == "bd"); +} + +TEST_CASE ("BinaryParagraph three depends", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Depends", "a, b, c"}, + }); + + REQUIRE(pgh.depends.size() == 3); + REQUIRE(pgh.depends[0] == "a"); + REQUIRE(pgh.depends[1] == "b"); + REQUIRE(pgh.depends[2] == "c"); +} + +TEST_CASE ("BinaryParagraph abi", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Abi", "abcd123"}, + }); + + REQUIRE(pgh.depends.size() == 0); + REQUIRE(pgh.abi == "abcd123"); +} + +TEST_CASE ("BinaryParagraph default features", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "a"}, + {"Version", "1.0"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Default-Features", "a1"}, + }); + + REQUIRE(pgh.depends.size() == 0); + REQUIRE(pgh.default_features.size() == 1); + REQUIRE(pgh.default_features[0] == "a1"); +} + +TEST_CASE ("parse paragraphs empty", "[paragraph]") +{ + const char* str = ""; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + REQUIRE(pghs.empty()); +} + +TEST_CASE ("parse paragraphs one field", "[paragraph]") +{ + const char* str = "f1: v1"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 1); + REQUIRE(pghs[0]["f1"] == "v1"); +} + +TEST_CASE ("parse paragraphs one pgh", "[paragraph]") +{ + const char* str = "f1: v1\n" + "f2: v2"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 2); + REQUIRE(pghs[0]["f1"] == "v1"); + REQUIRE(pghs[0]["f2"] == "v2"); +} + +TEST_CASE ("parse paragraphs two pgh", "[paragraph]") +{ + const char* str = "f1: v1\n" + "f2: v2\n" + "\n" + "f3: v3\n" + "f4: v4"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 2); + REQUIRE(pghs[0].size() == 2); + REQUIRE(pghs[0]["f1"] == "v1"); + REQUIRE(pghs[0]["f2"] == "v2"); + REQUIRE(pghs[1].size() == 2); + REQUIRE(pghs[1]["f3"] == "v3"); + REQUIRE(pghs[1]["f4"] == "v4"); +} + +TEST_CASE ("parse paragraphs field names", "[paragraph]") +{ + const char* str = "1:\n" + "f:\n" + "F:\n" + "0:\n" + "F-2:\n"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 5); +} + +TEST_CASE ("parse paragraphs multiple blank lines", "[paragraph]") +{ + const char* str = "f1: v1\n" + "f2: v2\n" + "\n" + "\n" + "f3: v3\n" + "f4: v4"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 2); +} + +TEST_CASE ("parse paragraphs empty fields", "[paragraph]") +{ + const char* str = "f1:\n" + "f2: "; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 2); + REQUIRE(pghs[0]["f1"] == ""); + REQUIRE(pghs[0]["f2"] == ""); + REQUIRE(pghs[0].size() == 2); +} + +TEST_CASE ("parse paragraphs multiline fields", "[paragraph]") +{ + const char* str = "f1: simple\n" + " f1\r\n" + "f2:\r\n" + " f2\r\n" + " continue\r\n"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0]["f1"] == "simple\n f1"); + REQUIRE(pghs[0]["f2"] == "\n f2\n continue"); +} + +TEST_CASE ("parse paragraphs crlfs", "[paragraph]") +{ + const char* str = "f1: v1\r\n" + "f2: v2\r\n" + "\r\n" + "f3: v3\r\n" + "f4: v4"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 2); + REQUIRE(pghs[0].size() == 2); + REQUIRE(pghs[0]["f1"] == "v1"); + REQUIRE(pghs[0]["f2"] == "v2"); + REQUIRE(pghs[1].size() == 2); + REQUIRE(pghs[1]["f3"] == "v3"); + REQUIRE(pghs[1]["f4"] == "v4"); +} + +TEST_CASE ("parse paragraphs comment", "[paragraph]") +{ + const char* str = "f1: v1\r\n" + "#comment\r\n" + "f2: v2\r\n" + "#comment\r\n" + "\r\n" + "#comment\r\n" + "f3: v3\r\n" + "#comment\r\n" + "f4: v4"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 2); + REQUIRE(pghs[0].size() == 2); + REQUIRE(pghs[0]["f1"] == "v1"); + REQUIRE(pghs[0]["f2"] == "v2"); + REQUIRE(pghs[1].size()); + REQUIRE(pghs[1]["f3"] == "v3"); + REQUIRE(pghs[1]["f4"] == "v4"); +} + +TEST_CASE ("parse comment before single line feed", "[paragraph]") +{ + const char* str = "f1: v1\r\n" + "#comment\n"; + auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); + REQUIRE(pghs[0].size() == 1); + REQUIRE(pghs[0]["f1"] == "v1"); +} + +TEST_CASE ("BinaryParagraph serialize min", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + }); + std::string ss = Strings::serialize(pgh); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 4); + REQUIRE(pghs[0]["Package"] == "zlib"); + REQUIRE(pghs[0]["Version"] == "1.2.8"); + REQUIRE(pghs[0]["Architecture"] == "x86-windows"); + REQUIRE(pghs[0]["Multi-Arch"] == "same"); +} + +TEST_CASE ("BinaryParagraph serialize max", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Description", "first line\n second line"}, + {"Maintainer", "abc "}, + {"Depends", "dep"}, + {"Multi-Arch", "same"}, + }); + std::string ss = Strings::serialize(pgh); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0].size() == 7); + REQUIRE(pghs[0]["Package"] == "zlib"); + REQUIRE(pghs[0]["Version"] == "1.2.8"); + REQUIRE(pghs[0]["Architecture"] == "x86-windows"); + REQUIRE(pghs[0]["Multi-Arch"] == "same"); + REQUIRE(pghs[0]["Description"] == "first line\n second line"); + REQUIRE(pghs[0]["Depends"] == "dep"); +} + +TEST_CASE ("BinaryParagraph serialize multiple deps", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Depends", "a, b, c"}, + }); + std::string ss = Strings::serialize(pgh); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0]["Depends"] == "a, b, c"); +} + +TEST_CASE ("BinaryParagraph serialize abi", "[paragraph]") +{ + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Depends", "a, b, c"}, + {"Abi", "123abc"}, + }); + std::string ss = Strings::serialize(pgh); + auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); + + REQUIRE(pghs.size() == 1); + REQUIRE(pghs[0]["Abi"] == "123abc"); +} diff --git a/toolsrc/src/vcpkg-test/plan.cpp b/toolsrc/src/vcpkg-test/plan.cpp new file mode 100644 index 000000000..049ef2066 --- /dev/null +++ b/toolsrc/src/vcpkg-test/plan.cpp @@ -0,0 +1,1241 @@ +#include +#include + +#include +#include +#include + +#include +#include +#include + +using namespace vcpkg; + +using Test::make_status_feature_pgh; +using Test::make_status_pgh; +using Test::unsafe_pspec; + +static std::unique_ptr make_control_file( + const char* name, + const char* depends, + const std::vector>& features = {}, + const std::vector& default_features = {}) +{ + using Pgh = std::unordered_map; + std::vector scf_pghs; + scf_pghs.push_back(Pgh{{"Source", name}, + {"Version", "0"}, + {"Build-Depends", depends}, + {"Default-Features", Strings::join(", ", default_features)}}); + for (auto&& feature : features) + { + scf_pghs.push_back(Pgh{ + {"Feature", feature.first}, + {"Description", "feature"}, + {"Build-Depends", feature.second}, + }); + } + auto m_pgh = vcpkg::SourceControlFile::parse_control_file(std::move(scf_pghs)); + REQUIRE(m_pgh.has_value()); + return std::move(*m_pgh.get()); +} + +/// +/// Assert that the given action an install of given features from given package. +/// +static void features_check(Dependencies::AnyAction& install_action, + std::string pkg_name, + std::vector vec, + const Triplet& triplet = Triplet::X86_WINDOWS) +{ + REQUIRE(install_action.install_action.has_value()); + const auto& plan = install_action.install_action.value_or_exit(VCPKG_LINE_INFO); + const auto& feature_list = plan.feature_list; + + REQUIRE(plan.spec.triplet().to_string() == triplet.to_string()); + + auto& scfl = *plan.source_control_file_location.get(); + REQUIRE(pkg_name == scfl.source_control_file->core_paragraph->name); + REQUIRE(feature_list.size() == vec.size()); + + for (auto&& feature_name : vec) + { + // TODO: see if this can be simplified + if (feature_name == "core" || feature_name == "") + { + REQUIRE((Util::find(feature_list, "core") != feature_list.end() || + Util::find(feature_list, "") != feature_list.end())); + continue; + } + REQUIRE(Util::find(feature_list, feature_name) != feature_list.end()); + } +} + +/// +/// Assert that the given action is a remove of given package. +/// +static void remove_plan_check(Dependencies::AnyAction& remove_action, + std::string pkg_name, + const Triplet& triplet = Triplet::X86_WINDOWS) +{ + const auto& plan = remove_action.remove_action.value_or_exit(VCPKG_LINE_INFO); + REQUIRE(plan.spec.triplet().to_string() == triplet.to_string()); + REQUIRE(pkg_name == plan.spec.name()); +} + +/// +/// Map of source control files by their package name. +/// +struct PackageSpecMap +{ + std::unordered_map map; + Triplet triplet; + PackageSpecMap(const Triplet& t = Triplet::X86_WINDOWS) noexcept { triplet = t; } + + PackageSpec emplace(const char* name, + const char* depends = "", + const std::vector>& features = {}, + const std::vector& default_features = {}) + { + auto scfl = SourceControlFileLocation{make_control_file(name, depends, features, default_features), ""}; + return emplace(std::move(scfl)); + } + + PackageSpec emplace(vcpkg::SourceControlFileLocation&& scfl) + { + auto spec = PackageSpec::from_name_and_triplet(scfl.source_control_file->core_paragraph->name, triplet); + REQUIRE(spec.has_value()); + map.emplace(scfl.source_control_file->core_paragraph->name, std::move(scfl)); + return PackageSpec{*spec.get()}; + } +}; + +TEST_CASE ("basic install scheme", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "b"); + auto spec_b = spec_map.emplace("b", "c"); + auto spec_c = spec_map.emplace("c"); + + Dependencies::MapPortFileProvider map_port(spec_map.map); + auto install_plan = Dependencies::create_feature_install_plan( + map_port, {FeatureSpec{spec_a, ""}}, StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + REQUIRE(install_plan.at(0).spec().name() == "c"); + REQUIRE(install_plan.at(1).spec().name() == "b"); + REQUIRE(install_plan.at(2).spec().name() == "a"); +} + +TEST_CASE ("multiple install scheme", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "d"); + auto spec_b = spec_map.emplace("b", "d, e"); + auto spec_c = spec_map.emplace("c", "e, h"); + auto spec_d = spec_map.emplace("d", "f, g, h"); + auto spec_e = spec_map.emplace("e", "g"); + auto spec_f = spec_map.emplace("f"); + auto spec_g = spec_map.emplace("g"); + auto spec_h = spec_map.emplace("h"); + + Dependencies::MapPortFileProvider map_port(spec_map.map); + auto install_plan = Dependencies::create_feature_install_plan( + map_port, + {FeatureSpec{spec_a, ""}, FeatureSpec{spec_b, ""}, FeatureSpec{spec_c, ""}}, + StatusParagraphs(std::move(status_paragraphs))); + + auto iterator_pos = [&](const PackageSpec& spec) { + auto it = + std::find_if(install_plan.begin(), install_plan.end(), [&](auto& action) { return action.spec() == spec; }); + REQUIRE(it != install_plan.end()); + return it - install_plan.begin(); + }; + + const auto a_pos = iterator_pos(spec_a); + const auto b_pos = iterator_pos(spec_b); + const auto c_pos = iterator_pos(spec_c); + const auto d_pos = iterator_pos(spec_d); + const auto e_pos = iterator_pos(spec_e); + const auto f_pos = iterator_pos(spec_f); + const auto g_pos = iterator_pos(spec_g); + const auto h_pos = iterator_pos(spec_h); + + REQUIRE(a_pos > d_pos); + REQUIRE(b_pos > e_pos); + REQUIRE(b_pos > d_pos); + REQUIRE(c_pos > e_pos); + REQUIRE(c_pos > h_pos); + REQUIRE(d_pos > f_pos); + REQUIRE(d_pos > g_pos); + REQUIRE(d_pos > h_pos); + REQUIRE(e_pos > g_pos); +} + +TEST_CASE ("existing package scheme", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(vcpkg::Test::make_status_pgh("a")); + + PackageSpecMap spec_map; + auto spec_a = FullPackageSpec{spec_map.emplace("a")}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 1); + const auto p = install_plan.at(0).install_action.get(); + REQUIRE(p); + REQUIRE(p->spec.name() == "a"); + REQUIRE(p->plan_type == Dependencies::InstallPlanType::ALREADY_INSTALLED); + REQUIRE(p->request_type == Dependencies::RequestType::USER_REQUESTED); +} + +TEST_CASE ("user requested package scheme", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map; + const auto spec_a = FullPackageSpec{spec_map.emplace("a", "b")}; + const auto spec_b = FullPackageSpec{spec_map.emplace("b")}; + + const auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 2); + const auto p = install_plan.at(0).install_action.get(); + REQUIRE(p); + REQUIRE(p->spec.name() == "b"); + REQUIRE(p->plan_type == Dependencies::InstallPlanType::BUILD_AND_INSTALL); + REQUIRE(p->request_type == Dependencies::RequestType::AUTO_SELECTED); + + const auto p2 = install_plan.at(1).install_action.get(); + REQUIRE(p2); + REQUIRE(p2->spec.name() == "a"); + REQUIRE(p2->plan_type == Dependencies::InstallPlanType::BUILD_AND_INSTALL); + REQUIRE(p2->request_type == Dependencies::RequestType::USER_REQUESTED); +} + +TEST_CASE ("long install scheme", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("j", "k")); + status_paragraphs.push_back(make_status_pgh("k")); + + PackageSpecMap spec_map; + + auto spec_a = spec_map.emplace("a", "b, c, d, e, f, g, h, j, k"); + auto spec_b = spec_map.emplace("b", "c, d, e, f, g, h, j, k"); + auto spec_c = spec_map.emplace("c", "d, e, f, g, h, j, k"); + auto spec_d = spec_map.emplace("d", "e, f, g, h, j, k"); + auto spec_e = spec_map.emplace("e", "f, g, h, j, k"); + auto spec_f = spec_map.emplace("f", "g, h, j, k"); + auto spec_g = spec_map.emplace("g", "h, j, k"); + auto spec_h = spec_map.emplace("h", "j, k"); + auto spec_j = spec_map.emplace("j", "k"); + auto spec_k = spec_map.emplace("k"); + + Dependencies::MapPortFileProvider map_port(spec_map.map); + auto install_plan = Dependencies::create_feature_install_plan( + map_port, {FeatureSpec{spec_a, ""}}, StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 8); + REQUIRE(install_plan.at(0).spec().name() == "h"); + REQUIRE(install_plan.at(1).spec().name() == "g"); + REQUIRE(install_plan.at(2).spec().name() == "f"); + REQUIRE(install_plan.at(3).spec().name() == "e"); + REQUIRE(install_plan.at(4).spec().name() == "d"); + REQUIRE(install_plan.at(5).spec().name() == "c"); + REQUIRE(install_plan.at(6).spec().name() == "b"); + REQUIRE(install_plan.at(7).spec().name() == "a"); +} + +TEST_CASE ("basic feature test 1", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a", "b, b[b1]")); + status_paragraphs.push_back(make_status_pgh("b")); + status_paragraphs.push_back(make_status_feature_pgh("b", "b1")); + + PackageSpecMap spec_map; + auto spec_a = FullPackageSpec{spec_map.emplace("a", "b, b[b1]", {{"a1", "b[b2]"}}), {"a1"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 4); + remove_plan_check(install_plan.at(0), "a"); + remove_plan_check(install_plan.at(1), "b"); + features_check(install_plan.at(2), "b", {"b1", "core", "b1"}); + features_check(install_plan.at(3), "a", {"a1", "core"}); +} + +TEST_CASE ("basic feature test 2", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map; + + auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[b1]", {{"a1", "b[b2]"}}), {"a1"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 2); + features_check(install_plan.at(0), "b", {"b1", "b2", "core"}); + features_check(install_plan.at(1), "a", {"a1", "core"}); +} + +TEST_CASE ("basic feature test 3", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + + PackageSpecMap spec_map; + + auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b")}; + auto spec_c = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; + + auto install_plan = Dependencies::create_feature_install_plan(spec_map.map, + FullPackageSpec::to_feature_specs({spec_c, spec_a}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 4); + remove_plan_check(install_plan.at(0), "a"); + features_check(install_plan.at(1), "b", {"core"}); + features_check(install_plan.at(2), "a", {"a1", "core"}); + features_check(install_plan.at(3), "c", {"core"}); +} + +TEST_CASE ("basic feature test 4", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.push_back(make_status_feature_pgh("a", "a1", "")); + + PackageSpecMap spec_map; + + auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}})}; + auto spec_b = FullPackageSpec{spec_map.emplace("b")}; + auto spec_c = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_c}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "c", {"core"}); +} + +TEST_CASE ("basic feature test 5", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map; + + auto spec_a = + FullPackageSpec{spec_map.emplace("a", "", {{"a1", "b[b1]"}, {"a2", "b[b2]"}, {"a3", "a[a2]"}}), {"a3"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}})}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 2); + features_check(install_plan.at(0), "b", {"core", "b2"}); + features_check(install_plan.at(1), "a", {"core", "a3", "a2"}); +} + +TEST_CASE ("basic feature test 6", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("b")); + + PackageSpecMap spec_map; + auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[core]"), {"core"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {"b1"}}; + + auto install_plan = Dependencies::create_feature_install_plan(spec_map.map, + FullPackageSpec::to_feature_specs({spec_a, spec_b}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + remove_plan_check(install_plan.at(0), "b"); + features_check(install_plan.at(1), "b", {"core", "b1"}); + features_check(install_plan.at(2), "a", {"core"}); +} + +TEST_CASE ("basic feature test 7", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("x", "b")); + status_paragraphs.push_back(make_status_pgh("b")); + + PackageSpecMap spec_map; + + auto spec_a = FullPackageSpec{spec_map.emplace("a")}; + auto spec_x = FullPackageSpec{spec_map.emplace("x", "a"), {"core"}}; + auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {"b1"}}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, FullPackageSpec::to_feature_specs({spec_b}), StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 5); + remove_plan_check(install_plan.at(0), "x"); + remove_plan_check(install_plan.at(1), "b"); + + // TODO: order here may change but A < X, and B anywhere + features_check(install_plan.at(2), "b", {"core", "b1"}); + features_check(install_plan.at(3), "a", {"core"}); + features_check(install_plan.at(4), "x", {"core"}); +} + +TEST_CASE ("basic feature test 8", "[plan][!mayfail]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.spec = + PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; + auto spec_b_64 = FullPackageSpec{spec_map.emplace("b")}; + auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; + + spec_map.triplet = Triplet::X86_WINDOWS; + auto spec_a_86 = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; + auto spec_b_86 = FullPackageSpec{spec_map.emplace("b")}; + auto spec_c_86 = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; + + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({spec_c_64, spec_a_86, spec_a_64, spec_c_86}), + StatusParagraphs(std::move(status_paragraphs))); + + remove_plan_check(install_plan.at(0), "a", Triplet::X64_WINDOWS); + remove_plan_check(install_plan.at(1), "a"); + features_check(install_plan.at(2), "b", {"core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(3), "a", {"a1", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(4), "c", {"core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(5), "b", {"core"}); + features_check(install_plan.at(6), "a", {"a1", "core"}); + features_check(install_plan.at(7), "c", {"core"}); +} + +TEST_CASE ("install all features test", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}), {"core"}}; + + auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); + REQUIRE(install_specs.has_value()); + if (!install_specs.has_value()) return; + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"0", "1", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install default features test 1", "[plan]") +{ + std::vector> status_paragraphs; + + // Add a port "a" with default features "1" and features "0" and "1". + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}, {"1"}); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect the default feature "1" to be installed, but not "0" + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"1", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install default features test 2", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.spec = + PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + + // Add a port "a" of which "core" is already installed, but we will + // install the default features "explicitly" + // "a" has two features, of which "a1" is default. + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "", {{"a0", ""}, {"a1", ""}}, {"a1"}); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect "a" to get removed for rebuild and then installed with default + // features. + REQUIRE(install_plan.size() == 2); + remove_plan_check(install_plan.at(0), "a", Triplet::X64_WINDOWS); + features_check(install_plan.at(1), "a", {"a1", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install default features test 3", "[plan]") +{ + std::vector> status_paragraphs; + + // "a" has two features, of which "a1" is default. + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "", {{"a0", ""}, {"a1", ""}}, {"a1"}); + + // Explicitly install "a" without default features + auto install_specs = FullPackageSpec::from_string("a[core]", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect the default feature not to get installed. + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install default features of dependency test 1", "[plan]") +{ + std::vector> status_paragraphs; + + // Add a port "a" which depends on the core of "b" + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "b[core]"); + // "b" has two features, of which "b1" is default. + spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect "a" to get installed and defaults of "b" through the dependency, + // as no explicit features of "b" are installed by the user. + REQUIRE(install_plan.size() == 2); + features_check(install_plan.at(0), "b", {"b1", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(1), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("do not install default features of existing dependency", "[plan]") +{ + // Add a port "a" which depends on the core of "b" + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "b[core]"); + // "b" has two features, of which "b1" is default. + spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); + + std::vector> status_paragraphs; + // "b[core]" is already installed + status_paragraphs.push_back(make_status_pgh("b")); + status_paragraphs.back()->package.spec = + PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect "a" to get installed, but not require rebuilding "b" + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install default features of dependency test 2", "[plan]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("b")); + status_paragraphs.back()->package.spec = + PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + + // Add a port "a" which depends on the core of "b", which was already + // installed explicitly + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "b[core]"); + // "b" has two features, of which "b1" is default. + spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + // Expect "a" to get installed, not the defaults of "b", as the required + // dependencies are already there, installed explicitly by the user. + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("install plan action dependencies", "[plan]") +{ + std::vector> status_paragraphs; + + // Add a port "a" which depends on the core of "b", which was already + // installed explicitly + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_c = spec_map.emplace("c"); + auto spec_b = spec_map.emplace("b", "c"); + spec_map.emplace("a", "b"); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + features_check(install_plan.at(0), "c", {"core"}, Triplet::X64_WINDOWS); + + features_check(install_plan.at(1), "b", {"core"}, Triplet::X64_WINDOWS); + REQUIRE(install_plan.at(1).install_action.get()->computed_dependencies == std::vector{spec_c}); + + features_check(install_plan.at(2), "a", {"core"}, Triplet::X64_WINDOWS); + REQUIRE(install_plan.at(2).install_action.get()->computed_dependencies == std::vector{spec_b}); +} + +TEST_CASE ("install plan action dependencies 2", "[plan]") +{ + std::vector> status_paragraphs; + + // Add a port "a" which depends on the core of "b", which was already + // installed explicitly + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_c = spec_map.emplace("c"); + auto spec_b = spec_map.emplace("b", "c"); + spec_map.emplace("a", "c, b"); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + features_check(install_plan.at(0), "c", {"core"}, Triplet::X64_WINDOWS); + + features_check(install_plan.at(1), "b", {"core"}, Triplet::X64_WINDOWS); + REQUIRE(install_plan.at(1).install_action.get()->computed_dependencies == std::vector{spec_c}); + + features_check(install_plan.at(2), "a", {"core"}, Triplet::X64_WINDOWS); + REQUIRE(install_plan.at(2).install_action.get()->computed_dependencies == std::vector{spec_b, spec_c}); +} + +TEST_CASE ("install plan action dependencies 3", "[plan]") +{ + std::vector> status_paragraphs; + + // Add a port "a" which depends on the core of "b", which was already + // installed explicitly + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + spec_map.emplace("a", "", {{"0", ""}, {"1", "a[0]"}}, {"1"}); + + // Install "a" (without explicit feature specification) + auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 1); + features_check(install_plan.at(0), "a", {"1", "0", "core"}, Triplet::X64_WINDOWS); + REQUIRE(install_plan.at(0).install_action.get()->computed_dependencies == std::vector{}); +} + +TEST_CASE ("install with default features", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a", "")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto b_spec = spec_map.emplace("b", "", {{"0", ""}}, {"0"}); + auto a_spec = spec_map.emplace("a", "b[core]", {{"0", ""}}); + + // Install "a" and indicate that "b" should not install default features + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, {FeatureSpec{a_spec, "0"}, FeatureSpec{b_spec, "core"}}, status_db); + + REQUIRE(install_plan.size() == 3); + remove_plan_check(install_plan.at(0), "a"); + features_check(install_plan.at(1), "b", {"core"}); + features_check(install_plan.at(2), "a", {"0", "core"}); +} + +TEST_CASE ("upgrade with default features 1", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a", "", "1")); + pghs.push_back(make_status_feature_pgh("a", "0")); + StatusParagraphs status_db(std::move(pghs)); + + // Add a port "a" of which "core" and "0" are already installed. + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}, {"1"}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + auto plan = graph.serialize(); + + // The upgrade should not install the default feature + REQUIRE(plan.size() == 2); + + REQUIRE(plan.at(0).spec().name() == "a"); + remove_plan_check(plan.at(0), "a"); + features_check(plan.at(1), "a", {"core", "0"}); +} + +TEST_CASE ("upgrade with default features 2", "[plan]") +{ + std::vector> pghs; + // B is currently installed _without_ default feature b0 + pghs.push_back(make_status_pgh("b", "", "b0", "x64-windows")); + pghs.push_back(make_status_pgh("a", "b[core]", "", "x64-windows")); + + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a = spec_map.emplace("a", "b[core]"); + auto spec_b = spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b0", "b1"}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + graph.upgrade(spec_b); + auto plan = graph.serialize(); + + // The upgrade should install the new default feature b1 but not b0 + REQUIRE(plan.size() == 4); + remove_plan_check(plan.at(0), "a", Triplet::X64_WINDOWS); + remove_plan_check(plan.at(1), "b", Triplet::X64_WINDOWS); + features_check(plan.at(2), "b", {"core", "b1"}, Triplet::X64_WINDOWS); + features_check(plan.at(3), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("upgrade with default features 3", "[plan]") +{ + std::vector> pghs; + // note: unrelated package due to x86 triplet + pghs.push_back(make_status_pgh("b", "", "", "x86-windows")); + pghs.push_back(make_status_pgh("a", "", "", "x64-windows")); + + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a = spec_map.emplace("a", "b[core]"); + spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b0"}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + auto plan = graph.serialize(); + + // The upgrade should install the default feature + REQUIRE(plan.size() == 3); + remove_plan_check(plan.at(0), "a", Triplet::X64_WINDOWS); + features_check(plan.at(1), "b", {"b0", "core"}, Triplet::X64_WINDOWS); + features_check(plan.at(2), "a", {"core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("upgrade with new default feature", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a", "", "0", "x86-windows")); + + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"0", ""}, {"1", ""}, {"2", ""}}, {"0", "1"}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + auto plan = graph.serialize(); + + // The upgrade should install the new default feature but not the old default feature 0 + REQUIRE(plan.size() == 2); + remove_plan_check(plan.at(0), "a", Triplet::X86_WINDOWS); + features_check(plan.at(1), "a", {"core", "1"}, Triplet::X86_WINDOWS); +} + +TEST_CASE ("transitive features test", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"0", "b[0]"}}), {"core"}}; + auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "c", {{"0", "c[0]"}}), {"core"}}; + auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; + + auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); + REQUIRE(install_specs.has_value()); + if (!install_specs.has_value()) return; + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + features_check(install_plan.at(0), "c", {"0", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(1), "b", {"0", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(2), "a", {"0", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("no transitive features test", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"0", ""}}), {"core"}}; + auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "c", {{"0", ""}}), {"core"}}; + auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; + + auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); + REQUIRE(install_specs.has_value()); + if (!install_specs.has_value()) return; + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + features_check(install_plan.at(0), "c", {"core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(1), "b", {"core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(2), "a", {"0", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("only transitive features test", "[plan]") +{ + std::vector> status_paragraphs; + + PackageSpecMap spec_map(Triplet::X64_WINDOWS); + auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "", {{"0", "b[0]"}}), {"core"}}; + auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "", {{"0", "c[0]"}}), {"core"}}; + auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; + + auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); + REQUIRE(install_specs.has_value()); + if (!install_specs.has_value()) return; + auto install_plan = Dependencies::create_feature_install_plan( + spec_map.map, + FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), + StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(install_plan.size() == 3); + features_check(install_plan.at(0), "c", {"0", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(1), "b", {"0", "core"}, Triplet::X64_WINDOWS); + features_check(install_plan.at(2), "a", {"0", "core"}, Triplet::X64_WINDOWS); +} + +TEST_CASE ("basic remove scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); + + REQUIRE(remove_plan.size() == 1); + REQUIRE(remove_plan.at(0).spec.name() == "a"); +} + +TEST_CASE ("recurse remove scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b", "a")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); + + REQUIRE(remove_plan.size() == 2); + REQUIRE(remove_plan.at(0).spec.name() == "b"); + REQUIRE(remove_plan.at(1).spec.name() == "a"); +} + +TEST_CASE ("features depend remove scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b")); + pghs.push_back(make_status_feature_pgh("b", "0", "a")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); + + REQUIRE(remove_plan.size() == 2); + REQUIRE(remove_plan.at(0).spec.name() == "b"); + REQUIRE(remove_plan.at(1).spec.name() == "a"); +} + +TEST_CASE ("features depend remove scheme once removed", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("expat")); + pghs.push_back(make_status_pgh("vtk", "expat")); + pghs.push_back(make_status_pgh("opencv")); + pghs.push_back(make_status_feature_pgh("opencv", "vtk", "vtk")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("expat")}, status_db); + + REQUIRE(remove_plan.size() == 3); + REQUIRE(remove_plan.at(0).spec.name() == "opencv"); + REQUIRE(remove_plan.at(1).spec.name() == "vtk"); + REQUIRE(remove_plan.at(2).spec.name() == "expat"); +} + +TEST_CASE ("features depend remove scheme once removed x64", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("expat", "", "", "x64")); + pghs.push_back(make_status_pgh("vtk", "expat", "", "x64")); + pghs.push_back(make_status_pgh("opencv", "", "", "x64")); + pghs.push_back(make_status_feature_pgh("opencv", "vtk", "vtk", "x64")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = + Dependencies::create_remove_plan({unsafe_pspec("expat", Triplet::from_canonical_name("x64"))}, status_db); + + REQUIRE(remove_plan.size() == 3); + REQUIRE(remove_plan.at(0).spec.name() == "opencv"); + REQUIRE(remove_plan.at(1).spec.name() == "vtk"); + REQUIRE(remove_plan.at(2).spec.name() == "expat"); +} + +TEST_CASE ("features depend core remove scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("curl", "", "", "x64")); + pghs.push_back(make_status_pgh("cpr", "curl[core]", "", "x64")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = + Dependencies::create_remove_plan({unsafe_pspec("curl", Triplet::from_canonical_name("x64"))}, status_db); + + REQUIRE(remove_plan.size() == 2); + REQUIRE(remove_plan.at(0).spec.name() == "cpr"); + REQUIRE(remove_plan.at(1).spec.name() == "curl"); +} + +TEST_CASE ("features depend core remove scheme 2", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("curl", "", "", "x64")); + pghs.push_back(make_status_feature_pgh("curl", "a", "", "x64")); + pghs.push_back(make_status_feature_pgh("curl", "b", "curl[a]", "x64")); + StatusParagraphs status_db(std::move(pghs)); + + auto remove_plan = + Dependencies::create_remove_plan({unsafe_pspec("curl", Triplet::from_canonical_name("x64"))}, status_db); + + REQUIRE(remove_plan.size() == 1); + REQUIRE(remove_plan.at(0).spec.name() == "curl"); +} + +TEST_CASE ("basic upgrade scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 2); + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + REQUIRE(plan.at(1).spec().name() == "a"); + REQUIRE(plan.at(1).install_action.has_value()); +} + +TEST_CASE ("basic upgrade scheme with recurse", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b", "a")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + spec_map.emplace("b", "a"); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 4); + REQUIRE(plan.at(0).spec().name() == "b"); + REQUIRE(plan.at(0).remove_action.has_value()); + + REQUIRE(plan.at(1).spec().name() == "a"); + REQUIRE(plan.at(1).remove_action.has_value()); + + REQUIRE(plan.at(2).spec().name() == "a"); + REQUIRE(plan.at(2).install_action.has_value()); + + REQUIRE(plan.at(3).spec().name() == "b"); + REQUIRE(plan.at(3).install_action.has_value()); +} + +TEST_CASE ("basic upgrade scheme with bystander", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + spec_map.emplace("b", "a"); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 2); + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + REQUIRE(plan.at(1).spec().name() == "a"); + REQUIRE(plan.at(1).install_action.has_value()); +} + +TEST_CASE ("basic upgrade scheme with new dep", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "b"); + spec_map.emplace("b"); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 3); + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + REQUIRE(plan.at(1).spec().name() == "b"); + REQUIRE(plan.at(1).install_action.has_value()); + REQUIRE(plan.at(2).spec().name() == "a"); + REQUIRE(plan.at(2).install_action.has_value()); +} + +TEST_CASE ("basic upgrade scheme with features", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_feature_pgh("a", "a1")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 2); + + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + + features_check(plan.at(1), "a", {"core", "a1"}); +} + +TEST_CASE ("basic upgrade scheme with new default feature", "[plan]") +{ + // only core of package "a" is installed + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + StatusParagraphs status_db(std::move(pghs)); + + // a1 was added as a default feature and should be installed in upgrade + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}, {"a1"}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 2); + + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + + features_check(plan.at(1), "a", {"core", "a1"}); +} + +TEST_CASE ("basic upgrade scheme with self features", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_feature_pgh("a", "a1", "")); + pghs.push_back(make_status_feature_pgh("a", "a2", "a[a1]")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"a1", ""}, {"a2", "a[a1]"}}); + + Dependencies::MapPortFileProvider provider(spec_map.map); + Dependencies::PackageGraph graph(provider, status_db); + + graph.upgrade(spec_a); + + auto plan = graph.serialize(); + + REQUIRE(plan.size() == 2); + + REQUIRE(plan.at(0).spec().name() == "a"); + REQUIRE(plan.at(0).remove_action.has_value()); + + REQUIRE(plan.at(1).spec().name() == "a"); + REQUIRE(plan.at(1).install_action.has_value()); + REQUIRE(plan.at(1).install_action.get()->feature_list == std::set{"core", "a1", "a2"}); +} + +TEST_CASE ("basic export scheme", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + + auto plan = Dependencies::create_export_plan({spec_a}, status_db); + + REQUIRE(plan.size() == 1); + REQUIRE(plan.at(0).spec.name() == "a"); + REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); +} + +TEST_CASE ("basic export scheme with recurse", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b", "a")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + auto spec_b = spec_map.emplace("b", "a"); + + auto plan = Dependencies::create_export_plan({spec_b}, status_db); + + REQUIRE(plan.size() == 2); + REQUIRE(plan.at(0).spec.name() == "a"); + REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); + + REQUIRE(plan.at(1).spec.name() == "b"); + REQUIRE(plan.at(1).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); +} + +TEST_CASE ("basic export scheme with bystander", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_pgh("b")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + auto spec_b = spec_map.emplace("b", "a"); + + auto plan = Dependencies::create_export_plan({spec_a}, status_db); + + REQUIRE(plan.size() == 1); + REQUIRE(plan.at(0).spec.name() == "a"); + REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); +} + +TEST_CASE ("basic export scheme with missing", "[plan]") +{ + StatusParagraphs status_db; + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a"); + + auto plan = Dependencies::create_export_plan({spec_a}, status_db); + + REQUIRE(plan.size() == 1); + REQUIRE(plan.at(0).spec.name() == "a"); + REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::NOT_BUILT); +} + +TEST_CASE ("basic export scheme with features", "[plan]") +{ + std::vector> pghs; + pghs.push_back(make_status_pgh("b")); + pghs.push_back(make_status_pgh("a")); + pghs.push_back(make_status_feature_pgh("a", "a1", "b[core]")); + StatusParagraphs status_db(std::move(pghs)); + + PackageSpecMap spec_map; + auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}); + + auto plan = Dependencies::create_export_plan({spec_a}, status_db); + + REQUIRE(plan.size() == 2); + + REQUIRE(plan.at(0).spec.name() == "b"); + REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); + + REQUIRE(plan.at(1).spec.name() == "a"); + REQUIRE(plan.at(1).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); +} diff --git a/toolsrc/src/vcpkg-test/specifier.cpp b/toolsrc/src/vcpkg-test/specifier.cpp new file mode 100644 index 000000000..330a96d78 --- /dev/null +++ b/toolsrc/src/vcpkg-test/specifier.cpp @@ -0,0 +1,134 @@ +#include + +#include +#include + +using namespace vcpkg; + +TEST_CASE ("specifier conversion", "[specifier]") +{ + SECTION ("full package spec to feature specs") + { + constexpr std::size_t SPEC_SIZE = 6; + + auto a_spec = PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + auto b_spec = PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); + + auto fspecs = FullPackageSpec::to_feature_specs({{a_spec, {"0", "1"}}, {b_spec, {"2", "3"}}}); + + REQUIRE(fspecs.size() == SPEC_SIZE); + + std::array features = {"", "0", "1", "", "2", "3"}; + std::array specs = {&a_spec, &a_spec, &a_spec, &b_spec, &b_spec, &b_spec}; + + for (std::size_t i = 0; i < SPEC_SIZE; ++i) + { + REQUIRE(features.at(i) == fspecs.at(i).feature()); + REQUIRE(*specs.at(i) == fspecs.at(i).spec()); + } + } +} + +TEST_CASE ("specifier parsing", "[specifier]") +{ + SECTION ("parsed specifier from string") + { + auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib"); + REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); + + auto& spec = *maybe_spec.get(); + REQUIRE(spec.name == "zlib"); + REQUIRE(spec.features.size() == 0); + REQUIRE(spec.triplet == ""); + } + + SECTION ("parsed specifier from string with triplet") + { + auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib:x64-uwp"); + REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); + + auto& spec = *maybe_spec.get(); + REQUIRE(spec.name == "zlib"); + REQUIRE(spec.triplet == "x64-uwp"); + } + + SECTION ("parsed specifier from string with colons") + { + auto ec = vcpkg::ParsedSpecifier::from_string("zlib:x86-uwp:").error(); + REQUIRE(ec == vcpkg::PackageSpecParseResult::TOO_MANY_COLONS); + } + + SECTION ("parsed specifier from string with feature") + { + auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[feature]:x64-uwp"); + REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); + + auto& spec = *maybe_spec.get(); + REQUIRE(spec.name == "zlib"); + REQUIRE(spec.features.size() == 1); + REQUIRE(spec.features.at(0) == "feature"); + REQUIRE(spec.triplet == "x64-uwp"); + } + + SECTION ("parsed specifier from string with many features") + { + auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[0, 1,2]"); + REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); + + auto& spec = *maybe_spec.get(); + REQUIRE(spec.name == "zlib"); + REQUIRE(spec.features.size() == 3); + REQUIRE(spec.features.at(0) == "0"); + REQUIRE(spec.features.at(1) == "1"); + REQUIRE(spec.features.at(2) == "2"); + REQUIRE(spec.triplet == ""); + } + + SECTION ("parsed specifier wildcard feature") + { + auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[*]"); + REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); + + auto& spec = *maybe_spec.get(); + REQUIRE(spec.name == "zlib"); + REQUIRE(spec.features.size() == 1); + REQUIRE(spec.features.at(0) == "*"); + REQUIRE(spec.triplet == ""); + } + + SECTION ("expand wildcards") + { + auto zlib = vcpkg::FullPackageSpec::from_string("zlib[0,1]", Triplet::X86_UWP).value_or_exit(VCPKG_LINE_INFO); + auto openssl = + vcpkg::FullPackageSpec::from_string("openssl[*]", Triplet::X86_UWP).value_or_exit(VCPKG_LINE_INFO); + auto specs = FullPackageSpec::to_feature_specs({zlib, openssl}); + Util::sort(specs); + auto spectargets = FeatureSpec::from_strings_and_triplet( + { + "openssl", + "zlib", + "openssl[*]", + "zlib[0]", + "zlib[1]", + }, + Triplet::X86_UWP); + Util::sort(spectargets); + + REQUIRE(specs.size() == spectargets.size()); + REQUIRE(Util::all_equal(specs, spectargets)); + } + +#if defined(_WIN32) + SECTION ("ASCII to utf16") + { + auto str = vcpkg::Strings::to_utf16("abc"); + REQUIRE(str == L"abc"); + } + + SECTION ("ASCII to utf16 with whitespace") + { + auto str = vcpkg::Strings::to_utf16("abc -x86-windows"); + REQUIRE(str == L"abc -x86-windows"); + } +#endif +}; diff --git a/toolsrc/src/vcpkg-test/statusparagraphs.cpp b/toolsrc/src/vcpkg-test/statusparagraphs.cpp new file mode 100644 index 000000000..c0833e8ba --- /dev/null +++ b/toolsrc/src/vcpkg-test/statusparagraphs.cpp @@ -0,0 +1,110 @@ +#include +#include + +#include +#include +#include + +using namespace vcpkg; +using namespace vcpkg::Paragraphs; +using namespace vcpkg::Test; + +TEST_CASE ("find installed", "[statusparagraphs]") +{ + auto pghs = parse_paragraphs(R"( +Package: ffmpeg +Version: 3.3.3 +Architecture: x64-windows +Multi-Arch: same +Description: +Status: install ok installed +)"); + + REQUIRE(pghs); + + StatusParagraphs status_db( + Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); + + auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); + REQUIRE(it != status_db.end()); +} + +TEST_CASE ("find not installed", "[statusparagraphs]") +{ + auto pghs = parse_paragraphs(R"( +Package: ffmpeg +Version: 3.3.3 +Architecture: x64-windows +Multi-Arch: same +Description: +Status: purge ok not-installed +)"); + + REQUIRE(pghs); + + StatusParagraphs status_db( + Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); + + auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); + REQUIRE(it == status_db.end()); +} + +TEST_CASE ("find with feature packages", "[statusparagraphs]") +{ + auto pghs = parse_paragraphs(R"( +Package: ffmpeg +Version: 3.3.3 +Architecture: x64-windows +Multi-Arch: same +Description: +Status: install ok installed + +Package: ffmpeg +Feature: openssl +Depends: openssl +Architecture: x64-windows +Multi-Arch: same +Description: +Status: purge ok not-installed +)"); + + REQUIRE(pghs); + + StatusParagraphs status_db( + Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); + + auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); + REQUIRE(it != status_db.end()); + + // Feature "openssl" is not installed and should not be found + auto it1 = status_db.find_installed({unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS), "openssl"}); + REQUIRE(it1 == status_db.end()); +} + +TEST_CASE ("find for feature packages", "[statusparagraphs]") +{ + auto pghs = parse_paragraphs(R"( +Package: ffmpeg +Version: 3.3.3 +Architecture: x64-windows +Multi-Arch: same +Description: +Status: install ok installed + +Package: ffmpeg +Feature: openssl +Depends: openssl +Architecture: x64-windows +Multi-Arch: same +Description: +Status: install ok installed +)"); + REQUIRE(pghs); + + StatusParagraphs status_db( + Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); + + // Feature "openssl" is installed and should therefore be found + auto it = status_db.find_installed({unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS), "openssl"}); + REQUIRE(it != status_db.end()); +} diff --git a/toolsrc/src/vcpkg-test/strings.cpp b/toolsrc/src/vcpkg-test/strings.cpp new file mode 100644 index 000000000..6b744eee6 --- /dev/null +++ b/toolsrc/src/vcpkg-test/strings.cpp @@ -0,0 +1,33 @@ +#include + +#include + +#include +#include +#include + +TEST_CASE ("b32 encoding", "[strings]") +{ + using u64 = std::uint64_t; + + std::vector> map; + + map.emplace_back(0, "AAAAAAAAAAAAA"); + map.emplace_back(1, "BAAAAAAAAAAAA"); + + map.emplace_back(u64(1) << 32, "AAAAAAEAAAAAA"); + map.emplace_back((u64(1) << 32) + 1, "BAAAAAEAAAAAA"); + + map.emplace_back(0xE4D0'1065'D11E'0229, "JRA4RIXMQAUJO"); + map.emplace_back(0xA626'FE45'B135'07FF, "77BKTYWI6XJMK"); + map.emplace_back(0xEE36'D228'0C31'D405, "FAVDDGAFSWN4O"); + map.emplace_back(0x1405'64E7'FE7E'A88C, "MEK5H774ELBIB"); + map.emplace_back(0xFFFF'FFFF'FFFF'FFFF, "777777777777P"); + + std::string result; + for (const auto& pr : map) + { + result = vcpkg::Strings::b32_encode(pr.first); + REQUIRE(vcpkg::Strings::b32_encode(pr.first) == pr.second); + } +} diff --git a/toolsrc/src/vcpkg-test/supports.cpp b/toolsrc/src/vcpkg-test/supports.cpp new file mode 100644 index 000000000..8bd386da0 --- /dev/null +++ b/toolsrc/src/vcpkg-test/supports.cpp @@ -0,0 +1,79 @@ +#include + +#include + +using namespace vcpkg; +using Parse::parse_comma_list; + +TEST_CASE ("parse supports all", "[supports]") +{ + auto v = Supports::parse({ + "x64", + "x86", + "arm", + "windows", + "uwp", + "v140", + "v141", + "crt-static", + "crt-dynamic", + }); + + REQUIRE(v.has_value()); + + REQUIRE(v.get()->is_supported(System::CPUArchitecture::X64, + Supports::Platform::UWP, + Supports::Linkage::DYNAMIC, + Supports::ToolsetVersion::V140)); + REQUIRE(v.get()->is_supported(System::CPUArchitecture::ARM, + Supports::Platform::WINDOWS, + Supports::Linkage::STATIC, + Supports::ToolsetVersion::V141)); +} + +TEST_CASE ("parse supports invalid", "[supports]") +{ + auto v = Supports::parse({"arm64"}); + + REQUIRE_FALSE(v.has_value()); + + REQUIRE(v.error().size() == 1); + REQUIRE(v.error().at(0) == "arm64"); +} + +TEST_CASE ("parse supports case sensitive", "[supports]") +{ + auto v = Supports::parse({"Windows"}); + + REQUIRE_FALSE(v.has_value()); + REQUIRE(v.error().size() == 1); + REQUIRE(v.error().at(0) == "Windows"); +} + +TEST_CASE ("parse supports some", "[supports]") +{ + auto v = Supports::parse({ + "x64", + "x86", + "windows", + }); + + REQUIRE(v.has_value()); + + REQUIRE(v.get()->is_supported(System::CPUArchitecture::X64, + Supports::Platform::WINDOWS, + Supports::Linkage::DYNAMIC, + Supports::ToolsetVersion::V140)); + REQUIRE_FALSE(v.get()->is_supported(System::CPUArchitecture::ARM, + Supports::Platform::WINDOWS, + Supports::Linkage::DYNAMIC, + Supports::ToolsetVersion::V140)); + REQUIRE_FALSE(v.get()->is_supported(System::CPUArchitecture::X64, + Supports::Platform::UWP, + Supports::Linkage::DYNAMIC, + Supports::ToolsetVersion::V140)); + REQUIRE(v.get()->is_supported(System::CPUArchitecture::X64, + Supports::Platform::WINDOWS, + Supports::Linkage::STATIC, + Supports::ToolsetVersion::V141)); +} diff --git a/toolsrc/src/vcpkg-test/update.cpp b/toolsrc/src/vcpkg-test/update.cpp new file mode 100644 index 000000000..70b2f04c1 --- /dev/null +++ b/toolsrc/src/vcpkg-test/update.cpp @@ -0,0 +1,102 @@ +#include +#include + +#include + +#include + +using namespace vcpkg; +using namespace vcpkg::Update; +using namespace vcpkg::Test; + +using Pgh = std::vector>; + +TEST_CASE ("find outdated packages basic", "[update]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.version = "2"; + + StatusParagraphs status_db(std::move(status_paragraphs)); + + std::unordered_map map; + auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); + map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); + Dependencies::MapPortFileProvider provider(map); + + auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), + &OutdatedPackage::compare_by_name); + + REQUIRE(pkgs.size() == 1); + REQUIRE(pkgs[0].version_diff.left.to_string() == "2"); + REQUIRE(pkgs[0].version_diff.right.to_string() == "0"); +} + +TEST_CASE ("find outdated packages features", "[update]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.version = "2"; + + status_paragraphs.push_back(make_status_feature_pgh("a", "b")); + status_paragraphs.back()->package.version = "2"; + + StatusParagraphs status_db(std::move(status_paragraphs)); + + std::unordered_map map; + auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); + map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); + Dependencies::MapPortFileProvider provider(map); + + auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), + &OutdatedPackage::compare_by_name); + + REQUIRE(pkgs.size() == 1); + REQUIRE(pkgs[0].version_diff.left.to_string() == "2"); + REQUIRE(pkgs[0].version_diff.right.to_string() == "0"); +} + +TEST_CASE ("find outdated packages features 2", "[update]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.version = "2"; + + status_paragraphs.push_back(make_status_feature_pgh("a", "b")); + status_paragraphs.back()->package.version = "0"; + status_paragraphs.back()->state = InstallState::NOT_INSTALLED; + status_paragraphs.back()->want = Want::PURGE; + + StatusParagraphs status_db(std::move(status_paragraphs)); + + std::unordered_map map; + auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); + map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); + Dependencies::MapPortFileProvider provider(map); + + auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), + &OutdatedPackage::compare_by_name); + + REQUIRE(pkgs.size() == 1); + REQUIRE(pkgs[0].version_diff.left.to_string() == "2"); + REQUIRE(pkgs[0].version_diff.right.to_string() == "0"); +} + +TEST_CASE ("find outdated packages none", "[update]") +{ + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.back()->package.version = "2"; + + StatusParagraphs status_db(std::move(status_paragraphs)); + + std::unordered_map map; + auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "2"}}})); + map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); + Dependencies::MapPortFileProvider provider(map); + + auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), + &OutdatedPackage::compare_by_name); + + REQUIRE(pkgs.size() == 0); +} diff --git a/toolsrc/src/vcpkg-test/util.cpp b/toolsrc/src/vcpkg-test/util.cpp new file mode 100644 index 000000000..19f8f355e --- /dev/null +++ b/toolsrc/src/vcpkg-test/util.cpp @@ -0,0 +1,158 @@ +#include +#include + +#include +#include +#include + +#include +#include + +#if defined(_WIN32) +#include +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1914 + +#define USE_STD_FILESYSTEM + +#include // required for filesystem::create_{directory_}symlink + +#elif !defined(_MSC_VER) + +#include + +#endif + +namespace vcpkg::Test +{ + std::unique_ptr make_status_pgh(const char* name, + const char* depends, + const char* default_features, + const char* triplet) + { + using Pgh = std::unordered_map; + return std::make_unique(Pgh{{"Package", name}, + {"Version", "1"}, + {"Architecture", triplet}, + {"Multi-Arch", "same"}, + {"Depends", depends}, + {"Default-Features", default_features}, + {"Status", "install ok installed"}}); + } + + std::unique_ptr make_status_feature_pgh(const char* name, + const char* feature, + const char* depends, + const char* triplet) + { + using Pgh = std::unordered_map; + return std::make_unique(Pgh{{"Package", name}, + {"Version", "1"}, + {"Feature", feature}, + {"Architecture", triplet}, + {"Multi-Arch", "same"}, + {"Depends", depends}, + {"Status", "install ok installed"}}); + } + + PackageSpec unsafe_pspec(std::string name, Triplet t) + { + auto m_ret = PackageSpec::from_name_and_triplet(name, t); + REQUIRE(m_ret.has_value()); + return m_ret.value_or_exit(VCPKG_LINE_INFO); + } + + + + // I am so sorry for this awful mix of macros + + static bool system_allows_symlinks() { +#if defined(_WIN32) + #if !defined(USE_STD_FILESYSTEM) + return false; + #else + HKEY key; + bool allow_symlinks = true; + + const auto status = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock)", 0, 0, &key); + + if (status == ERROR_FILE_NOT_FOUND) + { + allow_symlinks = false; + std::clog << "Symlinks are not allowed on this system\n"; + } + + if (status == ERROR_SUCCESS) RegCloseKey(key); + + return allow_symlinks; + #endif +#else + return true; +#endif + } + + static fs::path internal_temporary_directory() { +#if defined(_WIN32) + wchar_t* tmp = static_cast(std::calloc(32'767, 2)); + + if (!GetEnvironmentVariableW(L"TEMP", tmp, 32'767)) { + std::cerr << "No temporary directory found.\n"; + std::abort(); + } + + fs::path result = tmp; + std::free(tmp); + + return result / L"vcpkg-test"; +#else + return "/tmp/vcpkg-test"; +#endif + } + + const bool SYMLINKS_ALLOWED = system_allows_symlinks(); + const fs::path TEMPORARY_DIRECTORY = internal_temporary_directory(); + + void create_symlink(const fs::path& target, const fs::path& file, std::error_code& ec) { +#if defined(_MSC_VER) + #if defined(USE_STD_FILESYSTEM) + if (SYMLINKS_ALLOWED) + { + std::filesystem::path targetp = target.native(); + std::filesystem::path filep = file.native(); + + std::filesystem::create_symlink(targetp, filep); + } + else + #endif + { + vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "Symlinks are not allowed on this system"); + } +#else + if(symlink(target.c_str(), file.c_str()) != 0) { + ec.assign(errno, std::system_category()); + } +#endif + } + + void create_directory_symlink(const fs::path& target, const fs::path& file, std::error_code& ec) { +#if defined(_MSC_VER) + #if defined(USE_STD_FILESYSTEM) + if (SYMLINKS_ALLOWED) + { + std::filesystem::path targetp = target.native(); + std::filesystem::path filep = file.native(); + + std::filesystem::create_symlink(targetp, filep); + } + else + #endif + { + vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "Symlinks are not allowed on this system"); + } +#else + ::vcpkg::Test::create_symlink(target, file, ec); +#endif + } +} diff --git a/toolsrc/src/vcpkg-tests/arguments.cpp b/toolsrc/src/vcpkg-tests/arguments.cpp deleted file mode 100644 index 8c625be0f..000000000 --- a/toolsrc/src/vcpkg-tests/arguments.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include - -#include - -#include - -using vcpkg::CommandSetting; -using vcpkg::CommandStructure; -using vcpkg::CommandSwitch; -using vcpkg::VcpkgCmdArguments; - -TEST_CASE ("VcpkgCmdArguments from lowercase argument sequence", "[arguments]") -{ - std::vector t = {"--vcpkg-root", - "C:\\vcpkg", - "--scripts-root=C:\\scripts", - "--debug", - "--sendmetrics", - "--printmetrics", - "--overlay-ports=C:\\ports1", - "--overlay-ports=C:\\ports2", - "--overlay-triplets=C:\\tripletsA", - "--overlay-triplets=C:\\tripletsB"}; - auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); - - REQUIRE(*v.vcpkg_root_dir == "C:\\vcpkg"); - REQUIRE(*v.scripts_root_dir == "C:\\scripts"); - REQUIRE(v.debug); - REQUIRE(*v.debug.get()); - REQUIRE(v.sendmetrics); - REQUIRE(*v.sendmetrics.get()); - REQUIRE(v.printmetrics); - REQUIRE(*v.printmetrics.get()); - - REQUIRE(v.overlay_ports->size() == 2); - REQUIRE(v.overlay_ports->at(0) == "C:\\ports1"); - REQUIRE(v.overlay_ports->at(1) == "C:\\ports2"); - - REQUIRE(v.overlay_triplets->size() == 2); - REQUIRE(v.overlay_triplets->at(0) == "C:\\tripletsA"); - REQUIRE(v.overlay_triplets->at(1) == "C:\\tripletsB"); -} - -TEST_CASE ("VcpkgCmdArguments from uppercase argument sequence", "[arguments]") -{ - std::vector t = {"--VCPKG-ROOT", - "C:\\vcpkg", - "--SCRIPTS-ROOT=C:\\scripts", - "--DEBUG", - "--SENDMETRICS", - "--PRINTMETRICS", - "--OVERLAY-PORTS=C:\\ports1", - "--OVERLAY-PORTS=C:\\ports2", - "--OVERLAY-TRIPLETS=C:\\tripletsA", - "--OVERLAY-TRIPLETS=C:\\tripletsB"}; - auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); - - REQUIRE(*v.vcpkg_root_dir == "C:\\vcpkg"); - REQUIRE(*v.scripts_root_dir == "C:\\scripts"); - REQUIRE(v.debug); - REQUIRE(*v.debug.get()); - REQUIRE(v.sendmetrics); - REQUIRE(*v.sendmetrics.get()); - REQUIRE(v.printmetrics); - REQUIRE(*v.printmetrics.get()); - - REQUIRE(v.overlay_ports->size() == 2); - REQUIRE(v.overlay_ports->at(0) == "C:\\ports1"); - REQUIRE(v.overlay_ports->at(1) == "C:\\ports2"); - - REQUIRE(v.overlay_triplets->size() == 2); - REQUIRE(v.overlay_triplets->at(0) == "C:\\tripletsA"); - REQUIRE(v.overlay_triplets->at(1) == "C:\\tripletsB"); -} - -TEST_CASE ("VcpkgCmdArguments from argument sequence with valued options", "[arguments]") -{ - SECTION ("case 1") - { - std::array settings = {{{"--a", ""}}}; - CommandStructure cmdstruct = {"", 0, SIZE_MAX, {{}, settings}, nullptr}; - - std::vector t = {"--a=b", "command", "argument"}; - auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); - auto opts = v.parse_arguments(cmdstruct); - - REQUIRE(opts.settings["--a"] == "b"); - REQUIRE(v.command_arguments.size() == 1); - REQUIRE(v.command_arguments[0] == "argument"); - REQUIRE(v.command == "command"); - } - - SECTION ("case 2") - { - std::array switches = {{{"--a", ""}, {"--c", ""}}}; - std::array settings = {{{"--b", ""}, {"--d", ""}}}; - CommandStructure cmdstruct = {"", 0, SIZE_MAX, {switches, settings}, nullptr}; - - std::vector t = {"--a", "--b=c"}; - auto v = VcpkgCmdArguments::create_from_arg_sequence(t.data(), t.data() + t.size()); - auto opts = v.parse_arguments(cmdstruct); - - REQUIRE(opts.settings["--b"] == "c"); - REQUIRE(opts.settings.find("--d") == opts.settings.end()); - REQUIRE(opts.switches.find("--a") != opts.switches.end()); - REQUIRE(opts.settings.find("--c") == opts.settings.end()); - REQUIRE(v.command_arguments.size() == 0); - } -} diff --git a/toolsrc/src/vcpkg-tests/catch.cpp b/toolsrc/src/vcpkg-tests/catch.cpp deleted file mode 100644 index 701dcb39a..000000000 --- a/toolsrc/src/vcpkg-tests/catch.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#define CATCH_CONFIG_RUNNER -#include - -#include - -int main(int argc, char** argv) -{ - vcpkg::Debug::g_debugging = true; - - return Catch::Session().run(argc, argv); -} diff --git a/toolsrc/src/vcpkg-tests/chrono.cpp b/toolsrc/src/vcpkg-tests/chrono.cpp deleted file mode 100644 index c164753f9..000000000 --- a/toolsrc/src/vcpkg-tests/chrono.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include - -#include - -namespace Chrono = vcpkg::Chrono; - -TEST_CASE ("parse time", "[chrono]") -{ - auto timestring = "1990-02-03T04:05:06.0Z"; - auto maybe_time = Chrono::CTime::parse(timestring); - - REQUIRE(maybe_time.has_value()); - REQUIRE(maybe_time.get()->to_string() == timestring); -} - -TEST_CASE ("parse blank time", "[chrono]") -{ - auto maybe_time = Chrono::CTime::parse(""); - - REQUIRE_FALSE(maybe_time.has_value()); -} - -TEST_CASE ("difference of times", "[chrono]") -{ - auto maybe_time1 = Chrono::CTime::parse("1990-02-03T04:05:06.0Z"); - auto maybe_time2 = Chrono::CTime::parse("1990-02-10T04:05:06.0Z"); - - REQUIRE(maybe_time1.has_value()); - REQUIRE(maybe_time2.has_value()); - - auto delta = maybe_time2.get()->to_time_point() - maybe_time1.get()->to_time_point(); - - REQUIRE(std::chrono::duration_cast(delta).count() == 24 * 7); -} diff --git a/toolsrc/src/vcpkg-tests/dependencies.cpp b/toolsrc/src/vcpkg-tests/dependencies.cpp deleted file mode 100644 index 0dee6f296..000000000 --- a/toolsrc/src/vcpkg-tests/dependencies.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -#include - -using namespace vcpkg; -using Parse::parse_comma_list; - -TEST_CASE ("parse depends", "[dependencies]") -{ - auto v = expand_qualified_dependencies(parse_comma_list("libA (windows)")); - REQUIRE(v.size() == 1); - REQUIRE(v.at(0).depend.name == "libA"); - REQUIRE(v.at(0).qualifier == "windows"); -} - -TEST_CASE ("filter depends", "[dependencies]") -{ - auto deps = expand_qualified_dependencies(parse_comma_list("libA (windows), libB, libC (uwp)")); - auto v = filter_dependencies(deps, Triplet::X64_WINDOWS); - REQUIRE(v.size() == 2); - REQUIRE(v.at(0) == "libA"); - REQUIRE(v.at(1) == "libB"); - - auto v2 = filter_dependencies(deps, Triplet::ARM_UWP); - REQUIRE(v.size() == 2); - REQUIRE(v2.at(0) == "libB"); - REQUIRE(v2.at(1) == "libC"); -} diff --git a/toolsrc/src/vcpkg-tests/files.cpp b/toolsrc/src/vcpkg-tests/files.cpp deleted file mode 100644 index d2edffcff..000000000 --- a/toolsrc/src/vcpkg-tests/files.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include - -#include -#include - -#include // required for filesystem::create_{directory_}symlink -#include -#include - -#include - -using vcpkg::Test::SYMLINKS_ALLOWED; -using vcpkg::Test::TEMPORARY_DIRECTORY; - -namespace -{ - using uid = std::uniform_int_distribution; - - std::mt19937_64 get_urbg(std::uint64_t index) - { - // smallest prime > 2**63 - 1 - return std::mt19937_64{index + 9223372036854775837}; - } - - std::string get_random_filename(std::mt19937_64& urbg) { return vcpkg::Strings::b32_encode(uid{}(urbg)); } - - void create_directory_tree(std::mt19937_64& urbg, - vcpkg::Files::Filesystem& fs, - std::uint64_t depth, - const fs::path& base) - { - std::random_device rd; - constexpr std::uint64_t max_depth = 5; - constexpr std::uint64_t width = 5; - - // we want ~70% of our "files" to be directories, and then a third - // each of the remaining ~30% to be regular files, directory symlinks, - // and regular symlinks - constexpr std::uint64_t directory_min_tag = 0; - constexpr std::uint64_t directory_max_tag = 6; - constexpr std::uint64_t regular_file_tag = 7; - constexpr std::uint64_t regular_symlink_tag = 8; - constexpr std::uint64_t directory_symlink_tag = 9; - - // if we're at the max depth, we only want to build non-directories - std::uint64_t file_type; - if (depth < max_depth) - { - file_type = uid{directory_min_tag, regular_symlink_tag}(urbg); - } - else - { - file_type = uid{regular_file_tag, regular_symlink_tag}(urbg); - } - - if (!SYMLINKS_ALLOWED && file_type > regular_file_tag) - { - file_type = regular_file_tag; - } - - std::error_code ec; - if (file_type <= directory_max_tag) - { - fs.create_directory(base, ec); - if (ec) { - INFO("File that failed: " << base); - REQUIRE_FALSE(ec); - } - - for (int i = 0; i < width; ++i) - { - create_directory_tree(urbg, fs, depth + 1, base / get_random_filename(urbg)); - } - } - else if (file_type == regular_file_tag) - { - // regular file - fs.write_contents(base, "", ec); - } - else if (file_type == regular_symlink_tag) - { - // regular symlink - fs.write_contents(base, "", ec); - REQUIRE_FALSE(ec); - const std::filesystem::path basep = base.native(); - auto basep_link = basep; - basep_link.replace_filename(basep.filename().native() + L"-link"); - std::filesystem::create_symlink(basep, basep_link, ec); - } - else // type == directory_symlink_tag - { - // directory symlink - std::filesystem::path basep = base.native(); - std::filesystem::create_directory_symlink(basep / "..", basep, ec); - } - - REQUIRE_FALSE(ec); - } -} - -TEST_CASE ("remove all", "[files]") -{ - auto urbg = get_urbg(0); - - fs::path temp_dir = TEMPORARY_DIRECTORY / get_random_filename(urbg); - - auto& fs = vcpkg::Files::get_real_filesystem(); - - std::error_code ec; - fs.create_directory(TEMPORARY_DIRECTORY, ec); - - REQUIRE_FALSE(ec); - - INFO("temp dir is: " << temp_dir); - - create_directory_tree(urbg, fs, 0, temp_dir); - - fs::path fp; - fs.remove_all(temp_dir, ec, fp); - REQUIRE_FALSE(ec); - - REQUIRE_FALSE(fs.exists(temp_dir)); -} diff --git a/toolsrc/src/vcpkg-tests/paragraph.cpp b/toolsrc/src/vcpkg-tests/paragraph.cpp deleted file mode 100644 index 0fb85ec69..000000000 --- a/toolsrc/src/vcpkg-tests/paragraph.cpp +++ /dev/null @@ -1,445 +0,0 @@ -#include -#include - -#include - -#include - -namespace Strings = vcpkg::Strings; - -TEST_CASE ("SourceParagraph construct minimum", "[paragraph]") -{ - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - }}); - - REQUIRE(m_pgh.has_value()); - auto& pgh = **m_pgh.get(); - - REQUIRE(pgh.core_paragraph->name == "zlib"); - REQUIRE(pgh.core_paragraph->version == "1.2.8"); - REQUIRE(pgh.core_paragraph->maintainer == ""); - REQUIRE(pgh.core_paragraph->description == ""); - REQUIRE(pgh.core_paragraph->depends.size() == 0); -} - -TEST_CASE ("SourceParagraph construct maximum", "[paragraph]") -{ - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "s"}, - {"Version", "v"}, - {"Maintainer", "m"}, - {"Description", "d"}, - {"Build-Depends", "bd"}, - {"Default-Features", "df"}, - {"Supports", "x64"}, - }}); - REQUIRE(m_pgh.has_value()); - auto& pgh = **m_pgh.get(); - - REQUIRE(pgh.core_paragraph->name == "s"); - REQUIRE(pgh.core_paragraph->version == "v"); - REQUIRE(pgh.core_paragraph->maintainer == "m"); - REQUIRE(pgh.core_paragraph->description == "d"); - REQUIRE(pgh.core_paragraph->depends.size() == 1); - REQUIRE(pgh.core_paragraph->depends[0].name() == "bd"); - REQUIRE(pgh.core_paragraph->default_features.size() == 1); - REQUIRE(pgh.core_paragraph->default_features[0] == "df"); - REQUIRE(pgh.core_paragraph->supports.size() == 1); - REQUIRE(pgh.core_paragraph->supports[0] == "x64"); -} - -TEST_CASE ("SourceParagraph two depends", "[paragraph]") -{ - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - {"Build-Depends", "z, openssl"}, - }}); - REQUIRE(m_pgh.has_value()); - auto& pgh = **m_pgh.get(); - - REQUIRE(pgh.core_paragraph->depends.size() == 2); - REQUIRE(pgh.core_paragraph->depends[0].name() == "z"); - REQUIRE(pgh.core_paragraph->depends[1].name() == "openssl"); -} - -TEST_CASE ("SourceParagraph three depends", "[paragraph]") -{ - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - {"Build-Depends", "z, openssl, xyz"}, - }}); - REQUIRE(m_pgh.has_value()); - auto& pgh = **m_pgh.get(); - - REQUIRE(pgh.core_paragraph->depends.size() == 3); - REQUIRE(pgh.core_paragraph->depends[0].name() == "z"); - REQUIRE(pgh.core_paragraph->depends[1].name() == "openssl"); - REQUIRE(pgh.core_paragraph->depends[2].name() == "xyz"); -} - -TEST_CASE ("SourceParagraph three supports", "[paragraph]") -{ - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - {"Supports", "x64, windows, uwp"}, - }}); - REQUIRE(m_pgh.has_value()); - auto& pgh = **m_pgh.get(); - - REQUIRE(pgh.core_paragraph->supports.size() == 3); - REQUIRE(pgh.core_paragraph->supports[0] == "x64"); - REQUIRE(pgh.core_paragraph->supports[1] == "windows"); - REQUIRE(pgh.core_paragraph->supports[2] == "uwp"); -} - -TEST_CASE ("SourceParagraph construct qualified depends", "[paragraph]") -{ - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - {"Build-Depends", "libA (windows), libB (uwp)"}, - }}); - REQUIRE(m_pgh.has_value()); - auto& pgh = **m_pgh.get(); - - REQUIRE(pgh.core_paragraph->name == "zlib"); - REQUIRE(pgh.core_paragraph->version == "1.2.8"); - REQUIRE(pgh.core_paragraph->maintainer == ""); - REQUIRE(pgh.core_paragraph->description == ""); - REQUIRE(pgh.core_paragraph->depends.size() == 2); - REQUIRE(pgh.core_paragraph->depends[0].name() == "libA"); - REQUIRE(pgh.core_paragraph->depends[0].qualifier == "windows"); - REQUIRE(pgh.core_paragraph->depends[1].name() == "libB"); - REQUIRE(pgh.core_paragraph->depends[1].qualifier == "uwp"); -} - -TEST_CASE ("SourceParagraph default features", "[paragraph]") -{ - auto m_pgh = - vcpkg::SourceControlFile::parse_control_file(std::vector>{{ - {"Source", "a"}, - {"Version", "1.0"}, - {"Default-Features", "a1"}, - }}); - REQUIRE(m_pgh.has_value()); - auto& pgh = **m_pgh.get(); - - REQUIRE(pgh.core_paragraph->default_features.size() == 1); - REQUIRE(pgh.core_paragraph->default_features[0] == "a1"); -} - -TEST_CASE ("BinaryParagraph construct minimum", "[paragraph]") -{ - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - }); - - REQUIRE(pgh.spec.name() == "zlib"); - REQUIRE(pgh.version == "1.2.8"); - REQUIRE(pgh.maintainer == ""); - REQUIRE(pgh.description == ""); - REQUIRE(pgh.spec.triplet().canonical_name() == "x86-windows"); - REQUIRE(pgh.depends.size() == 0); -} - -TEST_CASE ("BinaryParagraph construct maximum", "[paragraph]") -{ - vcpkg::BinaryParagraph pgh({ - {"Package", "s"}, - {"Version", "v"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Maintainer", "m"}, - {"Description", "d"}, - {"Depends", "bd"}, - }); - - REQUIRE(pgh.spec.name() == "s"); - REQUIRE(pgh.version == "v"); - REQUIRE(pgh.maintainer == "m"); - REQUIRE(pgh.description == "d"); - REQUIRE(pgh.depends.size() == 1); - REQUIRE(pgh.depends[0] == "bd"); -} - -TEST_CASE ("BinaryParagraph three depends", "[paragraph]") -{ - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Depends", "a, b, c"}, - }); - - REQUIRE(pgh.depends.size() == 3); - REQUIRE(pgh.depends[0] == "a"); - REQUIRE(pgh.depends[1] == "b"); - REQUIRE(pgh.depends[2] == "c"); -} - -TEST_CASE ("BinaryParagraph abi", "[paragraph]") -{ - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Abi", "abcd123"}, - }); - - REQUIRE(pgh.depends.size() == 0); - REQUIRE(pgh.abi == "abcd123"); -} - -TEST_CASE ("BinaryParagraph default features", "[paragraph]") -{ - vcpkg::BinaryParagraph pgh({ - {"Package", "a"}, - {"Version", "1.0"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Default-Features", "a1"}, - }); - - REQUIRE(pgh.depends.size() == 0); - REQUIRE(pgh.default_features.size() == 1); - REQUIRE(pgh.default_features[0] == "a1"); -} - -TEST_CASE ("parse paragraphs empty", "[paragraph]") -{ - const char* str = ""; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - REQUIRE(pghs.empty()); -} - -TEST_CASE ("parse paragraphs one field", "[paragraph]") -{ - const char* str = "f1: v1"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - REQUIRE(pghs.size() == 1); - REQUIRE(pghs[0].size() == 1); - REQUIRE(pghs[0]["f1"] == "v1"); -} - -TEST_CASE ("parse paragraphs one pgh", "[paragraph]") -{ - const char* str = "f1: v1\n" - "f2: v2"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - REQUIRE(pghs.size() == 1); - REQUIRE(pghs[0].size() == 2); - REQUIRE(pghs[0]["f1"] == "v1"); - REQUIRE(pghs[0]["f2"] == "v2"); -} - -TEST_CASE ("parse paragraphs two pgh", "[paragraph]") -{ - const char* str = "f1: v1\n" - "f2: v2\n" - "\n" - "f3: v3\n" - "f4: v4"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - - REQUIRE(pghs.size() == 2); - REQUIRE(pghs[0].size() == 2); - REQUIRE(pghs[0]["f1"] == "v1"); - REQUIRE(pghs[0]["f2"] == "v2"); - REQUIRE(pghs[1].size() == 2); - REQUIRE(pghs[1]["f3"] == "v3"); - REQUIRE(pghs[1]["f4"] == "v4"); -} - -TEST_CASE ("parse paragraphs field names", "[paragraph]") -{ - const char* str = "1:\n" - "f:\n" - "F:\n" - "0:\n" - "F-2:\n"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - - REQUIRE(pghs.size() == 1); - REQUIRE(pghs[0].size() == 5); -} - -TEST_CASE ("parse paragraphs multiple blank lines", "[paragraph]") -{ - const char* str = "f1: v1\n" - "f2: v2\n" - "\n" - "\n" - "f3: v3\n" - "f4: v4"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - - REQUIRE(pghs.size() == 2); -} - -TEST_CASE ("parse paragraphs empty fields", "[paragraph]") -{ - const char* str = "f1:\n" - "f2: "; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - - REQUIRE(pghs.size() == 1); - REQUIRE(pghs[0].size() == 2); - REQUIRE(pghs[0]["f1"] == ""); - REQUIRE(pghs[0]["f2"] == ""); - REQUIRE(pghs[0].size() == 2); -} - -TEST_CASE ("parse paragraphs multiline fields", "[paragraph]") -{ - const char* str = "f1: simple\n" - " f1\r\n" - "f2:\r\n" - " f2\r\n" - " continue\r\n"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - - REQUIRE(pghs.size() == 1); - REQUIRE(pghs[0]["f1"] == "simple\n f1"); - REQUIRE(pghs[0]["f2"] == "\n f2\n continue"); -} - -TEST_CASE ("parse paragraphs crlfs", "[paragraph]") -{ - const char* str = "f1: v1\r\n" - "f2: v2\r\n" - "\r\n" - "f3: v3\r\n" - "f4: v4"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - - REQUIRE(pghs.size() == 2); - REQUIRE(pghs[0].size() == 2); - REQUIRE(pghs[0]["f1"] == "v1"); - REQUIRE(pghs[0]["f2"] == "v2"); - REQUIRE(pghs[1].size() == 2); - REQUIRE(pghs[1]["f3"] == "v3"); - REQUIRE(pghs[1]["f4"] == "v4"); -} - -TEST_CASE ("parse paragraphs comment", "[paragraph]") -{ - const char* str = "f1: v1\r\n" - "#comment\r\n" - "f2: v2\r\n" - "#comment\r\n" - "\r\n" - "#comment\r\n" - "f3: v3\r\n" - "#comment\r\n" - "f4: v4"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - - REQUIRE(pghs.size() == 2); - REQUIRE(pghs[0].size() == 2); - REQUIRE(pghs[0]["f1"] == "v1"); - REQUIRE(pghs[0]["f2"] == "v2"); - REQUIRE(pghs[1].size()); - REQUIRE(pghs[1]["f3"] == "v3"); - REQUIRE(pghs[1]["f4"] == "v4"); -} - -TEST_CASE ("parse comment before single line feed", "[paragraph]") -{ - const char* str = "f1: v1\r\n" - "#comment\n"; - auto pghs = vcpkg::Paragraphs::parse_paragraphs(str).value_or_exit(VCPKG_LINE_INFO); - REQUIRE(pghs[0].size() == 1); - REQUIRE(pghs[0]["f1"] == "v1"); -} - -TEST_CASE ("BinaryParagraph serialize min", "[paragraph]") -{ - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - }); - std::string ss = Strings::serialize(pgh); - auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); - - REQUIRE(pghs.size() == 1); - REQUIRE(pghs[0].size() == 4); - REQUIRE(pghs[0]["Package"] == "zlib"); - REQUIRE(pghs[0]["Version"] == "1.2.8"); - REQUIRE(pghs[0]["Architecture"] == "x86-windows"); - REQUIRE(pghs[0]["Multi-Arch"] == "same"); -} - -TEST_CASE ("BinaryParagraph serialize max", "[paragraph]") -{ - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Description", "first line\n second line"}, - {"Maintainer", "abc "}, - {"Depends", "dep"}, - {"Multi-Arch", "same"}, - }); - std::string ss = Strings::serialize(pgh); - auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); - - REQUIRE(pghs.size() == 1); - REQUIRE(pghs[0].size() == 7); - REQUIRE(pghs[0]["Package"] == "zlib"); - REQUIRE(pghs[0]["Version"] == "1.2.8"); - REQUIRE(pghs[0]["Architecture"] == "x86-windows"); - REQUIRE(pghs[0]["Multi-Arch"] == "same"); - REQUIRE(pghs[0]["Description"] == "first line\n second line"); - REQUIRE(pghs[0]["Depends"] == "dep"); -} - -TEST_CASE ("BinaryParagraph serialize multiple deps", "[paragraph]") -{ - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Depends", "a, b, c"}, - }); - std::string ss = Strings::serialize(pgh); - auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); - - REQUIRE(pghs.size() == 1); - REQUIRE(pghs[0]["Depends"] == "a, b, c"); -} - -TEST_CASE ("BinaryParagraph serialize abi", "[paragraph]") -{ - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "x86-windows"}, - {"Multi-Arch", "same"}, - {"Depends", "a, b, c"}, - {"Abi", "123abc"}, - }); - std::string ss = Strings::serialize(pgh); - auto pghs = vcpkg::Paragraphs::parse_paragraphs(ss).value_or_exit(VCPKG_LINE_INFO); - - REQUIRE(pghs.size() == 1); - REQUIRE(pghs[0]["Abi"] == "123abc"); -} diff --git a/toolsrc/src/vcpkg-tests/plan.cpp b/toolsrc/src/vcpkg-tests/plan.cpp deleted file mode 100644 index 7ecab460b..000000000 --- a/toolsrc/src/vcpkg-tests/plan.cpp +++ /dev/null @@ -1,1241 +0,0 @@ -#include -#include - -#include -#include -#include - -#include -#include -#include - -using namespace vcpkg; - -using Test::make_status_feature_pgh; -using Test::make_status_pgh; -using Test::unsafe_pspec; - -static std::unique_ptr make_control_file( - const char* name, - const char* depends, - const std::vector>& features = {}, - const std::vector& default_features = {}) -{ - using Pgh = std::unordered_map; - std::vector scf_pghs; - scf_pghs.push_back(Pgh{{"Source", name}, - {"Version", "0"}, - {"Build-Depends", depends}, - {"Default-Features", Strings::join(", ", default_features)}}); - for (auto&& feature : features) - { - scf_pghs.push_back(Pgh{ - {"Feature", feature.first}, - {"Description", "feature"}, - {"Build-Depends", feature.second}, - }); - } - auto m_pgh = vcpkg::SourceControlFile::parse_control_file(std::move(scf_pghs)); - REQUIRE(m_pgh.has_value()); - return std::move(*m_pgh.get()); -} - -/// -/// Assert that the given action an install of given features from given package. -/// -static void features_check(Dependencies::AnyAction& install_action, - std::string pkg_name, - std::vector vec, - const Triplet& triplet = Triplet::X86_WINDOWS) -{ - REQUIRE(install_action.install_action.has_value()); - const auto& plan = install_action.install_action.value_or_exit(VCPKG_LINE_INFO); - const auto& feature_list = plan.feature_list; - - REQUIRE(plan.spec.triplet().to_string() == triplet.to_string()); - - auto& scfl = *plan.source_control_file_location.get(); - REQUIRE(pkg_name == scfl.source_control_file->core_paragraph->name); - REQUIRE(feature_list.size() == vec.size()); - - for (auto&& feature_name : vec) - { - // TODO: see if this can be simplified - if (feature_name == "core" || feature_name == "") - { - REQUIRE((Util::find(feature_list, "core") != feature_list.end() || - Util::find(feature_list, "") != feature_list.end())); - continue; - } - REQUIRE(Util::find(feature_list, feature_name) != feature_list.end()); - } -} - -/// -/// Assert that the given action is a remove of given package. -/// -static void remove_plan_check(Dependencies::AnyAction& remove_action, - std::string pkg_name, - const Triplet& triplet = Triplet::X86_WINDOWS) -{ - const auto& plan = remove_action.remove_action.value_or_exit(VCPKG_LINE_INFO); - REQUIRE(plan.spec.triplet().to_string() == triplet.to_string()); - REQUIRE(pkg_name == plan.spec.name()); -} - -/// -/// Map of source control files by their package name. -/// -struct PackageSpecMap -{ - std::unordered_map map; - Triplet triplet; - PackageSpecMap(const Triplet& t = Triplet::X86_WINDOWS) noexcept { triplet = t; } - - PackageSpec emplace(const char* name, - const char* depends = "", - const std::vector>& features = {}, - const std::vector& default_features = {}) - { - auto scfl = SourceControlFileLocation{make_control_file(name, depends, features, default_features), ""}; - return emplace(std::move(scfl)); - } - - PackageSpec emplace(vcpkg::SourceControlFileLocation&& scfl) - { - auto spec = PackageSpec::from_name_and_triplet(scfl.source_control_file->core_paragraph->name, triplet); - REQUIRE(spec.has_value()); - map.emplace(scfl.source_control_file->core_paragraph->name, std::move(scfl)); - return PackageSpec{*spec.get()}; - } -}; - -TEST_CASE ("basic install scheme", "[plan]") -{ - std::vector> status_paragraphs; - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "b"); - auto spec_b = spec_map.emplace("b", "c"); - auto spec_c = spec_map.emplace("c"); - - Dependencies::MapPortFileProvider map_port(spec_map.map); - auto install_plan = Dependencies::create_feature_install_plan( - map_port, {FeatureSpec{spec_a, ""}}, StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 3); - REQUIRE(install_plan.at(0).spec().name() == "c"); - REQUIRE(install_plan.at(1).spec().name() == "b"); - REQUIRE(install_plan.at(2).spec().name() == "a"); -} - -TEST_CASE ("multiple install scheme", "[plan]") -{ - std::vector> status_paragraphs; - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "d"); - auto spec_b = spec_map.emplace("b", "d, e"); - auto spec_c = spec_map.emplace("c", "e, h"); - auto spec_d = spec_map.emplace("d", "f, g, h"); - auto spec_e = spec_map.emplace("e", "g"); - auto spec_f = spec_map.emplace("f"); - auto spec_g = spec_map.emplace("g"); - auto spec_h = spec_map.emplace("h"); - - Dependencies::MapPortFileProvider map_port(spec_map.map); - auto install_plan = Dependencies::create_feature_install_plan( - map_port, - {FeatureSpec{spec_a, ""}, FeatureSpec{spec_b, ""}, FeatureSpec{spec_c, ""}}, - StatusParagraphs(std::move(status_paragraphs))); - - auto iterator_pos = [&](const PackageSpec& spec) { - auto it = - std::find_if(install_plan.begin(), install_plan.end(), [&](auto& action) { return action.spec() == spec; }); - REQUIRE(it != install_plan.end()); - return it - install_plan.begin(); - }; - - const auto a_pos = iterator_pos(spec_a); - const auto b_pos = iterator_pos(spec_b); - const auto c_pos = iterator_pos(spec_c); - const auto d_pos = iterator_pos(spec_d); - const auto e_pos = iterator_pos(spec_e); - const auto f_pos = iterator_pos(spec_f); - const auto g_pos = iterator_pos(spec_g); - const auto h_pos = iterator_pos(spec_h); - - REQUIRE(a_pos > d_pos); - REQUIRE(b_pos > e_pos); - REQUIRE(b_pos > d_pos); - REQUIRE(c_pos > e_pos); - REQUIRE(c_pos > h_pos); - REQUIRE(d_pos > f_pos); - REQUIRE(d_pos > g_pos); - REQUIRE(d_pos > h_pos); - REQUIRE(e_pos > g_pos); -} - -TEST_CASE ("existing package scheme", "[plan]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(vcpkg::Test::make_status_pgh("a")); - - PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a")}; - - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 1); - const auto p = install_plan.at(0).install_action.get(); - REQUIRE(p); - REQUIRE(p->spec.name() == "a"); - REQUIRE(p->plan_type == Dependencies::InstallPlanType::ALREADY_INSTALLED); - REQUIRE(p->request_type == Dependencies::RequestType::USER_REQUESTED); -} - -TEST_CASE ("user requested package scheme", "[plan]") -{ - std::vector> status_paragraphs; - - PackageSpecMap spec_map; - const auto spec_a = FullPackageSpec{spec_map.emplace("a", "b")}; - const auto spec_b = FullPackageSpec{spec_map.emplace("b")}; - - const auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 2); - const auto p = install_plan.at(0).install_action.get(); - REQUIRE(p); - REQUIRE(p->spec.name() == "b"); - REQUIRE(p->plan_type == Dependencies::InstallPlanType::BUILD_AND_INSTALL); - REQUIRE(p->request_type == Dependencies::RequestType::AUTO_SELECTED); - - const auto p2 = install_plan.at(1).install_action.get(); - REQUIRE(p2); - REQUIRE(p2->spec.name() == "a"); - REQUIRE(p2->plan_type == Dependencies::InstallPlanType::BUILD_AND_INSTALL); - REQUIRE(p2->request_type == Dependencies::RequestType::USER_REQUESTED); -} - -TEST_CASE ("long install scheme", "[plan]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("j", "k")); - status_paragraphs.push_back(make_status_pgh("k")); - - PackageSpecMap spec_map; - - auto spec_a = spec_map.emplace("a", "b, c, d, e, f, g, h, j, k"); - auto spec_b = spec_map.emplace("b", "c, d, e, f, g, h, j, k"); - auto spec_c = spec_map.emplace("c", "d, e, f, g, h, j, k"); - auto spec_d = spec_map.emplace("d", "e, f, g, h, j, k"); - auto spec_e = spec_map.emplace("e", "f, g, h, j, k"); - auto spec_f = spec_map.emplace("f", "g, h, j, k"); - auto spec_g = spec_map.emplace("g", "h, j, k"); - auto spec_h = spec_map.emplace("h", "j, k"); - auto spec_j = spec_map.emplace("j", "k"); - auto spec_k = spec_map.emplace("k"); - - Dependencies::MapPortFileProvider map_port(spec_map.map); - auto install_plan = Dependencies::create_feature_install_plan( - map_port, {FeatureSpec{spec_a, ""}}, StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 8); - REQUIRE(install_plan.at(0).spec().name() == "h"); - REQUIRE(install_plan.at(1).spec().name() == "g"); - REQUIRE(install_plan.at(2).spec().name() == "f"); - REQUIRE(install_plan.at(3).spec().name() == "e"); - REQUIRE(install_plan.at(4).spec().name() == "d"); - REQUIRE(install_plan.at(5).spec().name() == "c"); - REQUIRE(install_plan.at(6).spec().name() == "b"); - REQUIRE(install_plan.at(7).spec().name() == "a"); -} - -TEST_CASE ("basic feature test 1", "[plan]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a", "b, b[b1]")); - status_paragraphs.push_back(make_status_pgh("b")); - status_paragraphs.push_back(make_status_feature_pgh("b", "b1")); - - PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b, b[b1]", {{"a1", "b[b2]"}}), {"a1"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})}; - - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 4); - remove_plan_check(install_plan.at(0), "a"); - remove_plan_check(install_plan.at(1), "b"); - features_check(install_plan.at(2), "b", {"b1", "core", "b1"}); - features_check(install_plan.at(3), "a", {"a1", "core"}); -} - -TEST_CASE ("basic feature test 2", "[plan]") -{ - std::vector> status_paragraphs; - - PackageSpecMap spec_map; - - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[b1]", {{"a1", "b[b2]"}}), {"a1"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})}; - - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 2); - features_check(install_plan.at(0), "b", {"b1", "b2", "core"}); - features_check(install_plan.at(1), "a", {"a1", "core"}); -} - -TEST_CASE ("basic feature test 3", "[plan]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - - PackageSpecMap spec_map; - - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b")}; - auto spec_c = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; - - auto install_plan = Dependencies::create_feature_install_plan(spec_map.map, - FullPackageSpec::to_feature_specs({spec_c, spec_a}), - StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 4); - remove_plan_check(install_plan.at(0), "a"); - features_check(install_plan.at(1), "b", {"core"}); - features_check(install_plan.at(2), "a", {"a1", "core"}); - features_check(install_plan.at(3), "c", {"core"}); -} - -TEST_CASE ("basic feature test 4", "[plan]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.push_back(make_status_feature_pgh("a", "a1", "")); - - PackageSpecMap spec_map; - - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}})}; - auto spec_b = FullPackageSpec{spec_map.emplace("b")}; - auto spec_c = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; - - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, FullPackageSpec::to_feature_specs({spec_c}), StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 1); - features_check(install_plan.at(0), "c", {"core"}); -} - -TEST_CASE ("basic feature test 5", "[plan]") -{ - std::vector> status_paragraphs; - - PackageSpecMap spec_map; - - auto spec_a = - FullPackageSpec{spec_map.emplace("a", "", {{"a1", "b[b1]"}, {"a2", "b[b2]"}, {"a3", "a[a2]"}}), {"a3"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}})}; - - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, FullPackageSpec::to_feature_specs({spec_a}), StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 2); - features_check(install_plan.at(0), "b", {"core", "b2"}); - features_check(install_plan.at(1), "a", {"core", "a3", "a2"}); -} - -TEST_CASE ("basic feature test 6", "[plan]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("b")); - - PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[core]"), {"core"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {"b1"}}; - - auto install_plan = Dependencies::create_feature_install_plan(spec_map.map, - FullPackageSpec::to_feature_specs({spec_a, spec_b}), - StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 3); - remove_plan_check(install_plan.at(0), "b"); - features_check(install_plan.at(1), "b", {"core", "b1"}); - features_check(install_plan.at(2), "a", {"core"}); -} - -TEST_CASE ("basic feature test 7", "[plan]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("x", "b")); - status_paragraphs.push_back(make_status_pgh("b")); - - PackageSpecMap spec_map; - - auto spec_a = FullPackageSpec{spec_map.emplace("a")}; - auto spec_x = FullPackageSpec{spec_map.emplace("x", "a"), {"core"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {"b1"}}; - - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, FullPackageSpec::to_feature_specs({spec_b}), StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 5); - remove_plan_check(install_plan.at(0), "x"); - remove_plan_check(install_plan.at(1), "b"); - - // TODO: order here may change but A < X, and B anywhere - features_check(install_plan.at(2), "b", {"core", "b1"}); - features_check(install_plan.at(3), "a", {"core"}); - features_check(install_plan.at(4), "x", {"core"}); -} - -TEST_CASE ("basic feature test 8", "[plan][!mayfail]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.spec = - PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b")}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; - - spec_map.triplet = Triplet::X86_WINDOWS; - auto spec_a_86 = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; - auto spec_b_86 = FullPackageSpec{spec_map.emplace("b")}; - auto spec_c_86 = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; - - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({spec_c_64, spec_a_86, spec_a_64, spec_c_86}), - StatusParagraphs(std::move(status_paragraphs))); - - remove_plan_check(install_plan.at(0), "a", Triplet::X64_WINDOWS); - remove_plan_check(install_plan.at(1), "a"); - features_check(install_plan.at(2), "b", {"core"}, Triplet::X64_WINDOWS); - features_check(install_plan.at(3), "a", {"a1", "core"}, Triplet::X64_WINDOWS); - features_check(install_plan.at(4), "c", {"core"}, Triplet::X64_WINDOWS); - features_check(install_plan.at(5), "b", {"core"}); - features_check(install_plan.at(6), "a", {"a1", "core"}); - features_check(install_plan.at(7), "c", {"core"}); -} - -TEST_CASE ("install all features test", "[plan]") -{ - std::vector> status_paragraphs; - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}), {"core"}}; - - auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); - REQUIRE(install_specs.has_value()); - if (!install_specs.has_value()) return; - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 1); - features_check(install_plan.at(0), "a", {"0", "1", "core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("install default features test 1", "[plan]") -{ - std::vector> status_paragraphs; - - // Add a port "a" with default features "1" and features "0" and "1". - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}, {"1"}); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect the default feature "1" to be installed, but not "0" - REQUIRE(install_plan.size() == 1); - features_check(install_plan.at(0), "a", {"1", "core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("install default features test 2", "[plan]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.spec = - PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - - // Add a port "a" of which "core" is already installed, but we will - // install the default features "explicitly" - // "a" has two features, of which "a1" is default. - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "", {{"a0", ""}, {"a1", ""}}, {"a1"}); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect "a" to get removed for rebuild and then installed with default - // features. - REQUIRE(install_plan.size() == 2); - remove_plan_check(install_plan.at(0), "a", Triplet::X64_WINDOWS); - features_check(install_plan.at(1), "a", {"a1", "core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("install default features test 3", "[plan]") -{ - std::vector> status_paragraphs; - - // "a" has two features, of which "a1" is default. - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "", {{"a0", ""}, {"a1", ""}}, {"a1"}); - - // Explicitly install "a" without default features - auto install_specs = FullPackageSpec::from_string("a[core]", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect the default feature not to get installed. - REQUIRE(install_plan.size() == 1); - features_check(install_plan.at(0), "a", {"core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("install default features of dependency test 1", "[plan]") -{ - std::vector> status_paragraphs; - - // Add a port "a" which depends on the core of "b" - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "b[core]"); - // "b" has two features, of which "b1" is default. - spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect "a" to get installed and defaults of "b" through the dependency, - // as no explicit features of "b" are installed by the user. - REQUIRE(install_plan.size() == 2); - features_check(install_plan.at(0), "b", {"b1", "core"}, Triplet::X64_WINDOWS); - features_check(install_plan.at(1), "a", {"core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("do not install default features of existing dependency", "[plan]") -{ - // Add a port "a" which depends on the core of "b" - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "b[core]"); - // "b" has two features, of which "b1" is default. - spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); - - std::vector> status_paragraphs; - // "b[core]" is already installed - status_paragraphs.push_back(make_status_pgh("b")); - status_paragraphs.back()->package.spec = - PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect "a" to get installed, but not require rebuilding "b" - REQUIRE(install_plan.size() == 1); - features_check(install_plan.at(0), "a", {"core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("install default features of dependency test 2", "[plan]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("b")); - status_paragraphs.back()->package.spec = - PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - - // Add a port "a" which depends on the core of "b", which was already - // installed explicitly - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "b[core]"); - // "b" has two features, of which "b1" is default. - spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - // Expect "a" to get installed, not the defaults of "b", as the required - // dependencies are already there, installed explicitly by the user. - REQUIRE(install_plan.size() == 1); - features_check(install_plan.at(0), "a", {"core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("install plan action dependencies", "[plan]") -{ - std::vector> status_paragraphs; - - // Add a port "a" which depends on the core of "b", which was already - // installed explicitly - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_c = spec_map.emplace("c"); - auto spec_b = spec_map.emplace("b", "c"); - spec_map.emplace("a", "b"); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 3); - features_check(install_plan.at(0), "c", {"core"}, Triplet::X64_WINDOWS); - - features_check(install_plan.at(1), "b", {"core"}, Triplet::X64_WINDOWS); - REQUIRE(install_plan.at(1).install_action.get()->computed_dependencies == std::vector{spec_c}); - - features_check(install_plan.at(2), "a", {"core"}, Triplet::X64_WINDOWS); - REQUIRE(install_plan.at(2).install_action.get()->computed_dependencies == std::vector{spec_b}); -} - -TEST_CASE ("install plan action dependencies 2", "[plan]") -{ - std::vector> status_paragraphs; - - // Add a port "a" which depends on the core of "b", which was already - // installed explicitly - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_c = spec_map.emplace("c"); - auto spec_b = spec_map.emplace("b", "c"); - spec_map.emplace("a", "c, b"); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 3); - features_check(install_plan.at(0), "c", {"core"}, Triplet::X64_WINDOWS); - - features_check(install_plan.at(1), "b", {"core"}, Triplet::X64_WINDOWS); - REQUIRE(install_plan.at(1).install_action.get()->computed_dependencies == std::vector{spec_c}); - - features_check(install_plan.at(2), "a", {"core"}, Triplet::X64_WINDOWS); - REQUIRE(install_plan.at(2).install_action.get()->computed_dependencies == std::vector{spec_b, spec_c}); -} - -TEST_CASE ("install plan action dependencies 3", "[plan]") -{ - std::vector> status_paragraphs; - - // Add a port "a" which depends on the core of "b", which was already - // installed explicitly - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - spec_map.emplace("a", "", {{"0", ""}, {"1", "a[0]"}}, {"1"}); - - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Triplet::X64_WINDOWS); - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 1); - features_check(install_plan.at(0), "a", {"1", "0", "core"}, Triplet::X64_WINDOWS); - REQUIRE(install_plan.at(0).install_action.get()->computed_dependencies == std::vector{}); -} - -TEST_CASE ("install with default features", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a", "")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto b_spec = spec_map.emplace("b", "", {{"0", ""}}, {"0"}); - auto a_spec = spec_map.emplace("a", "b[core]", {{"0", ""}}); - - // Install "a" and indicate that "b" should not install default features - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, {FeatureSpec{a_spec, "0"}, FeatureSpec{b_spec, "core"}}, status_db); - - REQUIRE(install_plan.size() == 3); - remove_plan_check(install_plan.at(0), "a"); - features_check(install_plan.at(1), "b", {"core"}); - features_check(install_plan.at(2), "a", {"0", "core"}); -} - -TEST_CASE ("upgrade with default features 1", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a", "", "1")); - pghs.push_back(make_status_feature_pgh("a", "0")); - StatusParagraphs status_db(std::move(pghs)); - - // Add a port "a" of which "core" and "0" are already installed. - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}, {"1"}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - auto plan = graph.serialize(); - - // The upgrade should not install the default feature - REQUIRE(plan.size() == 2); - - REQUIRE(plan.at(0).spec().name() == "a"); - remove_plan_check(plan.at(0), "a"); - features_check(plan.at(1), "a", {"core", "0"}); -} - -TEST_CASE ("upgrade with default features 2", "[plan]") -{ - std::vector> pghs; - // B is currently installed _without_ default feature b0 - pghs.push_back(make_status_pgh("b", "", "b0", "x64-windows")); - pghs.push_back(make_status_pgh("a", "b[core]", "", "x64-windows")); - - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a = spec_map.emplace("a", "b[core]"); - auto spec_b = spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b0", "b1"}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - graph.upgrade(spec_b); - auto plan = graph.serialize(); - - // The upgrade should install the new default feature b1 but not b0 - REQUIRE(plan.size() == 4); - remove_plan_check(plan.at(0), "a", Triplet::X64_WINDOWS); - remove_plan_check(plan.at(1), "b", Triplet::X64_WINDOWS); - features_check(plan.at(2), "b", {"core", "b1"}, Triplet::X64_WINDOWS); - features_check(plan.at(3), "a", {"core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("upgrade with default features 3", "[plan]") -{ - std::vector> pghs; - // note: unrelated package due to x86 triplet - pghs.push_back(make_status_pgh("b", "", "", "x86-windows")); - pghs.push_back(make_status_pgh("a", "", "", "x64-windows")); - - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a = spec_map.emplace("a", "b[core]"); - spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b0"}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - auto plan = graph.serialize(); - - // The upgrade should install the default feature - REQUIRE(plan.size() == 3); - remove_plan_check(plan.at(0), "a", Triplet::X64_WINDOWS); - features_check(plan.at(1), "b", {"b0", "core"}, Triplet::X64_WINDOWS); - features_check(plan.at(2), "a", {"core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("upgrade with new default feature", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a", "", "0", "x86-windows")); - - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"0", ""}, {"1", ""}, {"2", ""}}, {"0", "1"}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - auto plan = graph.serialize(); - - // The upgrade should install the new default feature but not the old default feature 0 - REQUIRE(plan.size() == 2); - remove_plan_check(plan.at(0), "a", Triplet::X86_WINDOWS); - features_check(plan.at(1), "a", {"core", "1"}, Triplet::X86_WINDOWS); -} - -TEST_CASE ("transitive features test", "[plan]") -{ - std::vector> status_paragraphs; - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"0", "b[0]"}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "c", {{"0", "c[0]"}}), {"core"}}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; - - auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); - REQUIRE(install_specs.has_value()); - if (!install_specs.has_value()) return; - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 3); - features_check(install_plan.at(0), "c", {"0", "core"}, Triplet::X64_WINDOWS); - features_check(install_plan.at(1), "b", {"0", "core"}, Triplet::X64_WINDOWS); - features_check(install_plan.at(2), "a", {"0", "core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("no transitive features test", "[plan]") -{ - std::vector> status_paragraphs; - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"0", ""}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "c", {{"0", ""}}), {"core"}}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; - - auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); - REQUIRE(install_specs.has_value()); - if (!install_specs.has_value()) return; - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 3); - features_check(install_plan.at(0), "c", {"core"}, Triplet::X64_WINDOWS); - features_check(install_plan.at(1), "b", {"core"}, Triplet::X64_WINDOWS); - features_check(install_plan.at(2), "a", {"0", "core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("only transitive features test", "[plan]") -{ - std::vector> status_paragraphs; - - PackageSpecMap spec_map(Triplet::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "", {{"0", "b[0]"}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "", {{"0", "c[0]"}}), {"core"}}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; - - auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS); - REQUIRE(install_specs.has_value()); - if (!install_specs.has_value()) return; - auto install_plan = Dependencies::create_feature_install_plan( - spec_map.map, - FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}), - StatusParagraphs(std::move(status_paragraphs))); - - REQUIRE(install_plan.size() == 3); - features_check(install_plan.at(0), "c", {"0", "core"}, Triplet::X64_WINDOWS); - features_check(install_plan.at(1), "b", {"0", "core"}, Triplet::X64_WINDOWS); - features_check(install_plan.at(2), "a", {"0", "core"}, Triplet::X64_WINDOWS); -} - -TEST_CASE ("basic remove scheme", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); - - REQUIRE(remove_plan.size() == 1); - REQUIRE(remove_plan.at(0).spec.name() == "a"); -} - -TEST_CASE ("recurse remove scheme", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b", "a")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); - - REQUIRE(remove_plan.size() == 2); - REQUIRE(remove_plan.at(0).spec.name() == "b"); - REQUIRE(remove_plan.at(1).spec.name() == "a"); -} - -TEST_CASE ("features depend remove scheme", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b")); - pghs.push_back(make_status_feature_pgh("b", "0", "a")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("a")}, status_db); - - REQUIRE(remove_plan.size() == 2); - REQUIRE(remove_plan.at(0).spec.name() == "b"); - REQUIRE(remove_plan.at(1).spec.name() == "a"); -} - -TEST_CASE ("features depend remove scheme once removed", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("expat")); - pghs.push_back(make_status_pgh("vtk", "expat")); - pghs.push_back(make_status_pgh("opencv")); - pghs.push_back(make_status_feature_pgh("opencv", "vtk", "vtk")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = Dependencies::create_remove_plan({unsafe_pspec("expat")}, status_db); - - REQUIRE(remove_plan.size() == 3); - REQUIRE(remove_plan.at(0).spec.name() == "opencv"); - REQUIRE(remove_plan.at(1).spec.name() == "vtk"); - REQUIRE(remove_plan.at(2).spec.name() == "expat"); -} - -TEST_CASE ("features depend remove scheme once removed x64", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("expat", "", "", "x64")); - pghs.push_back(make_status_pgh("vtk", "expat", "", "x64")); - pghs.push_back(make_status_pgh("opencv", "", "", "x64")); - pghs.push_back(make_status_feature_pgh("opencv", "vtk", "vtk", "x64")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = - Dependencies::create_remove_plan({unsafe_pspec("expat", Triplet::from_canonical_name("x64"))}, status_db); - - REQUIRE(remove_plan.size() == 3); - REQUIRE(remove_plan.at(0).spec.name() == "opencv"); - REQUIRE(remove_plan.at(1).spec.name() == "vtk"); - REQUIRE(remove_plan.at(2).spec.name() == "expat"); -} - -TEST_CASE ("features depend core remove scheme", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("curl", "", "", "x64")); - pghs.push_back(make_status_pgh("cpr", "curl[core]", "", "x64")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = - Dependencies::create_remove_plan({unsafe_pspec("curl", Triplet::from_canonical_name("x64"))}, status_db); - - REQUIRE(remove_plan.size() == 2); - REQUIRE(remove_plan.at(0).spec.name() == "cpr"); - REQUIRE(remove_plan.at(1).spec.name() == "curl"); -} - -TEST_CASE ("features depend core remove scheme 2", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("curl", "", "", "x64")); - pghs.push_back(make_status_feature_pgh("curl", "a", "", "x64")); - pghs.push_back(make_status_feature_pgh("curl", "b", "curl[a]", "x64")); - StatusParagraphs status_db(std::move(pghs)); - - auto remove_plan = - Dependencies::create_remove_plan({unsafe_pspec("curl", Triplet::from_canonical_name("x64"))}, status_db); - - REQUIRE(remove_plan.size() == 1); - REQUIRE(remove_plan.at(0).spec.name() == "curl"); -} - -TEST_CASE ("basic upgrade scheme", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - REQUIRE(plan.size() == 2); - REQUIRE(plan.at(0).spec().name() == "a"); - REQUIRE(plan.at(0).remove_action.has_value()); - REQUIRE(plan.at(1).spec().name() == "a"); - REQUIRE(plan.at(1).install_action.has_value()); -} - -TEST_CASE ("basic upgrade scheme with recurse", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b", "a")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - spec_map.emplace("b", "a"); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - REQUIRE(plan.size() == 4); - REQUIRE(plan.at(0).spec().name() == "b"); - REQUIRE(plan.at(0).remove_action.has_value()); - - REQUIRE(plan.at(1).spec().name() == "a"); - REQUIRE(plan.at(1).remove_action.has_value()); - - REQUIRE(plan.at(2).spec().name() == "a"); - REQUIRE(plan.at(2).install_action.has_value()); - - REQUIRE(plan.at(3).spec().name() == "b"); - REQUIRE(plan.at(3).install_action.has_value()); -} - -TEST_CASE ("basic upgrade scheme with bystander", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - spec_map.emplace("b", "a"); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - REQUIRE(plan.size() == 2); - REQUIRE(plan.at(0).spec().name() == "a"); - REQUIRE(plan.at(0).remove_action.has_value()); - REQUIRE(plan.at(1).spec().name() == "a"); - REQUIRE(plan.at(1).install_action.has_value()); -} - -TEST_CASE ("basic upgrade scheme with new dep", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "b"); - spec_map.emplace("b"); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - REQUIRE(plan.size() == 3); - REQUIRE(plan.at(0).spec().name() == "a"); - REQUIRE(plan.at(0).remove_action.has_value()); - REQUIRE(plan.at(1).spec().name() == "b"); - REQUIRE(plan.at(1).install_action.has_value()); - REQUIRE(plan.at(2).spec().name() == "a"); - REQUIRE(plan.at(2).install_action.has_value()); -} - -TEST_CASE ("basic upgrade scheme with features", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_feature_pgh("a", "a1")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - REQUIRE(plan.size() == 2); - - REQUIRE(plan.at(0).spec().name() == "a"); - REQUIRE(plan.at(0).remove_action.has_value()); - - features_check(plan.at(1), "a", {"core", "a1"}); -} - -TEST_CASE ("basic upgrade scheme with new default feature", "[plan]") -{ - // only core of package "a" is installed - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - StatusParagraphs status_db(std::move(pghs)); - - // a1 was added as a default feature and should be installed in upgrade - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}, {"a1"}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - REQUIRE(plan.size() == 2); - - REQUIRE(plan.at(0).spec().name() == "a"); - REQUIRE(plan.at(0).remove_action.has_value()); - - features_check(plan.at(1), "a", {"core", "a1"}); -} - -TEST_CASE ("basic upgrade scheme with self features", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_feature_pgh("a", "a1", "")); - pghs.push_back(make_status_feature_pgh("a", "a2", "a[a1]")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"a1", ""}, {"a2", "a[a1]"}}); - - Dependencies::MapPortFileProvider provider(spec_map.map); - Dependencies::PackageGraph graph(provider, status_db); - - graph.upgrade(spec_a); - - auto plan = graph.serialize(); - - REQUIRE(plan.size() == 2); - - REQUIRE(plan.at(0).spec().name() == "a"); - REQUIRE(plan.at(0).remove_action.has_value()); - - REQUIRE(plan.at(1).spec().name() == "a"); - REQUIRE(plan.at(1).install_action.has_value()); - REQUIRE(plan.at(1).install_action.get()->feature_list == std::set{"core", "a1", "a2"}); -} - -TEST_CASE ("basic export scheme", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - - auto plan = Dependencies::create_export_plan({spec_a}, status_db); - - REQUIRE(plan.size() == 1); - REQUIRE(plan.at(0).spec.name() == "a"); - REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); -} - -TEST_CASE ("basic export scheme with recurse", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b", "a")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - auto spec_b = spec_map.emplace("b", "a"); - - auto plan = Dependencies::create_export_plan({spec_b}, status_db); - - REQUIRE(plan.size() == 2); - REQUIRE(plan.at(0).spec.name() == "a"); - REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); - - REQUIRE(plan.at(1).spec.name() == "b"); - REQUIRE(plan.at(1).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); -} - -TEST_CASE ("basic export scheme with bystander", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_pgh("b")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - auto spec_b = spec_map.emplace("b", "a"); - - auto plan = Dependencies::create_export_plan({spec_a}, status_db); - - REQUIRE(plan.size() == 1); - REQUIRE(plan.at(0).spec.name() == "a"); - REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); -} - -TEST_CASE ("basic export scheme with missing", "[plan]") -{ - StatusParagraphs status_db; - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a"); - - auto plan = Dependencies::create_export_plan({spec_a}, status_db); - - REQUIRE(plan.size() == 1); - REQUIRE(plan.at(0).spec.name() == "a"); - REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::NOT_BUILT); -} - -TEST_CASE ("basic export scheme with features", "[plan]") -{ - std::vector> pghs; - pghs.push_back(make_status_pgh("b")); - pghs.push_back(make_status_pgh("a")); - pghs.push_back(make_status_feature_pgh("a", "a1", "b[core]")); - StatusParagraphs status_db(std::move(pghs)); - - PackageSpecMap spec_map; - auto spec_a = spec_map.emplace("a", "", {{"a1", ""}}); - - auto plan = Dependencies::create_export_plan({spec_a}, status_db); - - REQUIRE(plan.size() == 2); - - REQUIRE(plan.at(0).spec.name() == "b"); - REQUIRE(plan.at(0).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); - - REQUIRE(plan.at(1).spec.name() == "a"); - REQUIRE(plan.at(1).plan_type == Dependencies::ExportPlanType::ALREADY_BUILT); -} diff --git a/toolsrc/src/vcpkg-tests/specifier.cpp b/toolsrc/src/vcpkg-tests/specifier.cpp deleted file mode 100644 index 52ef044e7..000000000 --- a/toolsrc/src/vcpkg-tests/specifier.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include - -#include -#include - -using namespace vcpkg; - -TEST_CASE ("specifier conversion", "[specifier]") -{ - SECTION ("full package spec to feature specs") - { - constexpr std::size_t SPEC_SIZE = 6; - - auto a_spec = PackageSpec::from_name_and_triplet("a", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - auto b_spec = PackageSpec::from_name_and_triplet("b", Triplet::X64_WINDOWS).value_or_exit(VCPKG_LINE_INFO); - - auto fspecs = FullPackageSpec::to_feature_specs({{a_spec, {"0", "1"}}, {b_spec, {"2", "3"}}}); - - REQUIRE(fspecs.size() == SPEC_SIZE); - - std::array features = {"", "0", "1", "", "2", "3"}; - std::array specs = {&a_spec, &a_spec, &a_spec, &b_spec, &b_spec, &b_spec}; - - for (std::size_t i = 0; i < SPEC_SIZE; ++i) - { - REQUIRE(features.at(i) == fspecs.at(i).feature()); - REQUIRE(*specs.at(i) == fspecs.at(i).spec()); - } - } -} - -TEST_CASE ("specifier parsing", "[specifier]") -{ - SECTION ("parsed specifier from string") - { - auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib"); - REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); - - auto& spec = *maybe_spec.get(); - REQUIRE(spec.name == "zlib"); - REQUIRE(spec.features.size() == 0); - REQUIRE(spec.triplet == ""); - } - - SECTION ("parsed specifier from string with triplet") - { - auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib:x64-uwp"); - REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); - - auto& spec = *maybe_spec.get(); - REQUIRE(spec.name == "zlib"); - REQUIRE(spec.triplet == "x64-uwp"); - } - - SECTION ("parsed specifier from string with colons") - { - auto ec = vcpkg::ParsedSpecifier::from_string("zlib:x86-uwp:").error(); - REQUIRE(ec == vcpkg::PackageSpecParseResult::TOO_MANY_COLONS); - } - - SECTION ("parsed specifier from string with feature") - { - auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[feature]:x64-uwp"); - REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); - - auto& spec = *maybe_spec.get(); - REQUIRE(spec.name == "zlib"); - REQUIRE(spec.features.size() == 1); - REQUIRE(spec.features.at(0) == "feature"); - REQUIRE(spec.triplet == "x64-uwp"); - } - - SECTION ("parsed specifier from string with many features") - { - auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[0, 1,2]"); - REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); - - auto& spec = *maybe_spec.get(); - REQUIRE(spec.name == "zlib"); - REQUIRE(spec.features.size() == 3); - REQUIRE(spec.features.at(0) == "0"); - REQUIRE(spec.features.at(1) == "1"); - REQUIRE(spec.features.at(2) == "2"); - REQUIRE(spec.triplet == ""); - } - - SECTION ("parsed specifier wildcard feature") - { - auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[*]"); - REQUIRE(maybe_spec.error() == vcpkg::PackageSpecParseResult::SUCCESS); - - auto& spec = *maybe_spec.get(); - REQUIRE(spec.name == "zlib"); - REQUIRE(spec.features.size() == 1); - REQUIRE(spec.features.at(0) == "*"); - REQUIRE(spec.triplet == ""); - } - - SECTION ("expand wildcards") - { - auto zlib = vcpkg::FullPackageSpec::from_string("zlib[0,1]", Triplet::X86_UWP).value_or_exit(VCPKG_LINE_INFO); - auto openssl = - vcpkg::FullPackageSpec::from_string("openssl[*]", Triplet::X86_UWP).value_or_exit(VCPKG_LINE_INFO); - auto specs = FullPackageSpec::to_feature_specs({zlib, openssl}); - Util::sort(specs); - auto spectargets = FeatureSpec::from_strings_and_triplet( - { - "openssl", - "zlib", - "openssl[*]", - "zlib[0]", - "zlib[1]", - }, - Triplet::X86_UWP); - Util::sort(spectargets); - - REQUIRE(specs.size() == spectargets.size()); - REQUIRE(Util::all_equal(specs, spectargets)); - } - -#if defined(_WIN32) - SECTION ("ASCII to utf16") - { - auto str = vcpkg::Strings::to_utf16("abc"); - REQUIRE(str == L"abc"); - } - - SECTION ("ASCII to utf16 with whitespace") - { - auto str = vcpkg::Strings::to_utf16("abc -x86-windows"); - REQUIRE(str == L"abc -x86-windows"); - } -#endif -}; diff --git a/toolsrc/src/vcpkg-tests/statusparagraphs.cpp b/toolsrc/src/vcpkg-tests/statusparagraphs.cpp deleted file mode 100644 index df52ccb87..000000000 --- a/toolsrc/src/vcpkg-tests/statusparagraphs.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include - -#include -#include -#include - -using namespace vcpkg; -using namespace vcpkg::Paragraphs; -using namespace vcpkg::Test; - -TEST_CASE ("find installed", "[statusparagraphs]") -{ - auto pghs = parse_paragraphs(R"( -Package: ffmpeg -Version: 3.3.3 -Architecture: x64-windows -Multi-Arch: same -Description: -Status: install ok installed -)"); - - REQUIRE(pghs); - - StatusParagraphs status_db( - Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); - - auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); - REQUIRE(it != status_db.end()); -} - -TEST_CASE ("find not installed", "[statusparagraphs]") -{ - auto pghs = parse_paragraphs(R"( -Package: ffmpeg -Version: 3.3.3 -Architecture: x64-windows -Multi-Arch: same -Description: -Status: purge ok not-installed -)"); - - REQUIRE(pghs); - - StatusParagraphs status_db( - Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); - - auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); - REQUIRE(it == status_db.end()); -} - -TEST_CASE ("find with feature packages", "[statusparagraphs]") -{ - auto pghs = parse_paragraphs(R"( -Package: ffmpeg -Version: 3.3.3 -Architecture: x64-windows -Multi-Arch: same -Description: -Status: install ok installed - -Package: ffmpeg -Feature: openssl -Depends: openssl -Architecture: x64-windows -Multi-Arch: same -Description: -Status: purge ok not-installed -)"); - - REQUIRE(pghs); - - StatusParagraphs status_db( - Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); - - auto it = status_db.find_installed(unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS)); - REQUIRE(it != status_db.end()); - - // Feature "openssl" is not installed and should not be found - auto it1 = status_db.find_installed({unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS), "openssl"}); - REQUIRE(it1 == status_db.end()); -} - -TEST_CASE ("find for feature packages", "[statusparagraphs]") -{ - auto pghs = parse_paragraphs(R"( -Package: ffmpeg -Version: 3.3.3 -Architecture: x64-windows -Multi-Arch: same -Description: -Status: install ok installed - -Package: ffmpeg -Feature: openssl -Depends: openssl -Architecture: x64-windows -Multi-Arch: same -Description: -Status: install ok installed -)"); - REQUIRE(pghs); - - StatusParagraphs status_db( - Util::fmap(*pghs.get(), [](RawParagraph& rpgh) { return std::make_unique(std::move(rpgh)); })); - - // Feature "openssl" is installed and should therefore be found - auto it = status_db.find_installed({unsafe_pspec("ffmpeg", Triplet::X64_WINDOWS), "openssl"}); - REQUIRE(it != status_db.end()); -} diff --git a/toolsrc/src/vcpkg-tests/strings.cpp b/toolsrc/src/vcpkg-tests/strings.cpp deleted file mode 100644 index 3168a7c95..000000000 --- a/toolsrc/src/vcpkg-tests/strings.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include - -#include - -#include -#include -#include - -TEST_CASE ("b32 encoding", "[strings]") -{ - using u64 = std::uint64_t; - - std::vector> map; - - map.emplace_back(0, "AAAAAAAAAAAAA"); - map.emplace_back(1, "BAAAAAAAAAAAA"); - - map.emplace_back(u64(1) << 32, "AAAAAAEAAAAAA"); - map.emplace_back((u64(1) << 32) + 1, "BAAAAAEAAAAAA"); - - map.emplace_back(0xE4D0'1065'D11E'0229, "JRA4RIXMQAUJO"); - map.emplace_back(0xA626'FE45'B135'07FF, "77BKTYWI6XJMK"); - map.emplace_back(0xEE36'D228'0C31'D405, "FAVDDGAFSWN4O"); - map.emplace_back(0x1405'64E7'FE7E'A88C, "MEK5H774ELBIB"); - map.emplace_back(0xFFFF'FFFF'FFFF'FFFF, "777777777777P"); - - std::string result; - for (const auto& pr : map) - { - result = vcpkg::Strings::b32_encode(pr.first); - REQUIRE(vcpkg::Strings::b32_encode(pr.first) == pr.second); - } -} diff --git a/toolsrc/src/vcpkg-tests/supports.cpp b/toolsrc/src/vcpkg-tests/supports.cpp deleted file mode 100644 index c6c88bdbc..000000000 --- a/toolsrc/src/vcpkg-tests/supports.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include - -#include - -using namespace vcpkg; -using Parse::parse_comma_list; - -TEST_CASE ("parse supports all", "[supports]") -{ - auto v = Supports::parse({ - "x64", - "x86", - "arm", - "windows", - "uwp", - "v140", - "v141", - "crt-static", - "crt-dynamic", - }); - - REQUIRE(v.has_value()); - - REQUIRE(v.get()->is_supported(System::CPUArchitecture::X64, - Supports::Platform::UWP, - Supports::Linkage::DYNAMIC, - Supports::ToolsetVersion::V140)); - REQUIRE(v.get()->is_supported(System::CPUArchitecture::ARM, - Supports::Platform::WINDOWS, - Supports::Linkage::STATIC, - Supports::ToolsetVersion::V141)); -} - -TEST_CASE ("parse supports invalid", "[supports]") -{ - auto v = Supports::parse({"arm64"}); - - REQUIRE_FALSE(v.has_value()); - - REQUIRE(v.error().size() == 1); - REQUIRE(v.error().at(0) == "arm64"); -} - -TEST_CASE ("parse supports case sensitive", "[supports]") -{ - auto v = Supports::parse({"Windows"}); - - REQUIRE_FALSE(v.has_value()); - REQUIRE(v.error().size() == 1); - REQUIRE(v.error().at(0) == "Windows"); -} - -TEST_CASE ("parse supports some", "[supports]") -{ - auto v = Supports::parse({ - "x64", - "x86", - "windows", - }); - - REQUIRE(v.has_value()); - - REQUIRE(v.get()->is_supported(System::CPUArchitecture::X64, - Supports::Platform::WINDOWS, - Supports::Linkage::DYNAMIC, - Supports::ToolsetVersion::V140)); - REQUIRE_FALSE(v.get()->is_supported(System::CPUArchitecture::ARM, - Supports::Platform::WINDOWS, - Supports::Linkage::DYNAMIC, - Supports::ToolsetVersion::V140)); - REQUIRE_FALSE(v.get()->is_supported(System::CPUArchitecture::X64, - Supports::Platform::UWP, - Supports::Linkage::DYNAMIC, - Supports::ToolsetVersion::V140)); - REQUIRE(v.get()->is_supported(System::CPUArchitecture::X64, - Supports::Platform::WINDOWS, - Supports::Linkage::STATIC, - Supports::ToolsetVersion::V141)); -} diff --git a/toolsrc/src/vcpkg-tests/update.cpp b/toolsrc/src/vcpkg-tests/update.cpp deleted file mode 100644 index 93a8f74a9..000000000 --- a/toolsrc/src/vcpkg-tests/update.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include -#include - -#include - -#include - -using namespace vcpkg; -using namespace vcpkg::Update; -using namespace vcpkg::Test; - -using Pgh = std::vector>; - -TEST_CASE ("find outdated packages basic", "[update]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.version = "2"; - - StatusParagraphs status_db(std::move(status_paragraphs)); - - std::unordered_map map; - auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); - map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); - Dependencies::MapPortFileProvider provider(map); - - auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), - &OutdatedPackage::compare_by_name); - - REQUIRE(pkgs.size() == 1); - REQUIRE(pkgs[0].version_diff.left.to_string() == "2"); - REQUIRE(pkgs[0].version_diff.right.to_string() == "0"); -} - -TEST_CASE ("find outdated packages features", "[update]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.version = "2"; - - status_paragraphs.push_back(make_status_feature_pgh("a", "b")); - status_paragraphs.back()->package.version = "2"; - - StatusParagraphs status_db(std::move(status_paragraphs)); - - std::unordered_map map; - auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); - map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); - Dependencies::MapPortFileProvider provider(map); - - auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), - &OutdatedPackage::compare_by_name); - - REQUIRE(pkgs.size() == 1); - REQUIRE(pkgs[0].version_diff.left.to_string() == "2"); - REQUIRE(pkgs[0].version_diff.right.to_string() == "0"); -} - -TEST_CASE ("find outdated packages features 2", "[update]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.version = "2"; - - status_paragraphs.push_back(make_status_feature_pgh("a", "b")); - status_paragraphs.back()->package.version = "0"; - status_paragraphs.back()->state = InstallState::NOT_INSTALLED; - status_paragraphs.back()->want = Want::PURGE; - - StatusParagraphs status_db(std::move(status_paragraphs)); - - std::unordered_map map; - auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "0"}}})); - map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); - Dependencies::MapPortFileProvider provider(map); - - auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), - &OutdatedPackage::compare_by_name); - - REQUIRE(pkgs.size() == 1); - REQUIRE(pkgs[0].version_diff.left.to_string() == "2"); - REQUIRE(pkgs[0].version_diff.right.to_string() == "0"); -} - -TEST_CASE ("find outdated packages none", "[update]") -{ - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); - status_paragraphs.back()->package.version = "2"; - - StatusParagraphs status_db(std::move(status_paragraphs)); - - std::unordered_map map; - auto scf = unwrap(SourceControlFile::parse_control_file(Pgh{{{"Source", "a"}, {"Version", "2"}}})); - map.emplace("a", SourceControlFileLocation{std::move(scf), ""}); - Dependencies::MapPortFileProvider provider(map); - - auto pkgs = SortedVector(Update::find_outdated_packages(provider, status_db), - &OutdatedPackage::compare_by_name); - - REQUIRE(pkgs.size() == 0); -} diff --git a/toolsrc/src/vcpkg-tests/util.cpp b/toolsrc/src/vcpkg-tests/util.cpp deleted file mode 100644 index f14628379..000000000 --- a/toolsrc/src/vcpkg-tests/util.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include - -#include -#include - -#include -#include - -#if defined(_WIN32) -#include -#endif - -namespace vcpkg::Test -{ - std::unique_ptr make_status_pgh(const char* name, - const char* depends, - const char* default_features, - const char* triplet) - { - using Pgh = std::unordered_map; - return std::make_unique(Pgh{{"Package", name}, - {"Version", "1"}, - {"Architecture", triplet}, - {"Multi-Arch", "same"}, - {"Depends", depends}, - {"Default-Features", default_features}, - {"Status", "install ok installed"}}); - } - - std::unique_ptr make_status_feature_pgh(const char* name, - const char* feature, - const char* depends, - const char* triplet) - { - using Pgh = std::unordered_map; - return std::make_unique(Pgh{{"Package", name}, - {"Version", "1"}, - {"Feature", feature}, - {"Architecture", triplet}, - {"Multi-Arch", "same"}, - {"Depends", depends}, - {"Status", "install ok installed"}}); - } - - PackageSpec unsafe_pspec(std::string name, Triplet t) - { - auto m_ret = PackageSpec::from_name_and_triplet(name, t); - REQUIRE(m_ret.has_value()); - return m_ret.value_or_exit(VCPKG_LINE_INFO); - } - - - #if defined(_WIN32) - - static bool system_allows_symlinks() { - HKEY key; - bool allow_symlinks = true; - - const auto status = RegOpenKeyExW( - HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock)", 0, 0, &key); - - if (status == ERROR_FILE_NOT_FOUND) - { - allow_symlinks = false; - std::clog << "Symlinks are not allowed on this system\n"; - } - - if (status == ERROR_SUCCESS) RegCloseKey(key); - - return allow_symlinks; - } - - static fs::path internal_temporary_directory() { - wchar_t* tmp = static_cast(std::calloc(32'767, 2)); - - if (!GetEnvironmentVariableW(L"TEMP", tmp, 32'767)) { - std::cerr << "No temporary directory found.\n"; - std::abort(); - } - - fs::path result = tmp; - std::free(tmp); - - return result / L"vcpkg-test"; - } - - #else - - constexpr static bool system_allows_symlinks() { - return true; - } - static fs::path internal_temporary_directory() { - return "/tmp/vcpkg-test"; - } - - #endif - - const bool SYMLINKS_ALLOWED = system_allows_symlinks(); - const fs::path TEMPORARY_DIRECTORY = internal_temporary_directory(); -} -- cgit v1.2.3 From 2c20a9d98186e029ff443932295d7cdcad96980e Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 22 Jul 2019 11:16:07 -0700 Subject: fix some of the awful mix of macros --- toolsrc/src/vcpkg-test/util.cpp | 67 ++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 24 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/util.cpp b/toolsrc/src/vcpkg-test/util.cpp index 19f8f355e..a80ab36a0 100644 --- a/toolsrc/src/vcpkg-test/util.cpp +++ b/toolsrc/src/vcpkg-test/util.cpp @@ -5,6 +5,9 @@ #include #include +// used to get the implementation specific compiler flags (i.e., __cpp_lib_filesystem) +#include + #include #include @@ -12,16 +15,24 @@ #include #endif -#if defined(_MSC_VER) && _MSC_VER >= 1914 +#define FILESYSTEM_SYMLINK_STD 0 +#define FILESYSTEM_SYMLINK_UNIX 1 +#define FILESYSTEM_SYMLINK_NONE 2 -#define USE_STD_FILESYSTEM +#if defined(__cpp_lib_filesystem) +#define FILESYSTEM_SYMLINK FILESYSTEM_SYMLINK_STD #include // required for filesystem::create_{directory_}symlink #elif !defined(_MSC_VER) +#define FILESYSTEM_SYMLINK FILESYSTEM_SYMLINK_UNIX #include +#else + +#define FILESYSTEM_SYMLINK FILESYSTEM_SYMLINK_NONE + #endif namespace vcpkg::Test @@ -63,15 +74,14 @@ namespace vcpkg::Test return m_ret.value_or_exit(VCPKG_LINE_INFO); } - - - // I am so sorry for this awful mix of macros - - static bool system_allows_symlinks() { + static bool system_allows_symlinks() + { #if defined(_WIN32) - #if !defined(USE_STD_FILESYSTEM) - return false; - #else + if (!__cpp_lib_filesystem) + { + return false; + } + HKEY key; bool allow_symlinks = true; @@ -87,17 +97,18 @@ namespace vcpkg::Test if (status == ERROR_SUCCESS) RegCloseKey(key); return allow_symlinks; - #endif #else return true; #endif } - static fs::path internal_temporary_directory() { + static fs::path internal_temporary_directory() + { #if defined(_WIN32) wchar_t* tmp = static_cast(std::calloc(32'767, 2)); - if (!GetEnvironmentVariableW(L"TEMP", tmp, 32'767)) { + if (!GetEnvironmentVariableW(L"TEMP", tmp, 32'767)) + { std::cerr << "No temporary directory found.\n"; std::abort(); } @@ -114,9 +125,14 @@ namespace vcpkg::Test const bool SYMLINKS_ALLOWED = system_allows_symlinks(); const fs::path TEMPORARY_DIRECTORY = internal_temporary_directory(); - void create_symlink(const fs::path& target, const fs::path& file, std::error_code& ec) { -#if defined(_MSC_VER) - #if defined(USE_STD_FILESYSTEM) +#if FILESYSTEM_SYMLINK == FILSYSTEM_SYMLINK_NONE + constexpr inline char no_filesystem_message[] = + " doesn't exist; on windows, we don't attempt to use the win32 calls to create symlinks"; +#endif + + void create_symlink(const fs::path& target, const fs::path& file, std::error_code& ec) + { +#if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_STD if (SYMLINKS_ALLOWED) { std::filesystem::path targetp = target.native(); @@ -125,20 +141,22 @@ namespace vcpkg::Test std::filesystem::create_symlink(targetp, filep); } else - #endif { vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "Symlinks are not allowed on this system"); } -#else - if(symlink(target.c_str(), file.c_str()) != 0) { +#elif FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_UNIX + if (symlink(target.c_str(), file.c_str()) != 0) + { ec.assign(errno, std::system_category()); } +#else + vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, no_filesystem_message); #endif } - void create_directory_symlink(const fs::path& target, const fs::path& file, std::error_code& ec) { -#if defined(_MSC_VER) - #if defined(USE_STD_FILESYSTEM) + void create_directory_symlink(const fs::path& target, const fs::path& file, std::error_code& ec) + { +#if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_STD if (SYMLINKS_ALLOWED) { std::filesystem::path targetp = target.native(); @@ -147,12 +165,13 @@ namespace vcpkg::Test std::filesystem::create_symlink(targetp, filep); } else - #endif { vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "Symlinks are not allowed on this system"); } -#else +#elif FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_UNIX ::vcpkg::Test::create_symlink(target, file, ec); +#else + vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, no_filesystem_message); #endif } } -- cgit v1.2.3 From 459908ae14458a615bb0a8c278c799cabd34e558 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 23 Jul 2019 10:07:39 -0700 Subject: add external file hashes to the binary paragraph --- toolsrc/src/vcpkg/binaryparagraph.cpp | 34 ++++++- toolsrc/src/vcpkg/build.cpp | 157 ++++++++++++++++++++++----------- toolsrc/src/vcpkg/statusparagraphs.cpp | 48 +++++----- 3 files changed, 159 insertions(+), 80 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index ad7790fe1..2e9415dab 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -23,7 +24,7 @@ namespace vcpkg static const std::string MAINTAINER = "Maintainer"; static const std::string DEPENDS = "Depends"; static const std::string DEFAULTFEATURES = "Default-Features"; - static const std::string TYPE = "Type"; + static const std::string EXTERNALFILES = "External-Files"; } BinaryParagraph::BinaryParagraph() = default; @@ -61,8 +62,23 @@ namespace vcpkg this->default_features = parse_comma_list(parser.optional_field(Fields::DEFAULTFEATURES)); } - this->type = - SourceParagraph::type_from_string(parser.optional_field(Fields::TYPE)); + std::vector external_files_or_hashes = + parse_comma_list(parser.optional_field(Fields::EXTERNALFILES)); + + if (external_files_or_hashes.size() % 2 != 0) + { + Checks::exit_with_message( + VCPKG_LINE_INFO, + "The External-Files field is not composed of key-value pairs for ", + this->spec); + } + + for (int i = 0; i < external_files_or_hashes.size(); i += 2) + { + external_files.emplace( + std::move(external_files_or_hashes[i]), + std::move(external_files_or_hashes[i+1])); + } if (const auto err = parser.error_info(this->spec.to_string())) { @@ -124,6 +140,16 @@ namespace vcpkg if (!pgh.abi.empty()) out_str.append("Abi: ").append(pgh.abi).push_back('\n'); if (!pgh.description.empty()) out_str.append("Description: ").append(pgh.description).push_back('\n'); - out_str.append("Type: ").append(SourceParagraph::string_from_type(pgh.type)).push_back('\n'); + if (!pgh.external_files.empty()) + { + out_str.append("External-Files: "); + out_str.append(Strings::join(",", + Util::fmap( + pgh.external_files, + [](const std::pair& kv) + { + return kv.first + "," + kv.second; + }))).push_back('\n'); + } } } diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 47599bfca..110a571b0 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -261,10 +262,12 @@ namespace vcpkg::Build return BinaryParagraph(source_paragraph, feature_paragraph, triplet); } - static std::unique_ptr create_binary_control_file(const SourceParagraph& source_paragraph, - const Triplet& triplet, - const BuildInfo& build_info, - const std::string& abi_tag) + static std::unique_ptr create_binary_control_file( + const SourceParagraph& source_paragraph, + const Triplet& triplet, + const BuildInfo& build_info, + const PreBuildInfo& pre_build_info, + const std::string& abi_tag) { auto bcf = std::make_unique(); BinaryParagraph bpgh(source_paragraph, triplet, abi_tag); @@ -272,6 +275,14 @@ namespace vcpkg::Build { bpgh.version = *p_ver; } + + for (auto& file_hash : pre_build_info.external_files) + { + bpgh.external_files.emplace( + std::move(file_hash.first), + std::move(file_hash.second)); + } + bcf->core_paragraph = std::move(bpgh); return bcf; } @@ -447,6 +458,41 @@ namespace vcpkg::Build return command; } + static std::vector> get_external_file_hashes( + const VcpkgPaths& paths, + const std::vector& files) + { + static std::map s_hash_cache; + + const auto& fs = paths.get_filesystem(); + + std::vector> hashes; + for (const fs::path& external_file : files) + { + auto it_hash = s_hash_cache.find(external_file); + + if (it_hash != s_hash_cache.end()) + { + hashes.emplace_back(external_file, it_hash->second); + } + else if (fs.is_regular_file(external_file)) + { + auto emp = s_hash_cache.emplace(external_file.u8string(), + Hash::get_file_hash(fs, external_file, "SHA1")); + hashes.emplace_back(external_file, emp.first->second); + } + else + { + Checks::exit_with_message( + VCPKG_LINE_INFO, + external_file.u8string() + + " was listed as an additional file for calculating the abi, but was not found."); + } + } + + return hashes; + } + static std::string get_triplet_abi(const VcpkgPaths& paths, const PreBuildInfo& pre_build_info, const Triplet& triplet) @@ -496,31 +542,6 @@ namespace vcpkg::Build s_hash_cache.emplace(triplet_file_path, hash); } - for (const fs::path& additional_file : pre_build_info.additional_files) - { - it_hash = s_hash_cache.find(additional_file); - - if (it_hash != s_hash_cache.end()) - { - hash += "-"; - hash += it_hash->second; - } - else if (fs.is_regular_file(additional_file)) - { - std::string tmp_hash = Hash::get_file_hash(fs, additional_file, "SHA1"); - hash += "-"; - hash += tmp_hash; - - s_hash_cache.emplace(additional_file, tmp_hash); - } - else - { - Checks::exit_with_message( - VCPKG_LINE_INFO, - additional_file.u8string() + " was listed as an additional file for calculating the abi, but was not found."); - } - } - return hash; } @@ -572,7 +593,13 @@ namespace vcpkg::Build const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info, config.port_dir); - auto bcf = create_binary_control_file(*config.scf.core_paragraph, triplet, build_info, abi_tag); + std::unique_ptr bcf = + create_binary_control_file( + *config.scf.core_paragraph, + triplet, + build_info, + pre_build_info, + abi_tag); if (error_count != 0) { @@ -629,7 +656,9 @@ namespace vcpkg::Build std::vector abi_tag_entries(dependency_abis.begin(), dependency_abis.end()); - abi_tag_entries.emplace_back(AbiEntry{"cmake", paths.get_tool_version(Tools::CMAKE)}); + // Sorted here as the order of dependency_abis is the only + // non-deterministicly ordered set of AbiEntries + Util::sort(abi_tag_entries); // If there is an unusually large number of files in the port then // something suspicious is going on. Rather than hash all of them @@ -637,13 +666,16 @@ namespace vcpkg::Build const int max_port_file_count = 100; // the order of recursive_directory_iterator is undefined so save the names to sort - std::vector port_files; + std::vector> hashes_files; for (auto& port_file : fs::stdfs::recursive_directory_iterator(config.port_dir)) { if (fs::is_regular_file(status(port_file))) { - port_files.push_back(port_file); - if (port_files.size() > max_port_file_count) + hashes_files.emplace_back( + vcpkg::Hash::get_file_hash(fs, port_file, "SHA1"), + port_file.path().filename()); + + if (hashes_files.size() > max_port_file_count) { abi_tag_entries.emplace_back(AbiEntry{"no_hash_max_portfile", ""}); break; @@ -651,25 +683,45 @@ namespace vcpkg::Build } } - if (port_files.size() <= max_port_file_count) + if (hashes_files.size() <= max_port_file_count) { - std::sort(port_files.begin(), port_files.end()); + Util::sort(hashes_files); - int counter = 0; - for (auto& port_file : port_files) + for (auto& hash_file : hashes_files) { - // When vcpkg takes a dependency on C++17 it can use fs::relative, - // which will give a stable ordering and better names in the key entry. - // this is not available in the filesystem TS so instead number the files for the key. - std::string key = Strings::format("file_%03d", counter++); - if (Debug::g_debugging) - { - System::print2("[DEBUG] mapping ", key, " from ", port_file.u8string(), "\n"); - } - abi_tag_entries.emplace_back(AbiEntry{key, vcpkg::Hash::get_file_hash(fs, port_file, "SHA1")}); + // We've already sorted by hash so it's safe to write down the + // filename, which will be consistent across machines. + abi_tag_entries.emplace_back( + AbiEntry{ + std::move(hash_file.second), + std::move(hash_file.first) + }); } } + //Make a copy of the external files and their hashes, and sort by hash + auto additional_file_hashes = pre_build_info.external_files; + std::sort( + additional_file_hashes.begin(), + additional_file_hashes.end(), + [](const std::pair& l, + const std::pair& r) + { + return l.second < r.second || + (l.second == r.second && l.first < r.first); + }); + + for (auto& hash_file : additional_file_hashes) + { + abi_tag_entries.emplace_back( + AbiEntry{ + std::move(hash_file.first), + std::move(hash_file.second) + }); + } + + abi_tag_entries.emplace_back(AbiEntry{"cmake", paths.get_tool_version(Tools::CMAKE)}); + abi_tag_entries.emplace_back(AbiEntry{ "vcpkg_fixup_cmake_targets", vcpkg::Hash::get_file_hash(fs, paths.scripts / "cmake" / "vcpkg_fixup_cmake_targets.cmake", "SHA1")}); @@ -682,8 +734,6 @@ namespace vcpkg::Build if (config.build_package_options.use_head_version == UseHeadVersion::YES) abi_tag_entries.emplace_back(AbiEntry{"head", ""}); - Util::sort(abi_tag_entries); - const std::string full_abi_info = Strings::join("", abi_tag_entries, [](const AbiEntry& p) { return p.key + " " + p.value + "\n"; }); @@ -1114,12 +1164,15 @@ namespace vcpkg::Build case VcpkgTripletVar::ENV_PASSTHROUGH : pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";"); break; - case VcpkgTripletVar::ABI_ADDITIONAL_FILES : - pre_build_info.additional_files = Util::fmap(Strings::split(variable_value, ";"), + case VcpkgTripletVar::EXTERNAL_FILES : + pre_build_info.external_files = + get_external_file_hashes( + paths, + Util::fmap(Strings::split(variable_value, ";"), [](const std::string& path) { return fs::path{path}; - }); + })); break; } } diff --git a/toolsrc/src/vcpkg/statusparagraphs.cpp b/toolsrc/src/vcpkg/statusparagraphs.cpp index f204ed568..4f01b9918 100644 --- a/toolsrc/src/vcpkg/statusparagraphs.cpp +++ b/toolsrc/src/vcpkg/statusparagraphs.cpp @@ -118,30 +118,30 @@ namespace vcpkg return it != end() && (*it)->is_installed(); } - bool vcpkg::StatusParagraphs::needs_rebuild(const PackageSpec& spec) - { - auto it = find(spec); - if (it != end()) - { - for (const std::string& dep : (*it)->package.depends) - { - PackageSpec dep_spec = - PackageSpec::from_name_and_triplet( - dep, - spec.triplet()).value_or_exit(VCPKG_LINE_INFO); - - if (needs_rebuild(dep_spec)) - { - (*it)->state = InstallState::NEEDS_REBUILD; - return true; - } - } - - return (*it)->needs_rebuild(); - } - - return false; - } + //bool vcpkg::StatusParagraphs::needs_rebuild(const PackageSpec& spec) + //{ + // auto it = find(spec); + // if (it != end()) + // { + // for (const std::string& dep : (*it)->package.depends) + // { + // PackageSpec dep_spec = + // PackageSpec::from_name_and_triplet( + // dep, + // spec.triplet()).value_or_exit(VCPKG_LINE_INFO); + + // if (needs_rebuild(dep_spec)) + // { + // (*it)->state = InstallState::NEEDS_REBUILD; + // return true; + // } + // } + + // return (*it)->needs_rebuild(); + // } + + // return false; + //} StatusParagraphs::iterator StatusParagraphs::insert(std::unique_ptr pgh) { -- cgit v1.2.3 From 2f2a45595fa925edeace250b694d70095c42b5fa Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 23 Jul 2019 15:26:13 -0700 Subject: Prompt rebuild if external hash changes --- toolsrc/src/vcpkg/binaryparagraph.cpp | 27 +++++++++++++++++++++++++++ toolsrc/src/vcpkg/build.cpp | 12 ++++++++---- toolsrc/src/vcpkg/dependencies.cpp | 8 ++++++-- 3 files changed, 41 insertions(+), 6 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index 2e9415dab..88d257e7e 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include +#include #include #include #include @@ -27,6 +28,32 @@ namespace vcpkg static const std::string EXTERNALFILES = "External-Files"; } + bool BinaryParagraph::is_consistent() const + { + switch (consistency) + { + case ConsistencyState::UNKNOWN : + for (const auto& file_hash : external_files) + { + const auto& realfs = Files::get_real_filesystem(); + + if (realfs.is_regular_file(file_hash.first) && + Hash::get_file_hash(realfs, file_hash.first, "SHA1") != file_hash.second) + { + consistency = ConsistencyState::INCONSISTENT; + return false; + } + } + + consistency = ConsistencyState::CONSISTENT; + return true; + case ConsistencyState::CONSISTENT : return true; + case ConsistencyState::INCONSISTENT : return false; + } + + Checks::unreachable(VCPKG_LINE_INFO); + } + BinaryParagraph::BinaryParagraph() = default; BinaryParagraph::BinaryParagraph(std::unordered_map fields) diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 110a571b0..1f0dda590 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -475,11 +475,15 @@ namespace vcpkg::Build { hashes.emplace_back(external_file, it_hash->second); } - else if (fs.is_regular_file(external_file)) + else if (Files::get_real_filesystem().is_regular_file(external_file)) { - auto emp = s_hash_cache.emplace(external_file.u8string(), - Hash::get_file_hash(fs, external_file, "SHA1")); - hashes.emplace_back(external_file, emp.first->second); + auto emp = s_hash_cache.emplace( + external_file.u8string(), + Hash::get_file_hash( + Files::get_real_filesystem(), + external_file, "SHA1")); + + hashes.emplace_back(external_file.u8string(), emp.first->second); } else { diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp index b604c9acf..50c310dbb 100644 --- a/toolsrc/src/vcpkg/dependencies.cpp +++ b/toolsrc/src/vcpkg/dependencies.cpp @@ -664,13 +664,17 @@ namespace vcpkg::Dependencies if (auto p_installed = cluster.installed.get()) { - if (p_installed->original_features.find(feature) != p_installed->original_features.end()) + if (p_installed->original_features.find(feature) != p_installed->original_features.end() && + p_installed->ipv.core->package.is_consistent()) { return MarkPlusResult::SUCCESS; } } - // This feature was or will be uninstalled, therefore we need to rebuild + //The feature was not previously installed or the external files of the + //port are no longer consistent with the last installation of this port + //(they've either been modified or removed). Mark the cluster + //(aka the entire port) to be removed before re-adding it. mark_minus(cluster, graph, graph_plan, prevent_default_features); return follow_plus_dependencies(feature, cluster, graph, graph_plan, prevent_default_features); -- cgit v1.2.3 From e1813766047b17cf8d80dc4babed4d1195df3b56 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 23 Jul 2019 15:31:53 -0700 Subject: fix condition --- toolsrc/src/vcpkg/binaryparagraph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index 88d257e7e..7448d456b 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -37,7 +37,7 @@ namespace vcpkg { const auto& realfs = Files::get_real_filesystem(); - if (realfs.is_regular_file(file_hash.first) && + if (!realfs.is_regular_file(file_hash.first) || Hash::get_file_hash(realfs, file_hash.first, "SHA1") != file_hash.second) { consistency = ConsistencyState::INCONSISTENT; -- cgit v1.2.3 From f64d2e9103c8a181ad89cb5d485863a5772105a1 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 23 Jul 2019 15:33:36 -0700 Subject: remove accidental comment --- toolsrc/src/vcpkg/statusparagraphs.cpp | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/statusparagraphs.cpp b/toolsrc/src/vcpkg/statusparagraphs.cpp index 4f01b9918..c642af59b 100644 --- a/toolsrc/src/vcpkg/statusparagraphs.cpp +++ b/toolsrc/src/vcpkg/statusparagraphs.cpp @@ -118,31 +118,6 @@ namespace vcpkg return it != end() && (*it)->is_installed(); } - //bool vcpkg::StatusParagraphs::needs_rebuild(const PackageSpec& spec) - //{ - // auto it = find(spec); - // if (it != end()) - // { - // for (const std::string& dep : (*it)->package.depends) - // { - // PackageSpec dep_spec = - // PackageSpec::from_name_and_triplet( - // dep, - // spec.triplet()).value_or_exit(VCPKG_LINE_INFO); - - // if (needs_rebuild(dep_spec)) - // { - // (*it)->state = InstallState::NEEDS_REBUILD; - // return true; - // } - // } - - // return (*it)->needs_rebuild(); - // } - - // return false; - //} - StatusParagraphs::iterator StatusParagraphs::insert(std::unique_ptr pgh) { Checks::check_exit(VCPKG_LINE_INFO, pgh != nullptr, "Inserted null paragraph"); -- cgit v1.2.3 From 81909e47d1f1563926e78d2e0f0764a3dc1bef03 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 23 Jul 2019 15:38:09 -0700 Subject: Remove types from this PR --- toolsrc/src/vcpkg/binaryparagraph.cpp | 4 ++-- toolsrc/src/vcpkg/sourceparagraph.cpp | 30 ------------------------------ 2 files changed, 2 insertions(+), 32 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index 7448d456b..9b1a8e201 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -119,14 +119,14 @@ namespace vcpkg } BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const Triplet& triplet, const std::string& abi_tag) - : version(spgh.version), description(spgh.description), maintainer(spgh.maintainer), abi(abi_tag), type(spgh.type) + : version(spgh.version), description(spgh.description), maintainer(spgh.maintainer), abi(abi_tag) { this->spec = PackageSpec::from_name_and_triplet(spgh.name, triplet).value_or_exit(VCPKG_LINE_INFO); this->depends = filter_dependencies(spgh.depends, triplet); } BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const FeatureParagraph& fpgh, const Triplet& triplet) - : version(), description(fpgh.description), maintainer(), feature(fpgh.name), type(spgh.type) + : version(), description(fpgh.description), maintainer(), feature(fpgh.name) { this->spec = PackageSpec::from_name_and_triplet(spgh.name, triplet).value_or_exit(VCPKG_LINE_INFO); this->depends = filter_dependencies(fpgh.depends, triplet); diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 6af93a99b..5542ef923 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -100,35 +100,6 @@ namespace vcpkg } } - SourceParagraph::TYPE SourceParagraph::type_from_string(const std::string& in) - { - if (Strings::equals(in, "port") || Strings::equals(in, "")) - { - return SourceParagraph::PORT; - } - - if (Strings::equals(in, "sys-tool")) - { - return SourceParagraph::SYS_TOOL; - } - - System::print2( - in, " is not a valid control file type. Valid types are:", - "\n port\n sys-tool"); - - Checks::exit_fail(VCPKG_LINE_INFO); - } - - std::string SourceParagraph::string_from_type(const SourceParagraph::TYPE& in) - { - switch (in) - { - case SourceParagraph::PORT : return "port"; - case SourceParagraph::SYS_TOOL : return "sys-tool"; - default : Checks::exit_with_message(VCPKG_LINE_INFO, "Invalid CONTROL_TYPE value."); - } - } - static ParseExpected parse_source_paragraph(RawParagraph&& fields) { ParagraphParser parser(std::move(fields)); @@ -145,7 +116,6 @@ namespace vcpkg parse_comma_list(parser.optional_field(SourceParagraphFields::BUILD_DEPENDS))); spgh->supports = parse_comma_list(parser.optional_field(SourceParagraphFields::SUPPORTS)); spgh->default_features = parse_comma_list(parser.optional_field(SourceParagraphFields::DEFAULTFEATURES)); - spgh->type = SourceParagraph::type_from_string(parser.optional_field(SourceParagraphFields::TYPE)); auto err = parser.error_info(spgh->name); if (err) -- cgit v1.2.3 From 45cd8cda5a8339ec91693c720dd7df5b496b8856 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 23 Jul 2019 15:49:48 -0700 Subject: move the pre_build_info --- toolsrc/src/vcpkg/build.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index f810d537a..70c664b75 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -603,7 +603,7 @@ namespace vcpkg::Build *config.scf.core_paragraph, triplet, build_info, - pre_build_info, + std::move(pre_build_info), abi_tag); if (error_count != 0) -- cgit v1.2.3 From d68b9a08b1edfe80b77fd65afd21faffc81b162b Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Tue, 23 Jul 2019 16:28:00 -0700 Subject: only use filename --- toolsrc/src/vcpkg/build.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 70c664b75..9d5b490e3 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -281,7 +281,7 @@ namespace vcpkg::Build for (auto& file_hash : pre_build_info.external_files) { bpgh.external_files.emplace( - std::move(file_hash.first), + file_hash.first.u8string(), std::move(file_hash.second)); } @@ -459,7 +459,7 @@ namespace vcpkg::Build return command; } - static std::vector> get_external_file_hashes( + static std::vector> get_external_file_hashes( const VcpkgPaths& paths, const std::vector& files) { @@ -467,7 +467,7 @@ namespace vcpkg::Build const auto& fs = paths.get_filesystem(); - std::vector> hashes; + std::vector> hashes; for (const fs::path& external_file : files) { auto it_hash = s_hash_cache.find(external_file); @@ -705,7 +705,16 @@ namespace vcpkg::Build } //Make a copy of the external files and their hashes, and sort by hash - auto additional_file_hashes = pre_build_info.external_files; + std::vector> additional_file_hashes + = Util::fmap(pre_build_info.external_files, + [](const std::pair& file_hash) + { + return std::pair{ + file_hash.first.filename().u8string(), + file_hash.second + }; + }); + std::sort( additional_file_hashes.begin(), additional_file_hashes.end(), -- cgit v1.2.3 From 0c7669d009548616aeb754276deea974ba7a53c3 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Wed, 24 Jul 2019 14:24:49 -0700 Subject: store fs::path instead of std::string --- toolsrc/src/vcpkg/binaryparagraph.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index 9b1a8e201..f571e0e8e 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -100,7 +100,9 @@ namespace vcpkg this->spec); } - for (int i = 0; i < external_files_or_hashes.size(); i += 2) + for (decltype(external_files_or_hashes)::size_type i = 0; + i < external_files_or_hashes.size(); + i += 2) { external_files.emplace( std::move(external_files_or_hashes[i]), -- cgit v1.2.3 From be59ecce61a14ba9ca0f65f6eeb7db83782bac22 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Wed, 24 Jul 2019 14:43:44 -0700 Subject: Use correct types --- toolsrc/src/vcpkg/build.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index a5383b2a8..ff3025077 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -711,27 +711,19 @@ namespace vcpkg::Build [](const std::pair& file_hash) { return std::pair{ - file_hash.first.filename().u8string(), - file_hash.second + file_hash.second, + file_hash.first.filename().u8string() }; }); - std::sort( - additional_file_hashes.begin(), - additional_file_hashes.end(), - [](const std::pair& l, - const std::pair& r) - { - return l.second < r.second || - (l.second == r.second && l.first < r.first); - }); + std::sort(additional_file_hashes.begin(), additional_file_hashes.end()); for (auto& hash_file : additional_file_hashes) { abi_tag_entries.emplace_back( AbiEntry{ - std::move(hash_file.first), - std::move(hash_file.second) + std::move(hash_file.second), + std::move(hash_file.first) }); } -- cgit v1.2.3 From 67a749b9892b1c68609dd41dd014dd8de2cdbb9b Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Wed, 24 Jul 2019 14:46:55 -0700 Subject: turn path into string --- toolsrc/src/vcpkg/build.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index ff3025077..80ac3ffe6 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -679,7 +679,7 @@ namespace vcpkg::Build { hashes_files.emplace_back( vcpkg::Hash::get_file_hash(fs, port_file, "SHA1"), - port_file.path().filename()); + port_file.path().filename().u8string()); if (hashes_files.size() > max_port_file_count) { -- cgit v1.2.3 From f81aa47176dd805ccceea0fceb8c4e2158e5c554 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Wed, 24 Jul 2019 14:53:50 -0700 Subject: convert path to string --- toolsrc/src/vcpkg/binaryparagraph.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index f571e0e8e..9be2310c6 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -175,9 +175,9 @@ namespace vcpkg out_str.append(Strings::join(",", Util::fmap( pgh.external_files, - [](const std::pair& kv) + [](const std::pair& kv) { - return kv.first + "," + kv.second; + return kv.first.u8string() + "," + kv.second; }))).push_back('\n'); } } -- cgit v1.2.3 From 9da7c5c99ee42e382895dbd0dafdd29beaa61075 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Thu, 25 Jul 2019 09:38:05 -0700 Subject: Make comment better --- toolsrc/src/vcpkg/build.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 80ac3ffe6..69a313c1a 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -705,7 +705,8 @@ namespace vcpkg::Build } } - //Make a copy of the external files and their hashes, and sort by hash + //Make a copy of the external file names and their hashes, and sort by + //hash. std::vector> additional_file_hashes = Util::fmap(pre_build_info.external_files, [](const std::pair& file_hash) -- cgit v1.2.3 From f990dfaa5ba82155f95b75021453c075816fd4be Mon Sep 17 00:00:00 2001 From: nicole mazzuca Date: Fri, 26 Jul 2019 16:32:33 -0700 Subject: [vcpkg] Fix RealFilesystem::remove_all (#7430) * fix remove_all we were attempting to remove READONLY files before this, and so set them to non-READONLY * fix linux/macos support * whee fix vs2015 --- toolsrc/src/vcpkg-test/files.cpp | 4 +++- toolsrc/src/vcpkg/base/files.cpp | 51 ++++++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 11 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/files.cpp b/toolsrc/src/vcpkg-test/files.cpp index 9e14cec0c..ff0176a93 100644 --- a/toolsrc/src/vcpkg-test/files.cpp +++ b/toolsrc/src/vcpkg-test/files.cpp @@ -115,7 +115,9 @@ TEST_CASE ("remove all", "[files]") fs::path fp; fs.remove_all(temp_dir, ec, fp); - REQUIRE_FALSE(ec); + if (ec) { + FAIL("remove_all failure on file: " << fp); + } REQUIRE_FALSE(fs.exists(temp_dir)); } diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 6c6945e44..4a5d3caf1 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -28,16 +28,9 @@ namespace fs::detail #if defined(_WIN32) static_cast(ec); - /* - do not find the permissions of the file -- it's unnecessary for the - things that vcpkg does. - if one were to add support for this in the future, one should look - into GetFileSecurityW - */ - perms permissions = perms::unknown; - WIN32_FILE_ATTRIBUTE_DATA file_attributes; file_type ft = file_type::unknown; + perms permissions = perms::unknown; if (!GetFileAttributesExW(p.c_str(), GetFileExInfoStandard, &file_attributes)) { ft = file_type::not_found; @@ -64,7 +57,7 @@ namespace fs::detail #endif } - file_status symlink_status_t::operator()(const path& p, vcpkg::LineInfo li) const noexcept + file_status symlink_status_t::operator()(vcpkg::LineInfo li, const path& p) const noexcept { std::error_code ec; auto result = symlink_status(p, ec); @@ -78,6 +71,41 @@ namespace vcpkg::Files { static const std::regex FILESYSTEM_INVALID_CHARACTERS_REGEX = std::regex(R"([\/:*?"<>|])"); + namespace { + // does _not_ follow symlinks + void set_writeable(const fs::path& path, std::error_code& ec) noexcept { +#if defined(_WIN32) + auto const file_name = path.c_str(); + WIN32_FILE_ATTRIBUTE_DATA attributes; + if (!GetFileAttributesExW(file_name, GetFileExInfoStandard, &attributes)) { + ec.assign(GetLastError(), std::system_category()); + return; + } + + auto dw_attributes = attributes.dwFileAttributes; + dw_attributes &= ~FILE_ATTRIBUTE_READONLY; + if (!SetFileAttributesW(file_name, dw_attributes)) { + ec.assign(GetLastError(), std::system_category()); + } +#else + struct stat s; + if (lstat(path.c_str(), &s)) { + ec.assign(errno, std::system_category()); + return; + } + + auto mode = s.st_mode; + // if the file is a symlink, perms don't matter + if (!(mode & S_IFLNK)) { + mode |= S_IWUSR; + if (chmod(path.c_str(), mode)) { + ec.assign(errno, std::system_category()); + } + } +#endif + } + } + std::string Filesystem::read_contents(const fs::path& path, LineInfo linfo) const { auto maybe_contents = this->read_contents(path); @@ -384,6 +412,9 @@ namespace vcpkg::Files } } + set_writeable(current_path, ec); + if (check_ec(ec, info, queue, current_path)) return; + if (fs::stdfs::remove(current_path, ec)) { info.files_deleted.fetch_add(1, std::memory_order_relaxed); @@ -447,7 +478,7 @@ namespace vcpkg::Files return remove::tld{path, index, files_deleted, ec_mutex, ec, failure_point}; }; - remove::queue queue{4, VCPKG_LINE_INFO, tld_gen}; + remove::queue queue{VCPKG_LINE_INFO, 4, tld_gen}; // note: we don't actually start the queue running until the // `join()`. This allows us to rename all the top-level files in -- cgit v1.2.3 From ae6ca87221cf71fc217bff65f0df0808da17a047 Mon Sep 17 00:00:00 2001 From: lukka <681992+lukka@users.noreply.github.com> Date: Thu, 1 Aug 2019 17:48:22 -0700 Subject: - remove trailing \r when parsing response file that might have Windows line endings; (#7491) - when an option is not recognized (perhaps because it has trailing whitespace characters), print it out enclosed with single quote to delimit and highlight potenatial not printable characters. --- toolsrc/src/vcpkg/base/files.cpp | 4 ++++ toolsrc/src/vcpkg/vcpkgcmdarguments.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 4a5d3caf1..4446042f1 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -202,6 +202,10 @@ namespace vcpkg::Files std::string line; while (std::getline(file_stream, line)) { + // Remove the trailing \r to accomodate Windows line endings. + if ((!line.empty()) && (line.back() == '\r')) + line.pop_back(); + output.push_back(line); } file_stream.close(); diff --git a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp index 7a28fb571..452c7ca19 100644 --- a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp +++ b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp @@ -389,7 +389,7 @@ namespace vcpkg System::printf(System::Color::error, "Unknown option(s) for command '%s':\n", this->command); for (auto&& option : options_copy) { - System::print2(" ", option.first, "\n"); + System::print2(" '", option.first, "'\n"); } System::print2("\n"); failed = true; -- cgit v1.2.3 From 165907550c8f6ce7506beef591f55cd3f8458d78 Mon Sep 17 00:00:00 2001 From: nicole mazzuca Date: Fri, 2 Aug 2019 09:52:39 -0700 Subject: Update tests, and add documentation! (#7506) This PR does the following: * fix tests -- now, they're always built in the CMake scripts, and they work on VS2015 *add a new flag, BUILD_TESTING, which allows one to turn off testing builds * Add documentation for running tests --- toolsrc/src/vcpkg-test/util.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/util.cpp b/toolsrc/src/vcpkg-test/util.cpp index a80ab36a0..5359b0fad 100644 --- a/toolsrc/src/vcpkg-test/util.cpp +++ b/toolsrc/src/vcpkg-test/util.cpp @@ -76,12 +76,13 @@ namespace vcpkg::Test static bool system_allows_symlinks() { -#if defined(_WIN32) - if (!__cpp_lib_filesystem) - { - return false; - } - +#if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_NONE + return false; +#elif FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_UNIX + return true; +#elif !defined(_WIN32) // FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_STD + return true; +#else HKEY key; bool allow_symlinks = true; @@ -97,8 +98,6 @@ namespace vcpkg::Test if (status == ERROR_SUCCESS) RegCloseKey(key); return allow_symlinks; -#else - return true; #endif } @@ -125,8 +124,8 @@ namespace vcpkg::Test const bool SYMLINKS_ALLOWED = system_allows_symlinks(); const fs::path TEMPORARY_DIRECTORY = internal_temporary_directory(); -#if FILESYSTEM_SYMLINK == FILSYSTEM_SYMLINK_NONE - constexpr inline char no_filesystem_message[] = +#if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_NONE + constexpr char no_filesystem_message[] = " doesn't exist; on windows, we don't attempt to use the win32 calls to create symlinks"; #endif -- cgit v1.2.3 From 22e0b9f376a66e6717f820e6c382c4112191ef9b Mon Sep 17 00:00:00 2001 From: Phil Christensen Date: Fri, 2 Aug 2019 21:37:49 -0700 Subject: improve logic expression evaluation (#7508) * better logic expression evaluation Improve the logic expression evaluation currently used when filtering dependencies. Biggest improvements: + Allow '|' operator + Support nested '()' + Allow whitespace + Useful error message for malformed expressions Also changed names of types to RawParagraph when that is what the original author was using. --- toolsrc/src/vcpkg/binaryparagraph.cpp | 2 +- toolsrc/src/vcpkg/build.cpp | 4 +- toolsrc/src/vcpkg/commands.cache.cpp | 2 +- toolsrc/src/vcpkg/commands.import.cpp | 2 +- toolsrc/src/vcpkg/logicexpression.cpp | 285 ++++++++++++++++++++++++++++++++++ toolsrc/src/vcpkg/paragraphs.cpp | 42 ++--- toolsrc/src/vcpkg/parse.cpp | 2 +- toolsrc/src/vcpkg/sourceparagraph.cpp | 37 ++--- toolsrc/src/vcpkg/statusparagraph.cpp | 2 +- toolsrc/src/vcpkg/userconfig.cpp | 2 +- 10 files changed, 326 insertions(+), 54 deletions(-) create mode 100644 toolsrc/src/vcpkg/logicexpression.cpp (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index 4b80debab..8b1886098 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -27,7 +27,7 @@ namespace vcpkg BinaryParagraph::BinaryParagraph() = default; - BinaryParagraph::BinaryParagraph(std::unordered_map fields) + BinaryParagraph::BinaryParagraph(Parse::RawParagraph fields) { using namespace vcpkg::Parse; diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 235adb819..54a691454 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -938,7 +938,7 @@ namespace vcpkg::Build Commands::Version::version()); } - static BuildInfo inner_create_buildinfo(std::unordered_map pgh) + static BuildInfo inner_create_buildinfo(Parse::RawParagraph pgh) { Parse::ParagraphParser parser(std::move(pgh)); @@ -995,7 +995,7 @@ namespace vcpkg::Build BuildInfo read_build_info(const Files::Filesystem& fs, const fs::path& filepath) { - const Expected> pghs = + const Expected pghs = Paragraphs::get_single_paragraph(fs, filepath); Checks::check_exit(VCPKG_LINE_INFO, pghs.get() != nullptr, "Invalid BUILD_INFO file for package"); return inner_create_buildinfo(*pghs.get()); diff --git a/toolsrc/src/vcpkg/commands.cache.cpp b/toolsrc/src/vcpkg/commands.cache.cpp index c321de3b5..4c49db004 100644 --- a/toolsrc/src/vcpkg/commands.cache.cpp +++ b/toolsrc/src/vcpkg/commands.cache.cpp @@ -14,7 +14,7 @@ namespace vcpkg::Commands::Cache std::vector output; for (auto&& path : paths.get_filesystem().get_files_non_recursive(paths.packages)) { - const Expected> pghs = + const Expected pghs = Paragraphs::get_single_paragraph(paths.get_filesystem(), path / "CONTROL"); if (const auto p = pghs.get()) { diff --git a/toolsrc/src/vcpkg/commands.import.cpp b/toolsrc/src/vcpkg/commands.import.cpp index 40f5a434c..c18d788c5 100644 --- a/toolsrc/src/vcpkg/commands.import.cpp +++ b/toolsrc/src/vcpkg/commands.import.cpp @@ -108,7 +108,7 @@ namespace vcpkg::Commands::Import const fs::path include_directory(args.command_arguments[1]); const fs::path project_directory(args.command_arguments[2]); - const Expected> pghs = + const Expected pghs = Paragraphs::get_single_paragraph(paths.get_filesystem(), control_file_path); Checks::check_exit(VCPKG_LINE_INFO, pghs.get() != nullptr, diff --git a/toolsrc/src/vcpkg/logicexpression.cpp b/toolsrc/src/vcpkg/logicexpression.cpp new file mode 100644 index 000000000..fc8c4ef56 --- /dev/null +++ b/toolsrc/src/vcpkg/logicexpression.cpp @@ -0,0 +1,285 @@ + +#include "pch.h" + +#include +#include +#include + +#include +#include + + +namespace vcpkg +{ + struct ParseError + { + ParseError(int column, std::string line, std::string message) + :column(column), line(line), message(message) + {} + + const int column; + const std::string line; + const std::string message; + + void print_error() const + { + System::print2(System::Color::error, + "Error: ", message, "\n" + " on expression: \"", line, "\"\n", + " ", std::string(column, ' '), "^\n"); + Checks::exit_fail(VCPKG_LINE_INFO); + } + }; + + // logic expression supports the following : + // primary-expression: + // ( logic-expression ) + // identifier + // identifier: + // alpha-numeric string of characters + // logic-expression: <- this is the entry point + // not-expression + // not-expression | logic-expression + // not-expression & logic-expression + // not-expression: + // ! primary-expression + // primary-expression + // + // | and & have equal precidence and cannot be used together at the same nesting level + // for example a|b&c is not allowd but (a|b)&c and a|(b&c) are allowed. + class ExpressionParser + { + public: + ExpressionParser(const std::string& str, const std::string& evaluation_context) + : raw_text(str), evaluation_context(evaluation_context) + { + go_to_begin(); + + final_result = logic_expression(); + + if (current_iter != raw_text.end()) + { + add_error("Invalid logic expression"); + } + + if (err) + { + err->print_error(); + final_result = false; + } + } + + bool get_result() const + { + return final_result; + } + + bool has_error() const + { + return err == nullptr; + } + + private: + + bool final_result; + + std::string::const_iterator current_iter; + const std::string& raw_text; + char current_char; + + const std::string& evaluation_context; + + std::unique_ptr err; + + void add_error(std::string message, int column = -1) + { + // avoid castcading errors by only saving the first + if (!err) + { + if (column < 0) + { + column = current_column(); + } + err = std::make_unique(column, raw_text, message); + } + + // Avoid error loops by skipping to the end + skip_to_end(); + } + + int current_column() const + { + return static_cast(current_iter - raw_text.begin()); + } + + void go_to_begin() + { + current_iter = raw_text.begin(); + current_char = (current_iter != raw_text.end() ? *current_iter : current_char); + + if (current_char == ' ' || current_char == '\t') + { + next_skip_whitespace(); + } + } + void skip_to_end() + { + current_iter = raw_text.end(); + current_char = '\0'; + } + char current() const + { + return current_char; + } + char next() + { + if (current_char != '\0') + { + current_iter++; + current_char = (current_iter != raw_text.end() ? *current_iter : '\0'); + } + return current(); + } + void skip_whitespace() + { + while (current_char == ' ' || current_char == '\t') + { + current_char = next(); + } + } + char next_skip_whitespace() + { + next(); + skip_whitespace(); + return current_char; + } + + static bool is_alphanum(char ch) + { + return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || (ch == '-'); + } + + bool evaluate_identifier(const std::string name) const + { + return evaluation_context.find(name) != std::string::npos; + } + + // identifier: + // alpha-numeric string of characters + bool identifier_expression() + { + auto curr = current(); + std::string name; + + for (curr = current(); is_alphanum(curr); curr = next()) + { + name += curr; + } + + if (name.empty()) + { + add_error("Invalid logic expression, unexpected character"); + return false; + } + + bool result = evaluate_identifier(name); + skip_whitespace(); + return result; + } + + // not-expression: + // ! primary-expression + // primary-expression + bool not_expression() + { + if (current() == '!') + { + next_skip_whitespace(); + return !primary_expression(); + } + + return primary_expression(); + } + + + template + bool logic_expression_helper(bool seed) + { + do + { + // Support chains of the operator to avoid breaking backwards compatability + while (next() == oper) {}; + seed = operation(not_expression(), seed); + + } while (current() == oper); + + if (current() == other) + { + add_error("Mixing & and | is not allowed, Use () to specify order of operations."); + } + + skip_whitespace(); + return seed; + } + static bool and_helper(bool left, bool right) + { + return left && right; + } + static bool or_helper(bool left, bool right) + { + return left || right; + } + + // logic-expression: <- entry point + // not-expression + // not-expression | logic-expression + // not-expression & logic-expression + bool logic_expression() + { + auto result = not_expression(); + + switch (current()) + { + case '|': + { + return logic_expression_helper< '|', '&', or_helper > (result); + } + case '&': + { + return logic_expression_helper< '&', '|', and_helper > (result); + } + default: + return result; + } + } + + // primary-expression: + // ( logic-expression ) + // identifier + bool primary_expression() + { + if (current() == '(') + { + next_skip_whitespace(); + bool result = logic_expression(); + if (current() != ')') + { + add_error("Error: missing closing )"); + return result; + } + next_skip_whitespace(); + return result; + } + + return identifier_expression(); + } + }; + + + bool evaluate_expression(const std::string& expression, const std::string& evaluation_context) + { + ExpressionParser parser(expression, evaluation_context); + + return parser.get_result(); + } +} diff --git a/toolsrc/src/vcpkg/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp index 21ef2c4d9..b08a6b805 100644 --- a/toolsrc/src/vcpkg/paragraphs.cpp +++ b/toolsrc/src/vcpkg/paragraphs.cpp @@ -116,7 +116,7 @@ namespace vcpkg::Paragraphs skip_spaces(ch); } - void get_paragraph(char& ch, std::unordered_map& fields) + void get_paragraph(char& ch, RawParagraph& fields) { fields.clear(); std::string fieldname; @@ -141,9 +141,9 @@ namespace vcpkg::Paragraphs } public: - std::vector> get_paragraphs() + std::vector get_paragraphs() { - std::vector> paragraphs; + std::vector paragraphs; char ch; peek(ch); @@ -164,7 +164,20 @@ namespace vcpkg::Paragraphs } }; - Expected> get_single_paragraph(const Files::Filesystem& fs, + Expected parse_single_paragraph(const std::string& str) + { + const std::vector p = + Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs(); + + if (p.size() == 1) + { + return p.at(0); + } + + return std::error_code(ParagraphParseResult::EXPECTED_ONE_PARAGRAPH); + } + + Expected get_single_paragraph(const Files::Filesystem& fs, const fs::path& control_path) { const Expected contents = fs.read_contents(control_path); @@ -176,7 +189,7 @@ namespace vcpkg::Paragraphs return contents.error(); } - Expected>> get_paragraphs(const Files::Filesystem& fs, + Expected> get_paragraphs(const Files::Filesystem& fs, const fs::path& control_path) { const Expected contents = fs.read_contents(control_path); @@ -188,27 +201,14 @@ namespace vcpkg::Paragraphs return contents.error(); } - Expected> parse_single_paragraph(const std::string& str) - { - const std::vector> p = - Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs(); - - if (p.size() == 1) - { - return p.at(0); - } - - return std::error_code(ParagraphParseResult::EXPECTED_ONE_PARAGRAPH); - } - - Expected>> parse_paragraphs(const std::string& str) + Expected> parse_paragraphs(const std::string& str) { return Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs(); } ParseExpected try_load_port(const Files::Filesystem& fs, const fs::path& path) { - Expected>> pghs = get_paragraphs(fs, path / "CONTROL"); + Expected> pghs = get_paragraphs(fs, path / "CONTROL"); if (auto vector_pghs = pghs.get()) { return SourceControlFile::parse_control_file(std::move(*vector_pghs)); @@ -221,7 +221,7 @@ namespace vcpkg::Paragraphs Expected try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec) { - Expected>> pghs = + Expected> pghs = get_paragraphs(paths.get_filesystem(), paths.package_dir(spec) / "CONTROL"); if (auto p = pghs.get()) diff --git a/toolsrc/src/vcpkg/parse.cpp b/toolsrc/src/vcpkg/parse.cpp index d50296cf8..68fac0b0f 100644 --- a/toolsrc/src/vcpkg/parse.cpp +++ b/toolsrc/src/vcpkg/parse.cpp @@ -6,7 +6,7 @@ namespace vcpkg::Parse { - static Optional remove_field(std::unordered_map* fields, + static Optional remove_field(RawParagraph* fields, const std::string& fieldname) { auto it = fields->find(fieldname); diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 1a52bd05f..a5054eb3b 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -142,7 +143,7 @@ namespace vcpkg } ParseExpected SourceControlFile::parse_control_file( - std::vector>&& control_paragraphs) + std::vector&& control_paragraphs) { if (control_paragraphs.size() == 0) { @@ -222,18 +223,11 @@ namespace vcpkg std::vector ret; for (auto&& dep : deps) { - auto qualifiers = Strings::split(dep.qualifier, "&"); - if (std::all_of(qualifiers.begin(), qualifiers.end(), [&](const std::string& qualifier) { - if (qualifier.empty()) return true; - if (qualifier[0] == '!') - { - return t.canonical_name().find(qualifier.substr(1)) == std::string::npos; - } - return t.canonical_name().find(qualifier) != std::string::npos; - })) - { - ret.emplace_back(dep.name()); - } + const auto & qualifier = dep.qualifier; + if (qualifier.empty() || evaluate_expression(qualifier, t.canonical_name())) + { + ret.emplace_back(dep.name()); + } } return ret; } @@ -244,18 +238,11 @@ namespace vcpkg std::vector ret; for (auto&& dep : deps) { - auto qualifiers = Strings::split(dep.qualifier, "&"); - if (std::all_of(qualifiers.begin(), qualifiers.end(), [&](const std::string& qualifier) { - if (qualifier.empty()) return true; - if (qualifier[0] == '!') - { - return t.canonical_name().find(qualifier.substr(1)) == std::string::npos; - } - return t.canonical_name().find(qualifier) != std::string::npos; - })) - { - ret.emplace_back(dep.depend); - } + const auto & qualifier = dep.qualifier; + if (qualifier.empty() || evaluate_expression(qualifier, t.canonical_name())) + { + ret.emplace_back(dep.depend); + } } return ret; } diff --git a/toolsrc/src/vcpkg/statusparagraph.cpp b/toolsrc/src/vcpkg/statusparagraph.cpp index 86946a31a..f7e00f21c 100644 --- a/toolsrc/src/vcpkg/statusparagraph.cpp +++ b/toolsrc/src/vcpkg/statusparagraph.cpp @@ -24,7 +24,7 @@ namespace vcpkg .push_back('\n'); } - StatusParagraph::StatusParagraph(std::unordered_map&& fields) + StatusParagraph::StatusParagraph(Parse::RawParagraph&& fields) : want(Want::ERROR_STATE), state(InstallState::ERROR_STATE) { auto status_it = fields.find(BinaryParagraphRequiredField::STATUS); diff --git a/toolsrc/src/vcpkg/userconfig.cpp b/toolsrc/src/vcpkg/userconfig.cpp index a7c4e2765..3551ae81e 100644 --- a/toolsrc/src/vcpkg/userconfig.cpp +++ b/toolsrc/src/vcpkg/userconfig.cpp @@ -51,7 +51,7 @@ namespace vcpkg { const auto& pghs = *p_pghs; - std::unordered_map keys; + Parse::RawParagraph keys; if (pghs.size() > 0) keys = pghs[0]; for (size_t x = 1; x < pghs.size(); ++x) -- cgit v1.2.3 From e79f0dc5328f28b2b3942e2cd0e9b0c1accca4a1 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 2 Aug 2019 16:49:45 -0700 Subject: [vcpkg] Make Filesystem::remove_all faster #7570 I added benchmarks to measure how fast the parallel remove_all code was -- it turns out, about 3x slower than stdfs::remove_all. Since this was the case, I removed all of the parallelism and rewrote it serially, and ended up about 30% faster than stdfs::remove_all (in addition to supporting symlinks). In addition, I did the following three orthogonal changes: - simplified the work queue, basing it on Billy O'Neal's idea - Fix warnings on older versions of compilers in tests, by splitting the pragmas out of pch.h. - Ran clang-format on some files In fixing up remove_all, the following changes were made: - On Windows, regular symlinks and directory symlinks are distinct; as an example, to remove directory symlinks (and junctions, for that matter), one must use RemoveDirectory. Only on Windows, I added new `file_type` and `file_status` types, with `file_type` including a new `directory_symlink` enumerator, and `file_status` being exactly the same as the old one except using the new `file_type`. On Unix, I didn't make that change since they don't make a distinction. - I added new `symlink_status` and `status` functions which use the new `file_status` on Windows. - I made `Filesystem::exists` call `fs::exists(status(p))`, as opposed to the old version which called `stdfs::exists` directly. - Added benchmarks to `vcpkg-test/files.cpp`. They test the performance of `remove_all` on small directories (~20 files), with symlinks and without, and on large directories (~2000 files), with symlinks and without. --- toolsrc/src/vcpkg-test/files.cpp | 194 +++++++++++++++---- toolsrc/src/vcpkg-test/util.cpp | 26 +-- toolsrc/src/vcpkg.cpp | 14 +- toolsrc/src/vcpkg/base/files.cpp | 305 +++++++++++++++++------------- toolsrc/src/vcpkg/build.cpp | 127 ++++++------- toolsrc/src/vcpkg/commands.ci.cpp | 18 +- toolsrc/src/vcpkg/commands.dependinfo.cpp | 17 +- toolsrc/src/vcpkg/commands.search.cpp | 8 +- toolsrc/src/vcpkg/dependencies.cpp | 80 ++++---- toolsrc/src/vcpkg/install.cpp | 6 +- toolsrc/src/vcpkg/logicexpression.cpp | 91 ++++----- toolsrc/src/vcpkg/paragraphs.cpp | 9 +- toolsrc/src/vcpkg/parse.cpp | 3 +- toolsrc/src/vcpkg/remove.cpp | 4 +- toolsrc/src/vcpkg/sourceparagraph.cpp | 25 ++- toolsrc/src/vcpkg/userconfig.cpp | 2 +- toolsrc/src/vcpkg/vcpkgcmdarguments.cpp | 33 ++-- toolsrc/src/vcpkg/vcpkgpaths.cpp | 39 ++-- 18 files changed, 553 insertions(+), 448 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/files.cpp b/toolsrc/src/vcpkg-test/files.cpp index ff0176a93..a2faf455c 100644 --- a/toolsrc/src/vcpkg-test/files.cpp +++ b/toolsrc/src/vcpkg-test/files.cpp @@ -9,29 +9,63 @@ #include -using vcpkg::Test::SYMLINKS_ALLOWED; -using vcpkg::Test::TEMPORARY_DIRECTORY; +using vcpkg::Test::AllowSymlinks; +using vcpkg::Test::base_temporary_directory; +using vcpkg::Test::can_create_symlinks; + +#define CHECK_EC_ON_FILE(file, ec) \ + do \ + { \ + if (ec) \ + { \ + FAIL(file << ": " << ec.message()); \ + } \ + } while (0) namespace { - using uid = std::uniform_int_distribution; + using uid_t = std::uniform_int_distribution; + using urbg_t = std::mt19937_64; - std::mt19937_64 get_urbg(std::uint64_t index) + urbg_t get_urbg(std::uint64_t index) { // smallest prime > 2**63 - 1 - return std::mt19937_64{index + 9223372036854775837ULL}; + return urbg_t{index + 9223372036854775837ULL}; } - std::string get_random_filename(std::mt19937_64& urbg) { return vcpkg::Strings::b32_encode(uid{}(urbg)); } + std::string get_random_filename(urbg_t& urbg) { return vcpkg::Strings::b32_encode(uid_t{}(urbg)); } - void create_directory_tree(std::mt19937_64& urbg, + struct MaxDepth + { + std::uint64_t i; + explicit MaxDepth(std::uint64_t i) : i(i) {} + operator uint64_t() const { return i; } + }; + + struct Width + { + std::uint64_t i; + explicit Width(std::uint64_t i) : i(i) {} + operator uint64_t() const { return i; } + }; + + struct CurrentDepth + { + std::uint64_t i; + explicit CurrentDepth(std::uint64_t i) : i(i) {} + operator uint64_t() const { return i; } + CurrentDepth incremented() const { return CurrentDepth{i + 1}; } + }; + + void create_directory_tree(urbg_t& urbg, vcpkg::Files::Filesystem& fs, - std::uint64_t depth, - const fs::path& base) + const fs::path& base, + MaxDepth max_depth, + AllowSymlinks allow_symlinks = AllowSymlinks::Yes, + Width width = Width{5}, + CurrentDepth current_depth = CurrentDepth{0}) { std::random_device rd; - constexpr std::uint64_t max_depth = 5; - constexpr std::uint64_t width = 5; // we want ~70% of our "files" to be directories, and then a third // each of the remaining ~30% to be regular files, directory symlinks, @@ -42,18 +76,24 @@ namespace constexpr std::uint64_t regular_symlink_tag = 8; constexpr std::uint64_t directory_symlink_tag = 9; + allow_symlinks = AllowSymlinks{allow_symlinks && can_create_symlinks()}; + // if we're at the max depth, we only want to build non-directories std::uint64_t file_type; - if (depth < max_depth) + if (current_depth >= max_depth) + { + file_type = uid_t{regular_file_tag, directory_symlink_tag}(urbg); + } + else if (current_depth < 2) { - file_type = uid{directory_min_tag, regular_symlink_tag}(urbg); + file_type = directory_min_tag; } else { - file_type = uid{regular_file_tag, regular_symlink_tag}(urbg); + file_type = uid_t{directory_min_tag, regular_symlink_tag}(urbg); } - if (!SYMLINKS_ALLOWED && file_type > regular_file_tag) + if (!allow_symlinks && file_type > regular_file_tag) { file_type = regular_file_tag; } @@ -62,14 +102,20 @@ namespace if (file_type <= directory_max_tag) { fs.create_directory(base, ec); - if (ec) { - INFO("File that failed: " << base); - REQUIRE_FALSE(ec); + if (ec) + { + CHECK_EC_ON_FILE(base, ec); } for (int i = 0; i < width; ++i) { - create_directory_tree(urbg, fs, depth + 1, base / get_random_filename(urbg)); + create_directory_tree(urbg, + fs, + base / get_random_filename(urbg), + max_depth, + allow_symlinks, + width, + current_depth.incremented()); } } else if (file_type == regular_file_tag) @@ -80,19 +126,34 @@ namespace else if (file_type == regular_symlink_tag) { // regular symlink - fs.write_contents(base, "", ec); - REQUIRE_FALSE(ec); auto base_link = base; - base_link.replace_filename(base.filename().u8string() + "-link"); - vcpkg::Test::create_symlink(base, base_link, ec); + base_link.replace_filename(base.filename().u8string() + "-orig"); + fs.write_contents(base_link, "", ec); + CHECK_EC_ON_FILE(base_link, ec); + vcpkg::Test::create_symlink(base_link, base, ec); } else // type == directory_symlink_tag { // directory symlink - vcpkg::Test::create_directory_symlink(base / "..", base, ec); + auto parent = base; + parent.remove_filename(); + vcpkg::Test::create_directory_symlink(parent, base, ec); } - REQUIRE_FALSE(ec); + CHECK_EC_ON_FILE(base, ec); + REQUIRE(fs::exists(fs.symlink_status(base, ec))); + CHECK_EC_ON_FILE(base, ec); + } + + vcpkg::Files::Filesystem& setup(urbg_t& urbg) + { + auto& fs = vcpkg::Files::get_real_filesystem(); + + std::error_code ec; + fs.create_directory(base_temporary_directory(), ec); + CHECK_EC_ON_FILE(base_temporary_directory(), ec); + + return fs; } } @@ -100,24 +161,83 @@ TEST_CASE ("remove all", "[files]") { auto urbg = get_urbg(0); - fs::path temp_dir = TEMPORARY_DIRECTORY / get_random_filename(urbg); + auto& fs = setup(urbg); - auto& fs = vcpkg::Files::get_real_filesystem(); + fs::path temp_dir = base_temporary_directory() / get_random_filename(urbg); + INFO("temp dir is: " << temp_dir); + + create_directory_tree(urbg, fs, temp_dir, MaxDepth{5}); std::error_code ec; - fs.create_directory(TEMPORARY_DIRECTORY, ec); + fs::path fp; + fs.remove_all(temp_dir, ec, fp); + CHECK_EC_ON_FILE(fp, ec); - REQUIRE_FALSE(ec); + REQUIRE_FALSE(fs.exists(temp_dir, ec)); + CHECK_EC_ON_FILE(temp_dir, ec); +} - INFO("temp dir is: " << temp_dir); +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +TEST_CASE ("remove all -- benchmarks", "[files][!benchmark]") +{ + auto urbg = get_urbg(1); + auto& fs = setup(urbg); - create_directory_tree(urbg, fs, 0, temp_dir); + struct + { + urbg_t& urbg; + vcpkg::Files::Filesystem& fs; - fs::path fp; - fs.remove_all(temp_dir, ec, fp); - if (ec) { - FAIL("remove_all failure on file: " << fp); - } + void operator()(Catch::Benchmark::Chronometer& meter, MaxDepth max_depth, AllowSymlinks allow_symlinks) const + { + std::vector temp_dirs; + temp_dirs.resize(meter.runs()); + + std::generate(begin(temp_dirs), end(temp_dirs), [&] { + fs::path temp_dir = base_temporary_directory() / get_random_filename(urbg); + create_directory_tree(urbg, fs, temp_dir, max_depth, allow_symlinks); + return temp_dir; + }); + + meter.measure([&](int run) { + std::error_code ec; + fs::path fp; + const auto& temp_dir = temp_dirs[run]; + + fs.remove_all(temp_dir, ec, fp); + CHECK_EC_ON_FILE(fp, ec); + }); + + for (const auto& dir : temp_dirs) + { + std::error_code ec; + REQUIRE_FALSE(fs.exists(dir, ec)); + CHECK_EC_ON_FILE(dir, ec); + } + } + } do_benchmark = {urbg, fs}; + + BENCHMARK_ADVANCED("small directory, no symlinks")(Catch::Benchmark::Chronometer meter) + { + do_benchmark(meter, MaxDepth{2}, AllowSymlinks::No); + }; + + BENCHMARK_ADVANCED("large directory, no symlinks")(Catch::Benchmark::Chronometer meter) + { + do_benchmark(meter, MaxDepth{5}, AllowSymlinks::No); + }; - REQUIRE_FALSE(fs.exists(temp_dir)); + if (can_create_symlinks()) + { + BENCHMARK_ADVANCED("small directory, symlinks")(Catch::Benchmark::Chronometer meter) + { + do_benchmark(meter, MaxDepth{2}, AllowSymlinks::Yes); + }; + + BENCHMARK_ADVANCED("large directory, symlinks")(Catch::Benchmark::Chronometer meter) + { + do_benchmark(meter, MaxDepth{5}, AllowSymlinks::Yes); + }; + } } +#endif diff --git a/toolsrc/src/vcpkg-test/util.cpp b/toolsrc/src/vcpkg-test/util.cpp index 5359b0fad..384954b4e 100644 --- a/toolsrc/src/vcpkg-test/util.cpp +++ b/toolsrc/src/vcpkg-test/util.cpp @@ -74,14 +74,14 @@ namespace vcpkg::Test return m_ret.value_or_exit(VCPKG_LINE_INFO); } - static bool system_allows_symlinks() + static AllowSymlinks internal_can_create_symlinks() noexcept { #if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_NONE - return false; + return AllowSymlinks::No; #elif FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_UNIX - return true; + return AllowSymlinks::Yes; #elif !defined(_WIN32) // FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_STD - return true; + return AllowSymlinks::Yes; #else HKEY key; bool allow_symlinks = true; @@ -97,11 +97,14 @@ namespace vcpkg::Test if (status == ERROR_SUCCESS) RegCloseKey(key); - return allow_symlinks; + return allow_symlinks ? AllowSymlinks::Yes : AllowSymlinks::No; #endif } + const static AllowSymlinks CAN_CREATE_SYMLINKS = internal_can_create_symlinks(); - static fs::path internal_temporary_directory() + AllowSymlinks can_create_symlinks() noexcept { return CAN_CREATE_SYMLINKS; } + + static fs::path internal_base_temporary_directory() { #if defined(_WIN32) wchar_t* tmp = static_cast(std::calloc(32'767, 2)); @@ -121,8 +124,9 @@ namespace vcpkg::Test #endif } - const bool SYMLINKS_ALLOWED = system_allows_symlinks(); - const fs::path TEMPORARY_DIRECTORY = internal_temporary_directory(); + const static fs::path BASE_TEMPORARY_DIRECTORY = internal_base_temporary_directory(); + + const fs::path& base_temporary_directory() noexcept { return BASE_TEMPORARY_DIRECTORY; } #if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_NONE constexpr char no_filesystem_message[] = @@ -132,7 +136,7 @@ namespace vcpkg::Test void create_symlink(const fs::path& target, const fs::path& file, std::error_code& ec) { #if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_STD - if (SYMLINKS_ALLOWED) + if (can_create_symlinks()) { std::filesystem::path targetp = target.native(); std::filesystem::path filep = file.native(); @@ -156,12 +160,12 @@ namespace vcpkg::Test void create_directory_symlink(const fs::path& target, const fs::path& file, std::error_code& ec) { #if FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_STD - if (SYMLINKS_ALLOWED) + if (can_create_symlinks()) { std::filesystem::path targetp = target.native(); std::filesystem::path filep = file.native(); - std::filesystem::create_symlink(targetp, filep); + std::filesystem::create_directory_symlink(targetp, filep); } else { diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp index 46ec8c013..3fdbd0d3e 100644 --- a/toolsrc/src/vcpkg.cpp +++ b/toolsrc/src/vcpkg.cpp @@ -125,12 +125,8 @@ static void inner(const VcpkgCmdArguments& args) auto default_vs_path = System::get_environment_variable("VCPKG_VISUAL_STUDIO_PATH").value_or(""); - - - const Expected expected_paths = VcpkgPaths::create(vcpkg_root_dir, - vcpkg_scripts_root_dir, - default_vs_path, - args.overlay_triplets.get()); + const Expected expected_paths = + VcpkgPaths::create(vcpkg_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", @@ -143,7 +139,11 @@ static void inner(const VcpkgCmdArguments& args) #else const int exit_code = chdir(paths.root.c_str()); #endif - Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Changing the working directory to the vcpkg root directory failed. Did you incorrectly define the VCPKG_ROOT environment variable, or did you mistakenly create a file named .vcpkg-root somewhere?"); + Checks::check_exit( + VCPKG_LINE_INFO, + exit_code == 0, + "Changing the working directory to the vcpkg root directory failed. Did you incorrectly define the VCPKG_ROOT " + "environment variable, or did you mistakenly create a file named .vcpkg-root somewhere?"); if (args.command == "install" || args.command == "remove" || args.command == "export" || args.command == "update") { diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 4446042f1..4a0a52f06 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -23,22 +23,35 @@ namespace fs::detail { - file_status symlink_status_t::operator()(const path& p, std::error_code& ec) const noexcept + static file_status status_implementation(bool follow_symlinks, const path& p, std::error_code& ec) { #if defined(_WIN32) - static_cast(ec); - WIN32_FILE_ATTRIBUTE_DATA file_attributes; file_type ft = file_type::unknown; perms permissions = perms::unknown; if (!GetFileAttributesExW(p.c_str(), GetFileExInfoStandard, &file_attributes)) { - ft = file_type::not_found; + const auto err = GetLastError(); + if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) + { + ft = file_type::not_found; + } + else + { + ec.assign(err, std::system_category()); + } } - else if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + else if (!follow_symlinks && file_attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - // check for reparse point -- if yes, then symlink - ft = file_type::symlink; + // this also gives junctions file_type::directory_symlink + if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + ft = file_type::directory_symlink; + } + else + { + ft = file_type::symlink; + } } else if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { @@ -50,17 +63,60 @@ namespace fs::detail ft = file_type::regular; } + if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + { + constexpr auto all_write = perms::group_write | perms::owner_write | perms::others_write; + permissions = perms::all & ~all_write; + } + else if (ft != file_type::none && ft != file_type::none) + { + permissions = perms::all; + } + return file_status(ft, permissions); #else - return stdfs::symlink_status(p, ec); + auto result = symlink ? stdfs::symlink_status(p, ec) : stdfs::status(p, ec); + // libstdc++ doesn't correctly not-set ec on nonexistent paths + if (ec.value() == ENOENT) + { + ec.clear(); + result = file_status(file_type::not_found, perms::unknown); + } + return result; #endif } + file_status status_t::operator()(const path& p, std::error_code& ec) const noexcept + { + return status_implementation(false, p, ec); + } + file_status status_t::operator()(vcpkg::LineInfo li, const path& p) const noexcept + { + std::error_code ec; + auto result = (*this)(p, ec); + if (ec) vcpkg::Checks::exit_with_message(li, "error getting status of path %s: %s", p.string(), ec.message()); + + return result; + } + file_status status_t::operator()(const path& p) const + { +#if defined(_WIN32) + return (*this)(VCPKG_LINE_INFO, p); +#else + return fs::stdfs::status(p); +#endif + } + + file_status symlink_status_t::operator()(const path& p, std::error_code& ec) const noexcept + { + return status_implementation(true, p, ec); + } + file_status symlink_status_t::operator()(vcpkg::LineInfo li, const path& p) const noexcept { std::error_code ec; - auto result = symlink_status(p, ec); + auto result = (*this)(p, ec); if (ec) vcpkg::Checks::exit_with_message(li, "error getting status of path %s: %s", p.string(), ec.message()); return result; @@ -71,34 +127,41 @@ namespace vcpkg::Files { static const std::regex FILESYSTEM_INVALID_CHARACTERS_REGEX = std::regex(R"([\/:*?"<>|])"); - namespace { + namespace + { // does _not_ follow symlinks - void set_writeable(const fs::path& path, std::error_code& ec) noexcept { + void set_writeable(const fs::path& path, std::error_code& ec) noexcept + { #if defined(_WIN32) auto const file_name = path.c_str(); WIN32_FILE_ATTRIBUTE_DATA attributes; - if (!GetFileAttributesExW(file_name, GetFileExInfoStandard, &attributes)) { + if (!GetFileAttributesExW(file_name, GetFileExInfoStandard, &attributes)) + { ec.assign(GetLastError(), std::system_category()); return; } auto dw_attributes = attributes.dwFileAttributes; dw_attributes &= ~FILE_ATTRIBUTE_READONLY; - if (!SetFileAttributesW(file_name, dw_attributes)) { + if (!SetFileAttributesW(file_name, dw_attributes)) + { ec.assign(GetLastError(), std::system_category()); } #else struct stat s; - if (lstat(path.c_str(), &s)) { + if (lstat(path.c_str(), &s)) + { ec.assign(errno, std::system_category()); return; } auto mode = s.st_mode; // if the file is a symlink, perms don't matter - if (!(mode & S_IFLNK)) { + if (!(mode & S_IFLNK)) + { mode |= S_IWUSR; - if (chmod(path.c_str(), mode)) { + if (chmod(path.c_str(), mode)) + { ec.assign(errno, std::system_category()); } } @@ -138,6 +201,25 @@ namespace vcpkg::Files return r; } + bool Filesystem::exists(const fs::path& path, std::error_code& ec) const + { + return fs::exists(this->symlink_status(path, ec)); + } + + bool Filesystem::exists(LineInfo li, const fs::path& path) const + { + std::error_code ec; + auto result = this->exists(path, ec); + if (ec) Checks::exit_with_message(li, "error checking existence of file %s: %s", path.u8string(), ec.message()); + return result; + } + bool Filesystem::exists(const fs::path& path) const + { + std::error_code ec; + // drop this on the floor, for compatibility with existing code + return exists(path, ec); + } + void Filesystem::write_lines(const fs::path& path, const std::vector& lines, LineInfo linfo) { std::error_code ec; @@ -145,12 +227,12 @@ namespace vcpkg::Files if (ec) Checks::exit_with_message(linfo, "error writing lines: %s: %s", path.u8string(), ec.message()); } - std::uintmax_t Filesystem::remove_all(const fs::path& path, LineInfo li) + void Filesystem::remove_all(const fs::path& path, LineInfo li) { std::error_code ec; fs::path failure_point; - const auto result = this->remove_all(path, ec, failure_point); + this->remove_all(path, ec, failure_point); if (ec) { @@ -160,8 +242,6 @@ namespace vcpkg::Files failure_point.string(), ec.message()); } - - return result; } struct RealFilesystem final : Filesystem @@ -203,8 +283,7 @@ namespace vcpkg::Files while (std::getline(file_stream, line)) { // Remove the trailing \r to accomodate Windows line endings. - if ((!line.empty()) && (line.back() == '\r')) - line.pop_back(); + if ((!line.empty()) && (line.back() == '\r')) line.pop_back(); output.push_back(line); } @@ -216,7 +295,7 @@ namespace vcpkg::Files const std::string& filename) const override { fs::path current_dir = starting_dir; - if (exists(current_dir / filename)) + if (exists(VCPKG_LINE_INFO, current_dir / filename)) { return current_dir; } @@ -241,7 +320,7 @@ namespace vcpkg::Files current_dir = std::move(parent); const fs::path candidate = current_dir / filename; - if (exists(candidate)) + if (exists(VCPKG_LINE_INFO, candidate)) { return current_dir; } @@ -359,149 +438,113 @@ namespace vcpkg::Files #endif } virtual bool remove(const fs::path& path, std::error_code& ec) override { return fs::stdfs::remove(path, ec); } - virtual std::uintmax_t remove_all(const fs::path& path, std::error_code& ec, fs::path& failure_point) override + virtual void remove_all(const fs::path& path, std::error_code& ec, fs::path& failure_point) override { /* - does not use the std::filesystem call since it is buggy, and can - have spurious errors before VS 2017 update 6, and on later versions - (as well as on macOS and Linux), this is just as fast and will have - fewer spurious errors due to locks. + does not use the std::experimental::filesystem call since this is + quite a bit faster, and also supports symlinks */ - /* - `remove` doesn't actually remove anything -- it simply moves the - files into a parent directory (which ends up being at `path`), - and then inserts `actually_remove{current_path}` into the work - queue. - */ struct remove { - struct tld + struct ErrorInfo : Util::ResourceBase { - const fs::path& tmp_directory; - std::uint64_t index; - - std::atomic& files_deleted; - - std::mutex& ec_mutex; - std::error_code& ec; - fs::path& failure_point; + std::error_code ec; + fs::path failure_point; }; - - struct actually_remove; - using queue = WorkQueue; - /* if `current_path` is a directory, first `remove`s all - elements of the directory, then calls remove. + elements of the directory, then removes current_path. - else, just calls remove. + else if `current_path` exists, removes current_path + + else does nothing */ - struct actually_remove + static void do_remove(const fs::path& current_path, ErrorInfo& err) { - fs::path current_path; + std::error_code ec; + const auto path_status = fs::symlink_status(current_path, ec); + if (check_ec(ec, current_path, err)) return; + if (!fs::exists(path_status)) return; - void operator()(tld& info, const queue& queue) const - { - std::error_code ec; - const auto path_type = fs::symlink_status(current_path, ec).type(); + const auto path_type = path_status.type(); - if (check_ec(ec, info, queue, current_path)) return; + if ((path_status.permissions() & fs::perms::owner_write) != fs::perms::owner_write) + { + set_writeable(current_path, ec); + if (check_ec(ec, current_path, err)) return; + } - if (path_type == fs::file_type::directory) + if (path_type == fs::file_type::directory) + { + for (const auto& entry : fs::stdfs::directory_iterator(current_path)) { - for (const auto& entry : fs::stdfs::directory_iterator(current_path)) - { - remove{}(entry, info, queue); - } + do_remove(entry, err); + if (err.ec) return; } - - set_writeable(current_path, ec); - if (check_ec(ec, info, queue, current_path)) return; - - if (fs::stdfs::remove(current_path, ec)) +#if defined(_WIN32) + if (!RemoveDirectoryW(current_path.c_str())) { - info.files_deleted.fetch_add(1, std::memory_order_relaxed); + ec.assign(GetLastError(), std::system_category()); } - else +#else + if (rmdir(current_path.c_str())) { - check_ec(ec, info, queue, current_path); + ec.assign(errno, std::system_category()); } +#endif } - }; - - static bool check_ec(const std::error_code& ec, - tld& info, - const queue& queue, - const fs::path& failure_point) - { - if (ec) +#if defined(_WIN32) + else if (path_type == fs::file_type::directory_symlink) { - queue.terminate(); - - auto lck = std::unique_lock(info.ec_mutex); - if (!info.ec) + if (!RemoveDirectoryW(current_path.c_str())) { - info.ec = ec; - info.failure_point = failure_point; + ec.assign(GetLastError(), std::system_category()); } - - return true; } else { - return false; + if (!DeleteFileW(current_path.c_str())) + { + ec.assign(GetLastError(), std::system_category()); + } + } +#else + else + { + if (unlink(current_path.c_str())) + { + ec.assign(errno, std::system_category()); + } } +#endif + + check_ec(ec, current_path, err); } - void operator()(const fs::path& current_path, tld& info, const queue& queue) const + static bool check_ec(const std::error_code& ec, const fs::path& current_path, ErrorInfo& err) { - std::error_code ec; - - const auto tmp_name = Strings::b32_encode(info.index++); - const auto tmp_path = info.tmp_directory / tmp_name; - - fs::stdfs::rename(current_path, tmp_path, ec); - if (check_ec(ec, info, queue, current_path)) return; + if (ec) + { + err.ec = ec; + err.failure_point = current_path; - queue.enqueue_action(actually_remove{std::move(tmp_path)}); + return true; + } + else + { + return false; + } } }; - const auto path_type = fs::symlink_status(path, ec).type(); - - std::atomic files_deleted{0}; - - if (path_type == fs::file_type::directory) - { - std::uint64_t index = 0; - std::mutex ec_mutex; - - auto const tld_gen = [&] { - index += static_cast(1) << 32; - return remove::tld{path, index, files_deleted, ec_mutex, ec, failure_point}; - }; - - remove::queue queue{VCPKG_LINE_INFO, 4, tld_gen}; - - // note: we don't actually start the queue running until the - // `join()`. This allows us to rename all the top-level files in - // peace, so that we don't get collisions. - auto main_tld = tld_gen(); - for (const auto& entry : fs::stdfs::directory_iterator(path)) - { - remove{}(entry, main_tld, queue); - } - - queue.join(VCPKG_LINE_INFO); - } - /* we need to do backoff on the removal of the top level directory, - since we need to place all moved files into that top level - directory, and so we can only delete the directory after all the + so we can only delete the directory after all the lower levels have been deleted. */ + + remove::ErrorInfo err; for (int backoff = 0; backoff < 5; ++backoff) { if (backoff) @@ -511,16 +554,16 @@ namespace vcpkg::Files std::this_thread::sleep_for(backoff_time); } - if (fs::stdfs::remove(path, ec)) + remove::do_remove(path, err); + if (!err.ec) { - files_deleted.fetch_add(1, std::memory_order_relaxed); break; } } - return files_deleted; + ec = std::move(err.ec); + failure_point = std::move(err.failure_point); } - virtual bool exists(const fs::path& path) const override { return fs::stdfs::exists(path); } virtual bool is_directory(const fs::path& path) const override { return fs::stdfs::is_directory(path); } virtual bool is_regular_file(const fs::path& path) const override { return fs::stdfs::is_regular_file(path); } virtual bool is_empty(const fs::path& path) const override { return fs::stdfs::is_empty(path); } @@ -598,7 +641,7 @@ namespace vcpkg::Files for (auto&& ext : EXTS) { auto p = fs::u8path(base + ext.c_str()); - if (Util::find(ret, p) == ret.end() && this->exists(p)) + if (Util::find(ret, p) == ret.end() && this->exists(VCPKG_LINE_INFO, p)) { ret.push_back(p); Debug::print("Found path: ", p.u8string(), '\n'); diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 54a691454..02d4c4a71 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -63,8 +63,7 @@ namespace vcpkg::Build::Command std::set features_as_set(full_spec.features.begin(), full_spec.features.end()); features_as_set.emplace("core"); - const Build::BuildPackageConfig build_config{ - scfl, spec.triplet(), build_package_options, features_as_set}; + const Build::BuildPackageConfig build_config{scfl, spec.triplet(), build_package_options, features_as_set}; const auto build_timer = Chrono::ElapsedTimer::create_started(); const auto result = Build::build_package(paths, build_config, status_db); @@ -293,19 +292,17 @@ namespace vcpkg::Build const std::set& feature_list, const Triplet& triplet) { - return Util::fmap_flatten( - feature_list, - [&](std::string const& feature) -> std::vector { - if (feature == "core") - { - return filter_dependencies_to_features(scf.core_paragraph->depends, triplet); - } + return Util::fmap_flatten(feature_list, [&](std::string const& feature) -> std::vector { + if (feature == "core") + { + return filter_dependencies_to_features(scf.core_paragraph->depends, triplet); + } - auto maybe_feature = scf.find_feature(feature); - Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value()); + auto maybe_feature = scf.find_feature(feature); + Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value()); - return filter_dependencies_to_features(maybe_feature.get()->depends, triplet); - }); + return filter_dependencies_to_features(maybe_feature.get()->depends, triplet); + }); } static std::vector get_dependency_names(const SourceControlFile& scf, @@ -313,10 +310,7 @@ namespace vcpkg::Build const Triplet& triplet) { return Util::fmap(get_dependencies(scf, feature_list, triplet), - [&](const Features& feat) { - return feat.name; - } - ); + [&](const Features& feat) { return feat.name; }); } static std::vector compute_required_feature_specs(const BuildPackageConfig& config, @@ -324,8 +318,7 @@ namespace vcpkg::Build { const Triplet& triplet = config.triplet; - const std::vector dep_strings = - get_dependency_names(config.scf, config.feature_list, triplet); + const std::vector dep_strings = get_dependency_names(config.scf, config.feature_list, triplet); auto dep_fspecs = FeatureSpec::from_strings_and_triplet(dep_strings, triplet); Util::sort_unique_erase(dep_fspecs); @@ -428,8 +421,7 @@ namespace vcpkg::Build { const Toolset& toolset = paths.get_toolset(pre_build_info); const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE); - std::vector variables = - get_cmake_vars(paths, config, triplet, toolset); + std::vector variables = get_cmake_vars(paths, config, triplet, toolset); const std::string cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, paths.ports_cmake, variables); @@ -521,13 +513,10 @@ namespace vcpkg::Build const auto timer = Chrono::ElapsedTimer::create_started(); - std::string command = - make_build_cmd(paths, pre_build_info, config, triplet); - std::unordered_map env = - make_env_passthrough(pre_build_info); + std::string command = make_build_cmd(paths, pre_build_info, config, triplet); + std::unordered_map env = make_env_passthrough(pre_build_info); - const int return_code = - System::cmd_execute_clean(command, env); + const int return_code = System::cmd_execute_clean(command, env); const auto buildtimeus = timer.microseconds(); const auto spec_string = spec.to_string(); @@ -785,8 +774,7 @@ namespace vcpkg::Build AbiEntry{status_it->get()->package.spec.name(), status_it->get()->package.abi}); } - const auto pre_build_info = - PreBuildInfo::from_triplet_file(paths, triplet, config.scfl); + const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet, config.scfl); auto maybe_abi_tag_and_file = compute_abi_tag(paths, config, pre_build_info, dependency_abis); @@ -995,8 +983,7 @@ namespace vcpkg::Build BuildInfo read_build_info(const Files::Filesystem& fs, const fs::path& filepath) { - const Expected pghs = - Paragraphs::get_single_paragraph(fs, filepath); + const Expected pghs = Paragraphs::get_single_paragraph(fs, filepath); Checks::check_exit(VCPKG_LINE_INFO, pghs.get() != nullptr, "Invalid BUILD_INFO file for package"); return inner_create_buildinfo(*pghs.get()); } @@ -1015,14 +1002,11 @@ namespace vcpkg::Build if (port) { - args.emplace_back( - "CMAKE_ENV_OVERRIDES_FILE", - port.value_or_exit(VCPKG_LINE_INFO).source_location / "environment-overrides.cmake"); + args.emplace_back("CMAKE_ENV_OVERRIDES_FILE", + port.value_or_exit(VCPKG_LINE_INFO).source_location / "environment-overrides.cmake"); } - const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, - ports_cmake_script_path, - args); + const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, ports_cmake_script_path, args); const auto ec_data = System::cmd_execute_and_capture_output(cmd_launch_cmake); Checks::check_exit(VCPKG_LINE_INFO, ec_data.exit_code == 0, ec_data.output); @@ -1054,41 +1038,39 @@ namespace vcpkg::Build { switch (maybe_option->second) { - case VcpkgTripletVar::TARGET_ARCHITECTURE : - pre_build_info.target_architecture = variable_value; - break; - case VcpkgTripletVar::CMAKE_SYSTEM_NAME : - pre_build_info.cmake_system_name = variable_value; - break; - case VcpkgTripletVar::CMAKE_SYSTEM_VERSION : - pre_build_info.cmake_system_version = variable_value; - break; - case VcpkgTripletVar::PLATFORM_TOOLSET : - pre_build_info.platform_toolset = - variable_value.empty() ? nullopt : Optional{variable_value}; - break; - case VcpkgTripletVar::VISUAL_STUDIO_PATH : - pre_build_info.visual_studio_path = - variable_value.empty() ? nullopt : Optional{variable_value}; - break; - case VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE : - pre_build_info.external_toolchain_file = - variable_value.empty() ? nullopt : Optional{variable_value}; - break; - case VcpkgTripletVar::BUILD_TYPE : - if (variable_value.empty()) - pre_build_info.build_type = nullopt; - else if (Strings::case_insensitive_ascii_equals(variable_value, "debug")) - pre_build_info.build_type = ConfigurationType::DEBUG; - else if (Strings::case_insensitive_ascii_equals(variable_value, "release")) - pre_build_info.build_type = ConfigurationType::RELEASE; - else - Checks::exit_with_message( + case VcpkgTripletVar::TARGET_ARCHITECTURE: + pre_build_info.target_architecture = variable_value; + break; + case VcpkgTripletVar::CMAKE_SYSTEM_NAME: pre_build_info.cmake_system_name = variable_value; break; + case VcpkgTripletVar::CMAKE_SYSTEM_VERSION: + pre_build_info.cmake_system_version = variable_value; + break; + case VcpkgTripletVar::PLATFORM_TOOLSET: + pre_build_info.platform_toolset = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::VISUAL_STUDIO_PATH: + pre_build_info.visual_studio_path = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE: + pre_build_info.external_toolchain_file = + variable_value.empty() ? nullopt : Optional{variable_value}; + break; + case VcpkgTripletVar::BUILD_TYPE: + if (variable_value.empty()) + pre_build_info.build_type = nullopt; + else if (Strings::case_insensitive_ascii_equals(variable_value, "debug")) + pre_build_info.build_type = ConfigurationType::DEBUG; + else if (Strings::case_insensitive_ascii_equals(variable_value, "release")) + pre_build_info.build_type = ConfigurationType::RELEASE; + else + Checks::exit_with_message( VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value); - break; - case VcpkgTripletVar::ENV_PASSTHROUGH : - pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";"); - break; + break; + case VcpkgTripletVar::ENV_PASSTHROUGH: + pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";"); + break; } } else @@ -1097,8 +1079,7 @@ namespace vcpkg::Build } } - pre_build_info.triplet_abi_tag = - get_triplet_abi(paths, pre_build_info, triplet); + pre_build_info.triplet_abi_tag = get_triplet_abi(paths, pre_build_info, triplet); return pre_build_info; } diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index b4290baab..f0f162f5c 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -236,12 +236,7 @@ namespace vcpkg::Commands::CI { auto triplet = p->spec.triplet(); - const Build::BuildPackageConfig build_config{ - *scfl, - triplet, - build_options, - p->feature_list - }; + const Build::BuildPackageConfig build_config{*scfl, triplet, build_options, p->feature_list}; auto dependency_abis = Util::fmap(p->computed_dependencies, [&](const PackageSpec& spec) -> Build::AbiEntry { @@ -253,14 +248,7 @@ namespace vcpkg::Commands::CI return {spec.name(), it->second}; }); const auto& pre_build_info = pre_build_info_cache.get_lazy( - triplet, - [&]() { - return Build::PreBuildInfo::from_triplet_file( - paths, - triplet, - *scfl); - } - ); + triplet, [&]() { return Build::PreBuildInfo::from_triplet_file(paths, triplet, *scfl); }); auto maybe_tag_and_file = Build::compute_abi_tag(paths, build_config, pre_build_info, dependency_abis); @@ -362,7 +350,7 @@ namespace vcpkg::Commands::CI } StatusParagraphs status_db = database_load_check(paths); - + Dependencies::PathsPortFileProvider provider(paths, args.overlay_ports.get()); const Build::BuildPackageOptions install_plan_options = { diff --git a/toolsrc/src/vcpkg/commands.dependinfo.cpp b/toolsrc/src/vcpkg/commands.dependinfo.cpp index 8394e0166..7c04a5a2f 100644 --- a/toolsrc/src/vcpkg/commands.dependinfo.cpp +++ b/toolsrc/src/vcpkg/commands.dependinfo.cpp @@ -5,12 +5,12 @@ #include #include #include -#include #include +#include -#include #include #include +#include using vcpkg::Dependencies::PathsPortFileProvider; @@ -171,14 +171,14 @@ namespace vcpkg::Commands::DependInfo { if (requested_feature_name == "*") { - for (auto &&feature_paragraph : (*source_control_file)->feature_paragraphs) + for (auto&& feature_paragraph : (*source_control_file)->feature_paragraphs) { collected_features.insert(std::addressof(Util::as_const(*feature_paragraph))); } continue; } auto maybe_feature = (*source_control_file)->find_feature(requested_feature_name); - if (auto &&feature_paragraph = maybe_feature.get()) + if (auto&& feature_paragraph = maybe_feature.get()) { collected_features.insert(std::addressof(Util::as_const(*feature_paragraph))); } @@ -197,7 +197,8 @@ namespace vcpkg::Commands::DependInfo { for (const auto& dependency : feature_paragraph->depends) { - build_dependencies_list(packages_to_keep, dependency.depend.name, source_control_files, switches); + build_dependencies_list( + packages_to_keep, dependency.depend.name, source_control_files, switches); } } } @@ -214,9 +215,9 @@ namespace vcpkg::Commands::DependInfo // TODO: Optimize implementation, current implementation needs to load all ports from disk which is too slow. PathsPortFileProvider provider(paths, args.overlay_ports.get()); - auto source_control_files = Util::fmap(provider.load_all_control_files(), [](auto&& scfl) -> const SourceControlFile * { - return scfl->source_control_file.get(); - }); + auto source_control_files = + Util::fmap(provider.load_all_control_files(), + [](auto&& scfl) -> const SourceControlFile* { return scfl->source_control_file.get(); }); if (args.command_arguments.size() >= 1) { diff --git a/toolsrc/src/vcpkg/commands.search.cpp b/toolsrc/src/vcpkg/commands.search.cpp index 3d8387ee1..943233502 100644 --- a/toolsrc/src/vcpkg/commands.search.cpp +++ b/toolsrc/src/vcpkg/commands.search.cpp @@ -2,12 +2,12 @@ #include #include +#include #include #include #include #include #include -#include using vcpkg::Dependencies::PathsPortFileProvider; @@ -67,9 +67,9 @@ namespace vcpkg::Commands::Search const bool full_description = Util::Sets::contains(options.switches, OPTION_FULLDESC); PathsPortFileProvider provider(paths, args.overlay_ports.get()); - auto source_paragraphs = Util::fmap(provider.load_all_control_files(), [](auto&& port) -> const SourceControlFile * { - return port->source_control_file.get(); - }); + auto source_paragraphs = + Util::fmap(provider.load_all_control_files(), + [](auto&& port) -> const SourceControlFile* { return port->source_control_file.get(); }); if (args.command_arguments.empty()) { diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp index b604c9acf..65c5cc985 100644 --- a/toolsrc/src/vcpkg/dependencies.cpp +++ b/toolsrc/src/vcpkg/dependencies.cpp @@ -108,9 +108,8 @@ namespace vcpkg::Dependencies static ClusterSource cluster_from_scf(const SourceControlFileLocation& scfl, Triplet t) { ClusterSource ret; - ret.build_edges.emplace("core", - filter_dependencies_to_specs(scfl.source_control_file->core_paragraph->depends, - t)); + ret.build_edges.emplace("core", + filter_dependencies_to_specs(scfl.source_control_file->core_paragraph->depends, t)); for (const auto& feature : scfl.source_control_file->feature_paragraphs) ret.build_edges.emplace(feature->name, filter_dependencies_to_specs(feature->depends, t)); @@ -123,22 +122,23 @@ namespace vcpkg::Dependencies const PortFileProvider& m_provider; }; - std::string to_output_string(RequestType request_type, - const CStringView s, - const Build::BuildPackageOptions& options, + std::string to_output_string(RequestType request_type, + const CStringView s, + const Build::BuildPackageOptions& options, const fs::path& install_port_path, const fs::path& default_port_path) { - if (!default_port_path.empty() - && !Strings::case_insensitive_ascii_starts_with(install_port_path.u8string(), - default_port_path.u8string())) + if (!default_port_path.empty() && + !Strings::case_insensitive_ascii_starts_with(install_port_path.u8string(), default_port_path.u8string())) { const char* const from_head = options.use_head_version == Build::UseHeadVersion::YES ? " (from HEAD)" : ""; switch (request_type) { - case RequestType::AUTO_SELECTED: return Strings::format(" * %s%s -- %s", s, from_head, install_port_path.u8string()); - case RequestType::USER_REQUESTED: return Strings::format(" %s%s -- %s", s, from_head, install_port_path.u8string()); - default: Checks::unreachable(VCPKG_LINE_INFO); + case RequestType::AUTO_SELECTED: + return Strings::format(" * %s%s -- %s", s, from_head, install_port_path.u8string()); + case RequestType::USER_REQUESTED: + return Strings::format(" %s%s -- %s", s, from_head, install_port_path.u8string()); + default: Checks::unreachable(VCPKG_LINE_INFO); } } return to_output_string(request_type, s, options); @@ -152,7 +152,7 @@ namespace vcpkg::Dependencies switch (request_type) { - case RequestType::AUTO_SELECTED: return Strings::format(" * %s%s", s, from_head); + case RequestType::AUTO_SELECTED: return Strings::format(" * %s%s", s, from_head); case RequestType::USER_REQUESTED: return Strings::format(" %s%s", s, from_head); default: Checks::unreachable(VCPKG_LINE_INFO); } @@ -162,7 +162,7 @@ namespace vcpkg::Dependencies { switch (request_type) { - case RequestType::AUTO_SELECTED: return Strings::format(" * %s", s); + case RequestType::AUTO_SELECTED: return Strings::format(" * %s", s); case RequestType::USER_REQUESTED: return Strings::format(" %s", s); default: Checks::unreachable(VCPKG_LINE_INFO); } @@ -293,7 +293,8 @@ namespace vcpkg::Dependencies MapPortFileProvider::MapPortFileProvider(const std::unordered_map& map) : ports(map) - {} + { + } Optional MapPortFileProvider::get_control_file(const std::string& spec) const { @@ -304,11 +305,11 @@ namespace vcpkg::Dependencies std::vector MapPortFileProvider::load_all_control_files() const { - return Util::fmap(ports, [](auto&& kvpair) -> const SourceControlFileLocation * { return &kvpair.second; }); + return Util::fmap(ports, [](auto&& kvpair) -> const SourceControlFileLocation* { return &kvpair.second; }); } PathsPortFileProvider::PathsPortFileProvider(const vcpkg::VcpkgPaths& paths, - const std::vector* ports_dirs_paths) + const std::vector* ports_dirs_paths) : filesystem(paths.get_filesystem()) { if (ports_dirs_paths) @@ -325,7 +326,7 @@ namespace vcpkg::Dependencies overlay.string()); Checks::check_exit(VCPKG_LINE_INFO, - fs::stdfs::is_directory(overlay), + fs::is_directory(status(overlay)), "Error: Path \"%s\" must be a directory", overlay.string()); @@ -354,7 +355,7 @@ namespace vcpkg::Dependencies { if (scf->get()->core_paragraph->name == spec) { - SourceControlFileLocation scfl{ std::move(*scf), ports_dir }; + SourceControlFileLocation scfl{std::move(*scf), ports_dir}; auto it = cache.emplace(spec, std::move(scfl)); return it.first->second; } @@ -362,9 +363,8 @@ namespace vcpkg::Dependencies else { vcpkg::print_error_message(maybe_scf.error()); - Checks::exit_with_message(VCPKG_LINE_INFO, - "Error: Failed to load port from %s", - spec, ports_dir.u8string()); + Checks::exit_with_message( + VCPKG_LINE_INFO, "Error: Failed to load port from %s", spec, ports_dir.u8string()); } } @@ -373,7 +373,7 @@ namespace vcpkg::Dependencies { if (scf->get()->core_paragraph->name == spec) { - SourceControlFileLocation scfl{ std::move(*scf), ports_dir / spec }; + SourceControlFileLocation scfl{std::move(*scf), ports_dir / spec}; auto it = cache.emplace(spec, std::move(scfl)); return it.first->second; } @@ -399,7 +399,7 @@ namespace vcpkg::Dependencies auto port_name = scf->get()->core_paragraph->name; if (cache.find(port_name) == cache.end()) { - SourceControlFileLocation scfl{ std::move(*scf), ports_dir }; + SourceControlFileLocation scfl{std::move(*scf), ports_dir}; auto it = cache.emplace(port_name, std::move(scfl)); ret.emplace_back(&it.first->second); } @@ -407,9 +407,8 @@ namespace vcpkg::Dependencies else { vcpkg::print_error_message(maybe_scf.error()); - Checks::exit_with_message(VCPKG_LINE_INFO, - "Error: Failed to load port from %s", - ports_dir.u8string()); + Checks::exit_with_message( + VCPKG_LINE_INFO, "Error: Failed to load port from %s", ports_dir.u8string()); } continue; } @@ -421,7 +420,7 @@ namespace vcpkg::Dependencies auto port_name = scf->core_paragraph->name; if (cache.find(port_name) == cache.end()) { - SourceControlFileLocation scfl{ std::move(scf), ports_dir / port_name }; + SourceControlFileLocation scfl{std::move(scf), ports_dir / port_name}; auto it = cache.emplace(port_name, std::move(scfl)); ret.emplace_back(&it.first->second); } @@ -768,9 +767,10 @@ namespace vcpkg::Dependencies /// Map of all source control files in the current environment. /// Feature specifications to resolve dependencies for. /// Status of installed packages in the current environment. - std::vector create_feature_install_plan(const std::unordered_map& map, - const std::vector& specs, - const StatusParagraphs& status_db) + std::vector create_feature_install_plan( + const std::unordered_map& map, + const std::vector& specs, + const StatusParagraphs& status_db) { MapPortFileProvider provider(map); return create_feature_install_plan(provider, specs, status_db); @@ -832,9 +832,8 @@ namespace vcpkg::Dependencies { // If it will be transiently uninstalled, we need to issue a full installation command auto* pscfl = p_cluster->source.value_or_exit(VCPKG_LINE_INFO).scfl; - Checks::check_exit(VCPKG_LINE_INFO, - pscfl != nullptr, - "Error: Expected a SourceControlFileLocation to exist"); + Checks::check_exit( + VCPKG_LINE_INFO, pscfl != nullptr, "Error: Expected a SourceControlFileLocation to exist"); auto&& scfl = *pscfl; auto dep_specs = Util::fmap(m_graph_plan->install_graph.adjacency_list(p_cluster), @@ -914,7 +913,9 @@ namespace vcpkg::Dependencies PackageGraph::~PackageGraph() = default; - void print_plan(const std::vector& action_plan, const bool is_recursive, const fs::path& default_ports_dir) + void print_plan(const std::vector& action_plan, + const bool is_recursive, + const fs::path& default_ports_dir) { std::vector remove_plans; std::vector rebuilt_plans; @@ -971,13 +972,10 @@ namespace vcpkg::Dependencies static auto actions_to_output_string = [&](const std::vector& v) { return Strings::join("\n", v, [&](const InstallPlanAction* p) { - if (auto * pscfl = p->source_control_file_location.get()) + if (auto* pscfl = p->source_control_file_location.get()) { - return to_output_string(p->request_type, - p->displayname(), - p->build_options, - pscfl->source_location, - default_ports_dir); + return to_output_string( + p->request_type, p->displayname(), p->build_options, pscfl->source_location, default_ports_dir); } return to_output_string(p->request_type, p->displayname(), p->build_options); diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 32af57b39..165f13126 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -331,10 +331,8 @@ namespace vcpkg::Install auto result = [&]() -> Build::ExtendedBuildResult { const auto& scfl = action.source_control_file_location.value_or_exit(VCPKG_LINE_INFO); - const Build::BuildPackageConfig build_config{scfl, - action.spec.triplet(), - action.build_options, - action.feature_list}; + const Build::BuildPackageConfig build_config{ + scfl, action.spec.triplet(), action.build_options, action.feature_list}; return Build::build_package(paths, build_config, status_db); }(); diff --git a/toolsrc/src/vcpkg/logicexpression.cpp b/toolsrc/src/vcpkg/logicexpression.cpp index fc8c4ef56..0cf08ee03 100644 --- a/toolsrc/src/vcpkg/logicexpression.cpp +++ b/toolsrc/src/vcpkg/logicexpression.cpp @@ -1,21 +1,18 @@ #include "pch.h" -#include #include #include +#include #include #include - namespace vcpkg { struct ParseError { - ParseError(int column, std::string line, std::string message) - :column(column), line(line), message(message) - {} + ParseError(int column, std::string line, std::string message) : column(column), line(line), message(message) {} const int column; const std::string line; @@ -24,9 +21,15 @@ namespace vcpkg void print_error() const { System::print2(System::Color::error, - "Error: ", message, "\n" - " on expression: \"", line, "\"\n", - " ", std::string(column, ' '), "^\n"); + "Error: ", + message, + "\n" + " on expression: \"", + line, + "\"\n", + " ", + std::string(column, ' '), + "^\n"); Checks::exit_fail(VCPKG_LINE_INFO); } }; @@ -36,7 +39,7 @@ namespace vcpkg // ( logic-expression ) // identifier // identifier: - // alpha-numeric string of characters + // alpha-numeric string of characters // logic-expression: <- this is the entry point // not-expression // not-expression | logic-expression @@ -69,27 +72,20 @@ namespace vcpkg } } - bool get_result() const - { - return final_result; - } + bool get_result() const { return final_result; } - bool has_error() const - { - return err == nullptr; - } + bool has_error() const { return err == nullptr; } private: - bool final_result; std::string::const_iterator current_iter; const std::string& raw_text; - char current_char; + char current_char; - const std::string& evaluation_context; + const std::string& evaluation_context; - std::unique_ptr err; + std::unique_ptr err; void add_error(std::string message, int column = -1) { @@ -107,10 +103,7 @@ namespace vcpkg skip_to_end(); } - int current_column() const - { - return static_cast(current_iter - raw_text.begin()); - } + int current_column() const { return static_cast(current_iter - raw_text.begin()); } void go_to_begin() { @@ -127,10 +120,7 @@ namespace vcpkg current_iter = raw_text.end(); current_char = '\0'; } - char current() const - { - return current_char; - } + char current() const { return current_char; } char next() { if (current_char != '\0') @@ -165,7 +155,7 @@ namespace vcpkg } // identifier: - // alpha-numeric string of characters + // alpha-numeric string of characters bool identifier_expression() { auto curr = current(); @@ -181,7 +171,7 @@ namespace vcpkg add_error("Invalid logic expression, unexpected character"); return false; } - + bool result = evaluate_identifier(name); skip_whitespace(); return result; @@ -201,14 +191,15 @@ namespace vcpkg return primary_expression(); } - - template + template bool logic_expression_helper(bool seed) { do { // Support chains of the operator to avoid breaking backwards compatability - while (next() == oper) {}; + while (next() == oper) + { + }; seed = operation(not_expression(), seed); } while (current() == oper); @@ -218,17 +209,11 @@ namespace vcpkg add_error("Mixing & and | is not allowed, Use () to specify order of operations."); } - skip_whitespace(); + skip_whitespace(); return seed; } - static bool and_helper(bool left, bool right) - { - return left && right; - } - static bool or_helper(bool left, bool right) - { - return left || right; - } + static bool and_helper(bool left, bool right) { return left && right; } + static bool or_helper(bool left, bool right) { return left || right; } // logic-expression: <- entry point // not-expression @@ -240,16 +225,15 @@ namespace vcpkg switch (current()) { - case '|': - { - return logic_expression_helper< '|', '&', or_helper > (result); - } - case '&': - { - return logic_expression_helper< '&', '|', and_helper > (result); - } - default: - return result; + case '|': + { + return logic_expression_helper<'|', '&', or_helper>(result); + } + case '&': + { + return logic_expression_helper<'&', '|', and_helper>(result); + } + default: return result; } } @@ -275,7 +259,6 @@ namespace vcpkg } }; - bool evaluate_expression(const std::string& expression, const std::string& evaluation_context) { ExpressionParser parser(expression, evaluation_context); diff --git a/toolsrc/src/vcpkg/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp index b08a6b805..1232b940a 100644 --- a/toolsrc/src/vcpkg/paragraphs.cpp +++ b/toolsrc/src/vcpkg/paragraphs.cpp @@ -166,8 +166,7 @@ namespace vcpkg::Paragraphs Expected parse_single_paragraph(const std::string& str) { - const std::vector p = - Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs(); + const std::vector p = Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs(); if (p.size() == 1) { @@ -177,8 +176,7 @@ namespace vcpkg::Paragraphs return std::error_code(ParagraphParseResult::EXPECTED_ONE_PARAGRAPH); } - Expected get_single_paragraph(const Files::Filesystem& fs, - const fs::path& control_path) + Expected get_single_paragraph(const Files::Filesystem& fs, const fs::path& control_path) { const Expected contents = fs.read_contents(control_path); if (auto spgh = contents.get()) @@ -189,8 +187,7 @@ namespace vcpkg::Paragraphs return contents.error(); } - Expected> get_paragraphs(const Files::Filesystem& fs, - const fs::path& control_path) + Expected> get_paragraphs(const Files::Filesystem& fs, const fs::path& control_path) { const Expected contents = fs.read_contents(control_path); if (auto spgh = contents.get()) diff --git a/toolsrc/src/vcpkg/parse.cpp b/toolsrc/src/vcpkg/parse.cpp index 68fac0b0f..9c9968249 100644 --- a/toolsrc/src/vcpkg/parse.cpp +++ b/toolsrc/src/vcpkg/parse.cpp @@ -6,8 +6,7 @@ namespace vcpkg::Parse { - static Optional remove_field(RawParagraph* fields, - const std::string& fieldname) + static Optional remove_field(RawParagraph* fields, const std::string& fieldname) { auto it = fields->find(fieldname); if (it == fields->end()) diff --git a/toolsrc/src/vcpkg/remove.cpp b/toolsrc/src/vcpkg/remove.cpp index 84ec6c981..65e00668a 100644 --- a/toolsrc/src/vcpkg/remove.cpp +++ b/toolsrc/src/vcpkg/remove.cpp @@ -73,7 +73,7 @@ namespace vcpkg::Remove if (ec) { #if defined(_WIN32) - fs::stdfs::permissions(target, fs::stdfs::perms::owner_all | fs::stdfs::perms::group_all, ec); + fs::stdfs::permissions(target, fs::perms::owner_all | fs::perms::group_all, ec); fs.remove(target, ec); if (ec) { @@ -86,7 +86,7 @@ namespace vcpkg::Remove #endif } } - else if (!fs::stdfs::exists(status)) + else if (!fs::exists(status)) { System::printf(System::Color::warning, "Warning: %s: file not found\n", target.u8string()); } diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index a5054eb3b..298095df6 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -1,9 +1,9 @@ #include "pch.h" +#include #include #include #include -#include #include #include @@ -223,26 +223,25 @@ namespace vcpkg std::vector ret; for (auto&& dep : deps) { - const auto & qualifier = dep.qualifier; - if (qualifier.empty() || evaluate_expression(qualifier, t.canonical_name())) - { - ret.emplace_back(dep.name()); - } + const auto& qualifier = dep.qualifier; + if (qualifier.empty() || evaluate_expression(qualifier, t.canonical_name())) + { + ret.emplace_back(dep.name()); + } } return ret; } - std::vector filter_dependencies_to_features(const std::vector& deps, - const Triplet& t) + std::vector filter_dependencies_to_features(const std::vector& deps, const Triplet& t) { std::vector ret; for (auto&& dep : deps) { - const auto & qualifier = dep.qualifier; - if (qualifier.empty() || evaluate_expression(qualifier, t.canonical_name())) - { - ret.emplace_back(dep.depend); - } + const auto& qualifier = dep.qualifier; + if (qualifier.empty() || evaluate_expression(qualifier, t.canonical_name())) + { + ret.emplace_back(dep.depend); + } } return ret; } diff --git a/toolsrc/src/vcpkg/userconfig.cpp b/toolsrc/src/vcpkg/userconfig.cpp index 3551ae81e..a3c019be7 100644 --- a/toolsrc/src/vcpkg/userconfig.cpp +++ b/toolsrc/src/vcpkg/userconfig.cpp @@ -51,7 +51,7 @@ namespace vcpkg { const auto& pghs = *p_pghs; - Parse::RawParagraph keys; + Parse::RawParagraph keys; if (pghs.size() > 0) keys = pghs[0]; for (size_t x = 1; x < pghs.size(); ++x) diff --git a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp index 452c7ca19..e48340df7 100644 --- a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp +++ b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp @@ -148,9 +148,8 @@ namespace vcpkg } if (Strings::starts_with(arg, "--scripts-root=")) { - parse_cojoined_value(arg.substr(sizeof("--scripts-root=") - 1), - "--scripts-root", - args.scripts_root_dir); + parse_cojoined_value( + arg.substr(sizeof("--scripts-root=") - 1), "--scripts-root", args.scripts_root_dir); continue; } if (arg == "--triplet") @@ -161,16 +160,14 @@ namespace vcpkg } if (Strings::starts_with(arg, "--overlay-ports=")) { - parse_cojoined_multivalue(arg.substr(sizeof("--overlay-ports=") - 1), - "--overlay-ports", - args.overlay_ports); + parse_cojoined_multivalue( + arg.substr(sizeof("--overlay-ports=") - 1), "--overlay-ports", args.overlay_ports); continue; } if (Strings::starts_with(arg, "--overlay-triplets=")) { - parse_cojoined_multivalue(arg.substr(sizeof("--overlay-triplets=") - 1), - "--overlay-triplets", - args.overlay_triplets); + parse_cojoined_multivalue( + arg.substr(sizeof("--overlay-triplets=") - 1), "--overlay-triplets", args.overlay_triplets); continue; } if (arg == "--debug") @@ -224,11 +221,11 @@ namespace vcpkg { const auto& key = arg.substr(0, eq_pos); const auto& value = arg.substr(eq_pos + 1); - + auto it = args.optional_command_arguments.find(key); if (args.optional_command_arguments.end() == it) { - args.optional_command_arguments.emplace(key, std::vector { value }); + args.optional_command_arguments.emplace(key, std::vector{value}); } else { @@ -370,8 +367,9 @@ namespace vcpkg { if (v.empty()) { - System::printf( - System::Color::error, "Error: The option '%s' must be passed an argument.\n", option.name); + System::printf(System::Color::error, + "Error: The option '%s' must be passed an argument.\n", + option.name); failed = true; } else @@ -425,12 +423,9 @@ namespace vcpkg System::printf(" %-40s %s\n", (option.name + "=..."), option.short_help_text); } System::printf(" %-40s %s\n", "--triplet ", "Set the default triplet for unqualified packages"); - System::printf(" %-40s %s\n", - "--overlay-ports=", - "Specify directories to be used when searching for ports"); - System::printf(" %-40s %s\n", - "--overlay-triplets=", - "Specify directories containing triplets files"); + System::printf( + " %-40s %s\n", "--overlay-ports=", "Specify directories to be used when searching for ports"); + System::printf(" %-40s %s\n", "--overlay-triplets=", "Specify directories containing triplets files"); System::printf(" %-40s %s\n", "--vcpkg-root ", "Specify the vcpkg directory to use instead of current directory or tool directory"); diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index d16acf2e8..c5b5749ff 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -42,7 +42,7 @@ namespace vcpkg if (auto odp = overriddenDownloadsPath.get()) { auto asPath = fs::u8path(*odp); - if (!fs::stdfs::is_directory(asPath)) + if (!fs::is_directory(status(asPath))) { Metrics::g_metrics.lock()->track_property("error", "Invalid VCPKG_DOWNLOADS override directory."); Checks::exit_with_message( @@ -71,12 +71,12 @@ namespace vcpkg { if (scripts_dir->empty() || !fs::stdfs::is_directory(*scripts_dir)) { - Metrics::g_metrics.lock()->track_property("error", "Invalid scripts override directory."); - Checks::exit_with_message( - VCPKG_LINE_INFO, - "Invalid scripts override directory: %s; " - "create that directory or unset --scripts-root to use the default scripts location.", - scripts_dir->u8string()); + Metrics::g_metrics.lock()->track_property("error", "Invalid scripts override directory."); + Checks::exit_with_message( + VCPKG_LINE_INFO, + "Invalid scripts override directory: %s; " + "create that directory or unset --scripts-root to use the default scripts location.", + scripts_dir->u8string()); } paths.scripts = *scripts_dir; @@ -147,26 +147,25 @@ namespace vcpkg } Util::sort_unique_erase(output); return output; - }); + }); } const fs::path VcpkgPaths::get_triplet_file_path(const Triplet& triplet) const { - return m_triplets_cache.get_lazy(triplet, [&]()-> auto { - for (auto&& triplet_dir : triplets_dirs) - { - auto&& path = triplet_dir / (triplet.canonical_name() + ".cmake"); - if (this->get_filesystem().exists(path)) + return m_triplets_cache.get_lazy( + triplet, [&]() -> auto { + for (auto&& triplet_dir : triplets_dirs) { - return path; + auto&& path = triplet_dir / (triplet.canonical_name() + ".cmake"); + if (this->get_filesystem().exists(path)) + { + return path; + } } - } - Checks::exit_with_message(VCPKG_LINE_INFO, - "Error: Triplet file %s.cmake not found", - triplet.canonical_name()); - }); - + Checks::exit_with_message( + VCPKG_LINE_INFO, "Error: Triplet file %s.cmake not found", triplet.canonical_name()); + }); } const fs::path& VcpkgPaths::get_tool_exe(const std::string& tool) const -- cgit v1.2.3 From 14c792441dc5963d0d17cb2e7a6dc1b2f7665d9b Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Tue, 23 Jul 2019 01:46:36 -0700 Subject: [vcpkg] Revert accidental removal of powershell-core usage in bb3a9ddb6ec917f54 --- toolsrc/src/vcpkg/build.cpp | 17 ++++++++++++++++- toolsrc/src/vcpkg/tools.cpp | 45 ++++++++++++++++----------------------------- 2 files changed, 32 insertions(+), 30 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 02d4c4a71..5b93242a1 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -499,6 +499,14 @@ namespace vcpkg::Build const BuildPackageConfig& config) { auto& fs = paths.get_filesystem(); +#if defined(_WIN32) + const fs::path& powershell_exe_path = paths.get_tool_exe("powershell-core"); + if (!fs.exists(powershell_exe_path.parent_path() / "powershell.exe")) + { + fs.copy(powershell_exe_path, powershell_exe_path.parent_path() / "powershell.exe", fs::copy_options::none); + } +#endif + const Triplet& triplet = spec.triplet(); const auto& triplet_file_path = paths.get_triplet_file_path(spec.triplet()).u8string(); @@ -516,8 +524,12 @@ namespace vcpkg::Build std::string command = make_build_cmd(paths, pre_build_info, config, triplet); std::unordered_map env = make_env_passthrough(pre_build_info); +#if defined(_WIN32) + const int return_code = + System::cmd_execute_clean(command, env, powershell_exe_path.parent_path().u8string() + ";"); +#else const int return_code = System::cmd_execute_clean(command, env); - +#endif const auto buildtimeus = timer.microseconds(); const auto spec_string = spec.to_string(); @@ -597,6 +609,9 @@ namespace vcpkg::Build std::vector abi_tag_entries(dependency_abis.begin(), dependency_abis.end()); +#if defined(_WIN32) + abi_tag_entries.emplace_back(AbiEntry{"powershell", paths.get_tool_version("powershell-core")}); +#endif abi_tag_entries.emplace_back(AbiEntry{"cmake", paths.get_tool_version(Tools::CMAKE)}); // If there is an unusually large number of files in the port then diff --git a/toolsrc/src/vcpkg/tools.cpp b/toolsrc/src/vcpkg/tools.cpp index 4f4b23055..7d56854c6 100644 --- a/toolsrc/src/vcpkg/tools.cpp +++ b/toolsrc/src/vcpkg/tools.cpp @@ -294,20 +294,6 @@ CMake suite maintained and supported by Kitware (kitware.com/cmake). } }; - static fs::path get_7za_path(const VcpkgPaths& paths) - { -#if defined(_WIN32) - static const ToolData TOOL_DATA = parse_tool_data_from_xml(paths, "7zip").value_or_exit(VCPKG_LINE_INFO); - if (!paths.get_filesystem().exists(TOOL_DATA.exe_path)) - { - return fetch_tool(paths, "7zip", TOOL_DATA); - } - return TOOL_DATA.exe_path; -#else - Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot download 7zip for non-Windows platforms."); -#endif - } - struct NinjaProvider : ToolProvider { std::string m_exe = "ninja"; @@ -443,31 +429,21 @@ git version 2.17.1.windows.2 virtual const fs::path& get_tool_path(const VcpkgPaths& paths, const std::string& tool) const override { return path_only_cache.get_lazy(tool, [&]() { - // First deal with specially handled tools. - // For these we may look in locations like Program Files, the PATH etc as well as the auto-downloaded - // location. - if (tool == Tools::SEVEN_ZIP) return get_7za_path(paths); - if (tool == Tools::CMAKE || tool == Tools::GIT || tool == Tools::NINJA || tool == Tools::NUGET || - tool == Tools::IFW_INSTALLER_BASE) - return get_tool_pathversion(paths, tool).path; if (tool == Tools::IFW_BINARYCREATOR) return get_tool_path(paths, Tools::IFW_INSTALLER_BASE).parent_path() / "binarycreator.exe"; if (tool == Tools::IFW_REPOGEN) return get_tool_path(paths, Tools::IFW_INSTALLER_BASE).parent_path() / "repogen.exe"; - // For other tools, we simply always auto-download them. - const ToolData tool_data = parse_tool_data_from_xml(paths, tool).value_or_exit(VCPKG_LINE_INFO); - if (paths.get_filesystem().exists(tool_data.exe_path)) - { - return tool_data.exe_path; - } - return fetch_tool(paths, tool, tool_data); + return get_tool_pathversion(paths, tool).path; }); } const PathAndVersion& get_tool_pathversion(const VcpkgPaths& paths, const std::string& tool) const { return path_version_cache.get_lazy(tool, [&]() -> PathAndVersion { + // First deal with specially handled tools. + // For these we may look in locations like Program Files, the PATH etc as well as the auto-downloaded + // location. if (tool == Tools::CMAKE) { if (System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value()) @@ -495,7 +471,18 @@ git version 2.17.1.windows.2 if (tool == Tools::NUGET) return get_path(paths, NuGetProvider()); if (tool == Tools::IFW_INSTALLER_BASE) return get_path(paths, IfwInstallerBaseProvider()); - Checks::exit_with_message(VCPKG_LINE_INFO, "Finding version for %s is not implemented yet.", tool); + // For other tools, we simply always auto-download them. + auto maybe_tool_data = parse_tool_data_from_xml(paths, tool); + if (auto p_tool_data = maybe_tool_data.get()) + { + if (paths.get_filesystem().exists(p_tool_data->exe_path)) + { + return {p_tool_data->exe_path, p_tool_data->sha512}; + } + return {fetch_tool(paths, tool, *p_tool_data), p_tool_data->sha512}; + } + + Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown or unavailable tool: %s", tool); }); } -- cgit v1.2.3 From 67643a0ea34aa58337680266024fecb9f04b3eb5 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 9 Aug 2019 10:29:02 -0700 Subject: [vcpkg] fix 7616 There's a bug in `std::experimental::filesystem::status` on libstdc++ -- it incorrectly sets its `error_code` when a file doesn't exist, or when a path doesn't exist. In order to get around this, `error_code` was cleared when the file doesn't exist, but it was not cleared when the path didn't exist. Note: in this case, I say "the file doesn't exist" when, if you look up "a/b/c", "a/b" exists but "c" doesn't. I say "the path doesn't exist" when, if you look up "a/b/c", either "a" or "a/b" doesn't exist. --- toolsrc/src/vcpkg/base/files.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 4a0a52f06..eb6119f18 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -78,7 +78,7 @@ namespace fs::detail #else auto result = symlink ? stdfs::symlink_status(p, ec) : stdfs::status(p, ec); // libstdc++ doesn't correctly not-set ec on nonexistent paths - if (ec.value() == ENOENT) + if (ec.value() == ENOENT || ec.value() == ENOTDIR) { ec.clear(); result = file_status(file_type::not_found, perms::unknown); -- cgit v1.2.3 From 0c7d8f414669c6e025794c374f2837e5fa24d02b Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Fri, 9 Aug 2019 14:21:58 -0700 Subject: Change purpose of this PR to just overriding the abi --- toolsrc/src/vcpkg/binaryparagraph.cpp | 59 ---------------- toolsrc/src/vcpkg/build.cpp | 128 +++++++++++----------------------- toolsrc/src/vcpkg/dependencies.cpp | 7 +- 3 files changed, 42 insertions(+), 152 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index ef194f9f3..231380b19 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -25,33 +25,6 @@ namespace vcpkg static const std::string MAINTAINER = "Maintainer"; static const std::string DEPENDS = "Depends"; static const std::string DEFAULTFEATURES = "Default-Features"; - static const std::string EXTERNALFILES = "External-Files"; - } - - bool BinaryParagraph::is_consistent() const - { - switch (consistency) - { - case ConsistencyState::UNKNOWN : - for (const auto& file_hash : external_files) - { - const auto& realfs = Files::get_real_filesystem(); - - if (!realfs.is_regular_file(file_hash.first) || - Hash::get_file_hash(realfs, file_hash.first, "SHA1") != file_hash.second) - { - consistency = ConsistencyState::INCONSISTENT; - return false; - } - } - - consistency = ConsistencyState::CONSISTENT; - return true; - case ConsistencyState::CONSISTENT : return true; - case ConsistencyState::INCONSISTENT : return false; - } - - Checks::unreachable(VCPKG_LINE_INFO); } BinaryParagraph::BinaryParagraph() = default; @@ -89,26 +62,6 @@ namespace vcpkg this->default_features = parse_comma_list(parser.optional_field(Fields::DEFAULTFEATURES)); } - std::vector external_files_or_hashes = - parse_comma_list(parser.optional_field(Fields::EXTERNALFILES)); - - if (external_files_or_hashes.size() % 2 != 0) - { - Checks::exit_with_message( - VCPKG_LINE_INFO, - "The External-Files field is not composed of key-value pairs for ", - this->spec); - } - - for (decltype(external_files_or_hashes)::size_type i = 0; - i < external_files_or_hashes.size(); - i += 2) - { - external_files.emplace( - std::move(external_files_or_hashes[i]), - std::move(external_files_or_hashes[i+1])); - } - if (const auto err = parser.error_info(this->spec.to_string())) { System::print2(System::Color::error, "Error: while parsing the Binary Paragraph for ", this->spec, '\n'); @@ -168,17 +121,5 @@ namespace vcpkg if (!pgh.maintainer.empty()) out_str.append("Maintainer: ").append(pgh.maintainer).push_back('\n'); if (!pgh.abi.empty()) out_str.append("Abi: ").append(pgh.abi).push_back('\n'); if (!pgh.description.empty()) out_str.append("Description: ").append(pgh.description).push_back('\n'); - - if (!pgh.external_files.empty()) - { - out_str.append("External-Files: "); - out_str.append(Strings::join(",", - Util::fmap( - pgh.external_files, - [](const std::pair& kv) - { - return kv.first.u8string() + "," + kv.second; - }))).push_back('\n'); - } } } diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 6f14f46f8..147bbe796 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -277,13 +277,6 @@ namespace vcpkg::Build bpgh.version = *p_ver; } - for (auto& file_hash : pre_build_info.external_files) - { - bpgh.external_files.emplace( - file_hash.first.u8string(), - std::move(file_hash.second)); - } - bcf->core_paragraph = std::move(bpgh); return bcf; } @@ -451,45 +444,6 @@ namespace vcpkg::Build return command; } - static std::vector> get_external_file_hashes( - const VcpkgPaths& paths, - const std::vector& files) - { - static std::map s_hash_cache; - - const auto& fs = paths.get_filesystem(); - - std::vector> hashes; - for (const fs::path& external_file : files) - { - auto it_hash = s_hash_cache.find(external_file); - - if (it_hash != s_hash_cache.end()) - { - hashes.emplace_back(external_file, it_hash->second); - } - else if (Files::get_real_filesystem().is_regular_file(external_file)) - { - auto emp = s_hash_cache.emplace( - external_file.u8string(), - Hash::get_file_hash( - Files::get_real_filesystem(), - external_file, "SHA1")); - - hashes.emplace_back(external_file.u8string(), emp.first->second); - } - else - { - Checks::exit_with_message( - VCPKG_LINE_INFO, - external_file.u8string() + - " was listed as an additional file for calculating the abi, but was not found."); - } - } - - return hashes; - } - static std::string get_triplet_abi(const VcpkgPaths& paths, const PreBuildInfo& pre_build_info, const Triplet& triplet) @@ -645,6 +599,15 @@ namespace vcpkg::Build const PreBuildInfo& pre_build_info, Span dependency_abis) { + if (pre_build_info.public_abi_override) + { + return AbiTagAndFile + { + "override", + pre_build_info.public_abi_override.value_or_exit(VCPKG_LINE_INFO) + }; + } + auto& fs = paths.get_filesystem(); const Triplet& triplet = config.triplet; const std::string& name = config.scf.core_paragraph->name; @@ -694,29 +657,6 @@ namespace vcpkg::Build } } - //Make a copy of the external file names and their hashes, and sort by - //hash. - std::vector> additional_file_hashes - = Util::fmap(pre_build_info.external_files, - [](const std::pair& file_hash) - { - return std::pair{ - file_hash.second, - file_hash.first.filename().u8string() - }; - }); - - std::sort(additional_file_hashes.begin(), additional_file_hashes.end()); - - for (auto& hash_file : additional_file_hashes) - { - abi_tag_entries.emplace_back( - AbiEntry{ - std::move(hash_file.second), - std::move(hash_file.first) - }); - } - abi_tag_entries.emplace_back(AbiEntry{"cmake", paths.get_tool_version(Tools::CMAKE)}); abi_tag_entries.emplace_back(AbiEntry{ @@ -835,11 +775,16 @@ namespace vcpkg::Build if (!required_fspecs.empty()) { - return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)}; + return { + BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, + std::move(required_fspecs) + }; } const PackageSpec spec = - PackageSpec::from_name_and_triplet(config.scf.core_paragraph->name, triplet).value_or_exit(VCPKG_LINE_INFO); + PackageSpec::from_name_and_triplet( + config.scf.core_paragraph->name, + triplet).value_or_exit(VCPKG_LINE_INFO); std::vector dependency_abis; @@ -856,15 +801,27 @@ namespace vcpkg::Build const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet, config.scfl); auto maybe_abi_tag_and_file = compute_abi_tag(paths, config, pre_build_info, dependency_abis); + if (!maybe_abi_tag_and_file) + { + return do_build_package_and_clean_buildtrees( + paths, + pre_build_info, + spec, + AbiTagAndFile{}.tag, + config); + } + std::error_code ec; const auto abi_tag_and_file = maybe_abi_tag_and_file.get(); const fs::path archives_root_dir = paths.root / "archives"; const std::string archive_name = abi_tag_and_file->tag + ".zip"; const fs::path archive_subpath = fs::u8path(abi_tag_and_file->tag.substr(0, 2)) / archive_name; const fs::path archive_path = archives_root_dir / archive_subpath; const fs::path archive_tombstone_path = archives_root_dir / "fail" / archive_subpath; + const fs::path abi_package_dir = paths.package_dir(spec) / "share" / spec.name(); + const fs::path abi_file_in_package = paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt"; - if (config.build_package_options.binary_caching == BinaryCaching::YES && abi_tag_and_file) + if (config.build_package_options.binary_caching == BinaryCaching::YES) { if (fs.exists(archive_path)) { @@ -900,20 +857,19 @@ namespace vcpkg::Build System::printf("Could not locate cached archive: %s\n", archive_path.u8string()); } + fs.create_directories(abi_package_dir, ec); + Checks::check_exit(VCPKG_LINE_INFO, !ec, "Coud not create directory %s", abi_package_dir.u8string()); + fs.copy_file(abi_tag_and_file->tag_file, abi_file_in_package, fs::stdfs::copy_options::none, ec); + Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string()); + ExtendedBuildResult result = do_build_package_and_clean_buildtrees( paths, pre_build_info, spec, - maybe_abi_tag_and_file.value_or(AbiTagAndFile{}).tag, + maybe_abi_tag_and_file.value_or_exit(VCPKG_LINE_INFO).tag, config); - std::error_code ec; - fs.create_directories(paths.package_dir(spec) / "share" / spec.name(), ec); - auto abi_file_in_package = paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt"; - fs.copy_file(abi_tag_and_file->tag_file, abi_file_in_package, fs::stdfs::copy_options::none, ec); - Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string()); - if (config.build_package_options.binary_caching == BinaryCaching::YES && result.code == BuildResult::SUCCEEDED) { @@ -1098,6 +1054,8 @@ namespace vcpkg::Build PreBuildInfo pre_build_info; + pre_build_info.port = port; + const auto e = lines.cend(); auto cur = std::find(lines.cbegin(), e, FLAG_GUID); if (cur != e) ++cur; @@ -1154,15 +1112,9 @@ namespace vcpkg::Build case VcpkgTripletVar::ENV_PASSTHROUGH : pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";"); break; - case VcpkgTripletVar::EXTERNAL_FILES : - pre_build_info.external_files = - get_external_file_hashes( - paths, - Util::fmap(Strings::split(variable_value, ";"), - [](const std::string& path) - { - return fs::path{path}; - })); + case VcpkgTripletVar::PUBLIC_ABI_OVERRIDE : + pre_build_info.public_abi_override = + variable_value.empty() ? nullopt : Optional{variable_value}; break; } } diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp index c175cc86f..8c8b2f810 100644 --- a/toolsrc/src/vcpkg/dependencies.cpp +++ b/toolsrc/src/vcpkg/dependencies.cpp @@ -663,16 +663,13 @@ namespace vcpkg::Dependencies if (auto p_installed = cluster.installed.get()) { - if (p_installed->original_features.find(feature) != p_installed->original_features.end() && - p_installed->ipv.core->package.is_consistent()) + if (p_installed->original_features.find(feature) != p_installed->original_features.end()) { return MarkPlusResult::SUCCESS; } } - //The feature was not previously installed or the external files of the - //port are no longer consistent with the last installation of this port - //(they've either been modified or removed). Mark the cluster + //The feature was not previously installed. Mark the cluster //(aka the entire port) to be removed before re-adding it. mark_minus(cluster, graph, graph_plan, prevent_default_features); -- cgit v1.2.3 From ad82c38cc1e8cc87f026cbd179e8bfaa62ce3553 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Fri, 9 Aug 2019 14:40:09 -0700 Subject: Actually only override the PUBLIC ABI, not the private one --- toolsrc/src/vcpkg/build.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index de8fbc752..7e14a0926 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -611,15 +611,6 @@ namespace vcpkg::Build const PreBuildInfo& pre_build_info, Span dependency_abis) { - if (pre_build_info.public_abi_override) - { - return AbiTagAndFile - { - "override", - pre_build_info.public_abi_override.value_or_exit(VCPKG_LINE_INFO) - }; - } - auto& fs = paths.get_filesystem(); const Triplet& triplet = config.triplet; const std::string& name = config.scf.core_paragraph->name; @@ -823,7 +814,7 @@ namespace vcpkg::Build paths, pre_build_info, spec, - AbiTagAndFile{}.tag, + pre_build_info.public_abi_override.value_or(AbiTagAndFile{}.tag), config); } @@ -883,7 +874,7 @@ namespace vcpkg::Build paths, pre_build_info, spec, - maybe_abi_tag_and_file.value_or_exit(VCPKG_LINE_INFO).tag, + pre_build_info.public_abi_override.value_or(abi_tag_and_file->tag), config); if (config.build_package_options.binary_caching == BinaryCaching::YES && @@ -1129,8 +1120,7 @@ namespace vcpkg::Build pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";"); break; case VcpkgTripletVar::PUBLIC_ABI_OVERRIDE : - pre_build_info.public_abi_override = - variable_value.empty() ? nullopt : Optional{variable_value}; + pre_build_info.public_abi_override = variable_value; break; } } -- cgit v1.2.3 From f0dd7b62964df89eb3cd50678f9a8ef98392be1d Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Fri, 9 Aug 2019 14:51:16 -0700 Subject: fix missing abi key mistake --- toolsrc/src/vcpkg/build.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 7e14a0926..385013b9b 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -1120,7 +1120,8 @@ namespace vcpkg::Build pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";"); break; case VcpkgTripletVar::PUBLIC_ABI_OVERRIDE : - pre_build_info.public_abi_override = variable_value; + pre_build_info.public_abi_override = + variable_value.empty() ? nullopt : Optional{variable_value}; break; } } -- cgit v1.2.3 From 5bd45366fb0558616a6cb46cdbca6810da5afa4c Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Fri, 9 Aug 2019 15:15:22 -0700 Subject: Add public abi override into the private abi --- toolsrc/src/vcpkg/build.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 385013b9b..1e5394593 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -675,6 +675,15 @@ namespace vcpkg::Build const std::string features = Strings::join(";", config.feature_list); abi_tag_entries.emplace_back(AbiEntry{"features", features}); + if (pre_build_info.public_abi_override) + { + abi_tag_entries.emplace_back( + AbiEntry{ + "public_abi_override", + pre_build_info.public_abi_override.value_or_exit(VCPKG_LINE_INFO) + }); + } + if (config.build_package_options.use_head_version == UseHeadVersion::YES) abi_tag_entries.emplace_back(AbiEntry{"head", ""}); -- cgit v1.2.3 From 52b2e740de81d58fbe5fa535c1f66aa82e80951e Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 9 Aug 2019 12:00:43 -0700 Subject: [vcpkg] Fix build under /W4 I was building under /W3, because CMake hadn't been set up to build under /W4 -- therefore, I didn't see some warnings. We also decided to remove the niebloids and instead break ADL by using `= delete`, since otherwise we get warnings when we define a local variable with the same name as a niebloid. I also removed `status` and `symlink_status` from the `files` header, since it's unnecessary now, and they're just implementation details of `RealFilesystem`. I also removed some existing uses of unqualified `status(path)`, since that no longer compiles. I also added `Filesystem::canonical`, to remove another use of `fs::stdfs` in a function I was already working in. --- toolsrc/src/vcpkg-test/files.cpp | 6 +- toolsrc/src/vcpkg-test/util.cpp | 6 +- toolsrc/src/vcpkg/base/files.cpp | 190 +++++++++++++++++++------------------ toolsrc/src/vcpkg/build.cpp | 2 +- toolsrc/src/vcpkg/dependencies.cpp | 3 +- toolsrc/src/vcpkg/vcpkgpaths.cpp | 5 +- 6 files changed, 111 insertions(+), 101 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/files.cpp b/toolsrc/src/vcpkg-test/files.cpp index a2faf455c..d40edb3bd 100644 --- a/toolsrc/src/vcpkg-test/files.cpp +++ b/toolsrc/src/vcpkg-test/files.cpp @@ -145,7 +145,7 @@ namespace CHECK_EC_ON_FILE(base, ec); } - vcpkg::Files::Filesystem& setup(urbg_t& urbg) + vcpkg::Files::Filesystem& setup() { auto& fs = vcpkg::Files::get_real_filesystem(); @@ -161,7 +161,7 @@ TEST_CASE ("remove all", "[files]") { auto urbg = get_urbg(0); - auto& fs = setup(urbg); + auto& fs = setup(); fs::path temp_dir = base_temporary_directory() / get_random_filename(urbg); INFO("temp dir is: " << temp_dir); @@ -181,7 +181,7 @@ TEST_CASE ("remove all", "[files]") TEST_CASE ("remove all -- benchmarks", "[files][!benchmark]") { auto urbg = get_urbg(1); - auto& fs = setup(urbg); + auto& fs = setup(); struct { diff --git a/toolsrc/src/vcpkg-test/util.cpp b/toolsrc/src/vcpkg-test/util.cpp index 384954b4e..379b253b1 100644 --- a/toolsrc/src/vcpkg-test/util.cpp +++ b/toolsrc/src/vcpkg-test/util.cpp @@ -141,7 +141,7 @@ namespace vcpkg::Test std::filesystem::path targetp = target.native(); std::filesystem::path filep = file.native(); - std::filesystem::create_symlink(targetp, filep); + std::filesystem::create_symlink(targetp, filep, ec); } else { @@ -153,6 +153,7 @@ namespace vcpkg::Test ec.assign(errno, std::system_category()); } #else + std::ignore = ec; vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, no_filesystem_message); #endif } @@ -165,7 +166,7 @@ namespace vcpkg::Test std::filesystem::path targetp = target.native(); std::filesystem::path filep = file.native(); - std::filesystem::create_directory_symlink(targetp, filep); + std::filesystem::create_directory_symlink(targetp, filep, ec); } else { @@ -174,6 +175,7 @@ namespace vcpkg::Test #elif FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_UNIX ::vcpkg::Test::create_symlink(target, file, ec); #else + std::ignore = ec; vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, no_filesystem_message); #endif } diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index eb6119f18..583adbbb8 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -21,114 +21,87 @@ #include #endif -namespace fs::detail +namespace vcpkg::Files { - static file_status status_implementation(bool follow_symlinks, const path& p, std::error_code& ec) + static const std::regex FILESYSTEM_INVALID_CHARACTERS_REGEX = std::regex(R"([\/:*?"<>|])"); + + namespace { -#if defined(_WIN32) - WIN32_FILE_ATTRIBUTE_DATA file_attributes; - file_type ft = file_type::unknown; - perms permissions = perms::unknown; - if (!GetFileAttributesExW(p.c_str(), GetFileExInfoStandard, &file_attributes)) + fs::file_status status_implementation(bool follow_symlinks, const fs::path& p, std::error_code& ec) noexcept { - const auto err = GetLastError(); - if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) + using fs::file_type; + using fs::perms; +#if defined(_WIN32) + WIN32_FILE_ATTRIBUTE_DATA file_attributes; + auto ft = file_type::unknown; + auto permissions = perms::unknown; + if (!GetFileAttributesExW(p.c_str(), GetFileExInfoStandard, &file_attributes)) { - ft = file_type::not_found; + const auto err = GetLastError(); + if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) + { + ft = file_type::not_found; + } + else + { + ec.assign(err, std::system_category()); + } } - else + else if (!follow_symlinks && file_attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - ec.assign(err, std::system_category()); + // this also gives junctions file_type::directory_symlink + if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + ft = file_type::directory_symlink; + } + else + { + ft = file_type::symlink; + } } - } - else if (!follow_symlinks && file_attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) - { - // this also gives junctions file_type::directory_symlink - if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + else if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - ft = file_type::directory_symlink; + ft = file_type::directory; } else { - ft = file_type::symlink; + // otherwise, the file is a regular file + ft = file_type::regular; } - } - else if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - ft = file_type::directory; - } - else - { - // otherwise, the file is a regular file - ft = file_type::regular; - } - if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_READONLY) - { - constexpr auto all_write = perms::group_write | perms::owner_write | perms::others_write; - permissions = perms::all & ~all_write; - } - else if (ft != file_type::none && ft != file_type::none) - { - permissions = perms::all; - } - - return file_status(ft, permissions); - -#else - auto result = symlink ? stdfs::symlink_status(p, ec) : stdfs::status(p, ec); - // libstdc++ doesn't correctly not-set ec on nonexistent paths - if (ec.value() == ENOENT || ec.value() == ENOTDIR) - { - ec.clear(); - result = file_status(file_type::not_found, perms::unknown); - } - return result; -#endif - } + if (file_attributes.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + { + constexpr auto all_write = perms::group_write | perms::owner_write | perms::others_write; + permissions = perms::all & ~all_write; + } + else if (ft != file_type::none && ft != file_type::none) + { + permissions = perms::all; + } - file_status status_t::operator()(const path& p, std::error_code& ec) const noexcept - { - return status_implementation(false, p, ec); - } - file_status status_t::operator()(vcpkg::LineInfo li, const path& p) const noexcept - { - std::error_code ec; - auto result = (*this)(p, ec); - if (ec) vcpkg::Checks::exit_with_message(li, "error getting status of path %s: %s", p.string(), ec.message()); + return fs::file_status(ft, permissions); - return result; - } - file_status status_t::operator()(const path& p) const - { -#if defined(_WIN32) - return (*this)(VCPKG_LINE_INFO, p); #else - return fs::stdfs::status(p); + auto result = symlink ? stdfs::symlink_status(p, ec) : stdfs::status(p, ec); + // libstdc++ doesn't correctly not-set ec on nonexistent paths + if (ec.value() == ENOENT || ec.value() == ENOTDIR) + { + ec.clear(); + result = fs::file_status(file_type::not_found, perms::unknown); + } + return result; #endif - } - - file_status symlink_status_t::operator()(const path& p, std::error_code& ec) const noexcept - { - return status_implementation(true, p, ec); - } - - file_status symlink_status_t::operator()(vcpkg::LineInfo li, const path& p) const noexcept - { - std::error_code ec; - auto result = (*this)(p, ec); - if (ec) vcpkg::Checks::exit_with_message(li, "error getting status of path %s: %s", p.string(), ec.message()); - - return result; - } -} + } -namespace vcpkg::Files -{ - static const std::regex FILESYSTEM_INVALID_CHARACTERS_REGEX = std::regex(R"([\/:*?"<>|])"); + fs::file_status status(const fs::path& p, std::error_code& ec) noexcept + { + return status_implementation(false, p, ec); + } + fs::file_status symlink_status(const fs::path& p, std::error_code& ec) noexcept + { + return status_implementation(false, p, ec); + } - namespace - { // does _not_ follow symlinks void set_writeable(const fs::path& path, std::error_code& ec) noexcept { @@ -220,6 +193,24 @@ namespace vcpkg::Files return exists(path, ec); } + fs::file_status Filesystem::status(vcpkg::LineInfo li, const fs::path& p) const noexcept + { + std::error_code ec; + auto result = this->status(p, ec); + if (ec) vcpkg::Checks::exit_with_message(li, "error getting status of path %s: %s", p.string(), ec.message()); + + return result; + } + + fs::file_status Filesystem::symlink_status(vcpkg::LineInfo li, const fs::path& p) const noexcept + { + std::error_code ec; + auto result = this->symlink_status(p, ec); + if (ec) vcpkg::Checks::exit_with_message(li, "error getting status of path %s: %s", p.string(), ec.message()); + + return result; + } + void Filesystem::write_lines(const fs::path& path, const std::vector& lines, LineInfo linfo) { std::error_code ec; @@ -244,6 +235,16 @@ namespace vcpkg::Files } } + fs::path Filesystem::canonical(LineInfo li, const fs::path& path) const + { + std::error_code ec; + + const auto result = this->canonical(path, ec); + + if (ec) Checks::exit_with_message(li, "Error getting canonicalization of %s: %s", path.string(), ec.message()); + return result; + } + struct RealFilesystem final : Filesystem { virtual Expected read_contents(const fs::path& file_path) const override @@ -463,7 +464,7 @@ namespace vcpkg::Files static void do_remove(const fs::path& current_path, ErrorInfo& err) { std::error_code ec; - const auto path_status = fs::symlink_status(current_path, ec); + const auto path_status = Files::symlink_status(current_path, ec); if (check_ec(ec, current_path, err)) return; if (!fs::exists(path_status)) return; @@ -593,11 +594,11 @@ namespace vcpkg::Files virtual fs::file_status status(const fs::path& path, std::error_code& ec) const override { - return fs::status(path, ec); + return Files::status(path, ec); } virtual fs::file_status symlink_status(const fs::path& path, std::error_code& ec) const override { - return fs::symlink_status(path, ec); + return Files::symlink_status(path, ec); } virtual void write_contents(const fs::path& file_path, const std::string& data, std::error_code& ec) override { @@ -628,6 +629,11 @@ namespace vcpkg::Files } } + virtual fs::path canonical(const fs::path& path, std::error_code& ec) const override + { + return fs::stdfs::canonical(path, ec); + } + virtual std::vector find_from_PATH(const std::string& name) const override { #if defined(_WIN32) diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 5b93242a1..b809db0bc 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -623,7 +623,7 @@ namespace vcpkg::Build std::vector port_files; for (auto& port_file : fs::stdfs::recursive_directory_iterator(config.port_dir)) { - if (fs::is_regular_file(status(port_file))) + if (fs::is_regular_file(fs.status(VCPKG_LINE_INFO, port_file))) { port_files.push_back(port_file); if (port_files.size() > max_port_file_count) diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp index 65c5cc985..9fccf950e 100644 --- a/toolsrc/src/vcpkg/dependencies.cpp +++ b/toolsrc/src/vcpkg/dependencies.cpp @@ -312,6 +312,7 @@ namespace vcpkg::Dependencies const std::vector* ports_dirs_paths) : filesystem(paths.get_filesystem()) { + auto& fs = Files::get_real_filesystem(); if (ports_dirs_paths) { for (auto&& overlay_path : *ports_dirs_paths) @@ -326,7 +327,7 @@ namespace vcpkg::Dependencies overlay.string()); Checks::check_exit(VCPKG_LINE_INFO, - fs::is_directory(status(overlay)), + fs::is_directory(fs.status(VCPKG_LINE_INFO, overlay)), "Error: Path \"%s\" must be a directory", overlay.string()); diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index c5b5749ff..bc46d2cfc 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -18,8 +18,9 @@ namespace vcpkg const std::string& default_vs_path, const std::vector* triplets_dirs) { + auto& fs = Files::get_real_filesystem(); std::error_code ec; - const fs::path canonical_vcpkg_root_dir = fs::stdfs::canonical(vcpkg_root_dir, ec); + const fs::path canonical_vcpkg_root_dir = fs.canonical(vcpkg_root_dir, ec); if (ec) { return ec; @@ -42,7 +43,7 @@ namespace vcpkg if (auto odp = overriddenDownloadsPath.get()) { auto asPath = fs::u8path(*odp); - if (!fs::is_directory(status(asPath))) + if (!fs::is_directory(fs.status(VCPKG_LINE_INFO, asPath))) { Metrics::g_metrics.lock()->track_property("error", "Invalid VCPKG_DOWNLOADS override directory."); Checks::exit_with_message( -- cgit v1.2.3 From a6ae888f4ef69cda5212e7459debf6b620fa4a69 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 9 Aug 2019 12:21:25 -0700 Subject: fix the build on unix --- toolsrc/src/vcpkg/base/files.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 583adbbb8..7c29c8e10 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -82,14 +82,14 @@ namespace vcpkg::Files return fs::file_status(ft, permissions); #else - auto result = symlink ? stdfs::symlink_status(p, ec) : stdfs::status(p, ec); + auto result = symlink ? fs::stdfs::symlink_status(p, ec) : fs::stdfs::status(p, ec); // libstdc++ doesn't correctly not-set ec on nonexistent paths if (ec.value() == ENOENT || ec.value() == ENOTDIR) { ec.clear(); - result = fs::file_status(file_type::not_found, perms::unknown); + return fs::file_status(file_type::not_found, perms::unknown); } - return result; + return fs::file_status(result.type(), result.permissions()); #endif } -- cgit v1.2.3 From 58f95cc856cdb026eeadeb29d30e5ea2fd5b252c Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Sat, 10 Aug 2019 12:25:22 -0700 Subject: fix two bugs in status --- toolsrc/src/vcpkg/base/files.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 7c29c8e10..bbf37fd25 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -82,7 +82,7 @@ namespace vcpkg::Files return fs::file_status(ft, permissions); #else - auto result = symlink ? fs::stdfs::symlink_status(p, ec) : fs::stdfs::status(p, ec); + auto result = follow_symlinks ? fs::stdfs::status(p, ec) : fs::stdfs::symlink_status(p, ec); // libstdc++ doesn't correctly not-set ec on nonexistent paths if (ec.value() == ENOENT || ec.value() == ENOTDIR) { @@ -95,7 +95,7 @@ namespace vcpkg::Files fs::file_status status(const fs::path& p, std::error_code& ec) noexcept { - return status_implementation(false, p, ec); + return status_implementation(true, p, ec); } fs::file_status symlink_status(const fs::path& p, std::error_code& ec) noexcept { -- cgit v1.2.3 From 29ddf1a5c2711161a5642ab515f6cae5f01ca3e9 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Sat, 10 Aug 2019 12:27:49 -0700 Subject: remove clever use of std::ignore --- toolsrc/src/vcpkg-test/util.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/util.cpp b/toolsrc/src/vcpkg-test/util.cpp index 379b253b1..a2343c21b 100644 --- a/toolsrc/src/vcpkg-test/util.cpp +++ b/toolsrc/src/vcpkg-test/util.cpp @@ -153,7 +153,7 @@ namespace vcpkg::Test ec.assign(errno, std::system_category()); } #else - std::ignore = ec; + static_cast(ec); vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, no_filesystem_message); #endif } @@ -175,7 +175,7 @@ namespace vcpkg::Test #elif FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_UNIX ::vcpkg::Test::create_symlink(target, file, ec); #else - std::ignore = ec; + static_cast(ec); vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, no_filesystem_message); #endif } -- cgit v1.2.3 From 5c11033ad7a52960500c8b604a4b7e7b4fb2a1b3 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Mon, 12 Aug 2019 10:22:05 -0700 Subject: Fix formatting, hash override, don't move pre_build_info --- toolsrc/src/vcpkg/binaryparagraph.cpp | 1 - toolsrc/src/vcpkg/build.cpp | 85 ++++++++++++----------------------- 2 files changed, 28 insertions(+), 58 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index 231380b19..b4cd9cc4b 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 1e5394593..e0dc603ea 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -263,12 +263,11 @@ namespace vcpkg::Build return BinaryParagraph(source_paragraph, feature_paragraph, triplet); } - static std::unique_ptr create_binary_control_file( - const SourceParagraph& source_paragraph, - const Triplet& triplet, - const BuildInfo& build_info, - const PreBuildInfo& pre_build_info, - const std::string& abi_tag) + static std::unique_ptr create_binary_control_file(const SourceParagraph& source_paragraph, + const Triplet& triplet, + const BuildInfo& build_info, + const PreBuildInfo& pre_build_info, + const std::string& abi_tag) { auto bcf = std::make_unique(); BinaryParagraph bpgh(source_paragraph, triplet, abi_tag); @@ -554,12 +553,7 @@ namespace vcpkg::Build PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info, config.port_dir); std::unique_ptr bcf = - create_binary_control_file( - *config.scf.core_paragraph, - triplet, - build_info, - std::move(pre_build_info), - abi_tag); + create_binary_control_file(*config.scf.core_paragraph, triplet, build_info, pre_build_info, abi_tag); if (error_count != 0) { @@ -632,9 +626,8 @@ namespace vcpkg::Build { if (fs::is_regular_file(status(port_file))) { - hashes_files.emplace_back( - vcpkg::Hash::get_file_hash(fs, port_file, "SHA1"), - port_file.path().filename().u8string()); + hashes_files.emplace_back(vcpkg::Hash::get_file_hash(fs, port_file, "SHA1"), + port_file.path().filename().u8string()); if (hashes_files.size() > max_port_file_count) { @@ -652,16 +645,12 @@ namespace vcpkg::Build { // We've already sorted by hash so it's safe to write down the // filename, which will be consistent across machines. - abi_tag_entries.emplace_back( - AbiEntry{ - std::move(hash_file.second), - std::move(hash_file.first) - }); + abi_tag_entries.emplace_back(AbiEntry{std::move(hash_file.second), std::move(hash_file.first)}); } } abi_tag_entries.emplace_back(AbiEntry{"cmake", paths.get_tool_version(Tools::CMAKE)}); - + #if defined(_WIN32) abi_tag_entries.emplace_back(AbiEntry{"powershell", paths.get_tool_version("powershell-core")}); #endif @@ -677,11 +666,9 @@ namespace vcpkg::Build if (pre_build_info.public_abi_override) { - abi_tag_entries.emplace_back( - AbiEntry{ - "public_abi_override", - pre_build_info.public_abi_override.value_or_exit(VCPKG_LINE_INFO) - }); + abi_tag_entries.emplace_back(AbiEntry{ + "public_abi_override", + Hash::get_string_hash(pre_build_info.public_abi_override.value_or_exit(VCPKG_LINE_INFO), "SHA1")}); } if (config.build_package_options.use_head_version == UseHeadVersion::YES) @@ -791,16 +778,11 @@ namespace vcpkg::Build if (!required_fspecs.empty()) { - return { - BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, - std::move(required_fspecs) - }; + return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)}; } const PackageSpec spec = - PackageSpec::from_name_and_triplet( - config.scf.core_paragraph->name, - triplet).value_or_exit(VCPKG_LINE_INFO); + PackageSpec::from_name_and_triplet(config.scf.core_paragraph->name, triplet).value_or_exit(VCPKG_LINE_INFO); std::vector dependency_abis; @@ -820,11 +802,7 @@ namespace vcpkg::Build if (!maybe_abi_tag_and_file) { return do_build_package_and_clean_buildtrees( - paths, - pre_build_info, - spec, - pre_build_info.public_abi_override.value_or(AbiTagAndFile{}.tag), - config); + paths, pre_build_info, spec, pre_build_info.public_abi_override.value_or(AbiTagAndFile{}.tag), config); } std::error_code ec; @@ -878,16 +856,10 @@ namespace vcpkg::Build fs.copy_file(abi_tag_and_file->tag_file, abi_file_in_package, fs::stdfs::copy_options::none, ec); Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string()); - ExtendedBuildResult result = - do_build_package_and_clean_buildtrees( - paths, - pre_build_info, - spec, - pre_build_info.public_abi_override.value_or(abi_tag_and_file->tag), - config); + ExtendedBuildResult result = do_build_package_and_clean_buildtrees( + paths, pre_build_info, spec, pre_build_info.public_abi_override.value_or(abi_tag_and_file->tag), config); - if (config.build_package_options.binary_caching == BinaryCaching::YES && - result.code == BuildResult::SUCCEEDED) + if (config.build_package_options.binary_caching == BinaryCaching::YES && result.code == BuildResult::SUCCEEDED) { const auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip"); @@ -898,16 +870,15 @@ namespace vcpkg::Build if (ec) { System::printf(System::Color::warning, - "Failed to store binary cache %s: %s\n", - archive_path.u8string(), - ec.message()); + "Failed to store binary cache %s: %s\n", + archive_path.u8string(), + ec.message()); } else System::printf("Stored binary cache: %s\n", archive_path.u8string()); } else if (config.build_package_options.binary_caching == BinaryCaching::YES && - (result.code == BuildResult::BUILD_FAILED || - result.code == BuildResult::POST_BUILD_CHECKS_FAILED)) + (result.code == BuildResult::BUILD_FAILED || result.code == BuildResult::POST_BUILD_CHECKS_FAILED)) { if (!fs.exists(archive_tombstone_path)) { @@ -922,9 +893,9 @@ namespace vcpkg::Build if (log_file.path().extension() == ".log") { fs.copy_file(log_file.path(), - tmp_log_path_destination / log_file.path().filename(), - fs::stdfs::copy_options::none, - ec); + tmp_log_path_destination / log_file.path().filename(), + fs::stdfs::copy_options::none, + ec); } } @@ -1125,10 +1096,10 @@ namespace vcpkg::Build Checks::exit_with_message( VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value); break; - case VcpkgTripletVar::ENV_PASSTHROUGH : + case VcpkgTripletVar::ENV_PASSTHROUGH: pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";"); break; - case VcpkgTripletVar::PUBLIC_ABI_OVERRIDE : + case VcpkgTripletVar::PUBLIC_ABI_OVERRIDE: pre_build_info.public_abi_override = variable_value.empty() ? nullopt : Optional{variable_value}; break; -- cgit v1.2.3 From 44e08d28e777faa08a773054b2dac2d5cf949569 Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Mon, 12 Aug 2019 11:19:16 -0700 Subject: remove uneeded header --- toolsrc/src/vcpkg/binaryparagraph.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/binaryparagraph.cpp b/toolsrc/src/vcpkg/binaryparagraph.cpp index b4cd9cc4b..8b1886098 100644 --- a/toolsrc/src/vcpkg/binaryparagraph.cpp +++ b/toolsrc/src/vcpkg/binaryparagraph.cpp @@ -1,7 +1,6 @@ #include "pch.h" #include -#include #include #include #include -- cgit v1.2.3 From c605f4eea632878dc495fd280a41734bd14e851f Mon Sep 17 00:00:00 2001 From: "Curtis.Bezault" Date: Mon, 12 Aug 2019 11:40:03 -0700 Subject: drop uneeded parameter from create_binary_control_file --- toolsrc/src/vcpkg/build.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index e0dc603ea..199a7db1a 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -266,7 +266,6 @@ namespace vcpkg::Build static std::unique_ptr create_binary_control_file(const SourceParagraph& source_paragraph, const Triplet& triplet, const BuildInfo& build_info, - const PreBuildInfo& pre_build_info, const std::string& abi_tag) { auto bcf = std::make_unique(); @@ -553,7 +552,7 @@ namespace vcpkg::Build PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info, config.port_dir); std::unique_ptr bcf = - create_binary_control_file(*config.scf.core_paragraph, triplet, build_info, pre_build_info, abi_tag); + create_binary_control_file(*config.scf.core_paragraph, triplet, build_info, abi_tag); if (error_count != 0) { -- cgit v1.2.3 From 875648e10b2e5b5dfba6be75997171f10cb868ed Mon Sep 17 00:00:00 2001 From: nicole mazzuca Date: Mon, 12 Aug 2019 14:02:59 -0700 Subject: [vcpkg] Fix the build on VS2015 debug (#7637) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VS2015 standard library requires, in debug mode, a comparison operator on `T × U` and `U × T` to also be a comparison operator on `T × T` and on `U × U`, and so in vcpkg::Install::install_package::intersection_compare, I've added two new `operator()` overloads which take those respectively, on VS2015. Also, `[nodiscard]` was added to somewhere in `vcpkg/base/strings.h`, which gives a warning in VS2015 -- thus, I added the `vcpkg/pragmas.h` include, since that fixes the warning. --- toolsrc/src/vcpkg/install.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 165f13126..974e5f798 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -202,6 +202,12 @@ namespace vcpkg::Install struct intersection_compare { + // The VS2015 standard library requires comparison operators of T and U + // to also support comparison of T and T, and of U and U, due to debug checks. +#if _MSC_VER < 1910 + bool operator()(const std::string& lhs, const std::string& rhs) { return lhs < rhs; } + bool operator()(const file_pack& lhs, const file_pack& rhs) { return lhs.first < rhs.first; } +#endif bool operator()(const std::string& lhs, const file_pack& rhs) { return lhs < rhs.first; } bool operator()(const file_pack& lhs, const std::string& rhs) { return lhs.first < rhs; } }; -- cgit v1.2.3 From f9c92910a7d0ee328aaeead71c8a5c59a1189a97 Mon Sep 17 00:00:00 2001 From: Alexander Neumann <30894796+Neumann-A@users.noreply.github.com> Date: Wed, 14 Aug 2019 23:06:00 +0200 Subject: Change CMakeLists.txt in toolsrc to allow compiling with llvm toolset (#4572) * llvm warning pessimistic move * warning missing override * warning invalid noreturn. ::TerminateProcess ist not marked as noreturn! * use more modern cmake features instead of adding c++ standard by hand. * Normalize line endings * Fix add_executable() * Fix target commands * Clean up CMakeLists.txt --- toolsrc/src/vcpkg/base/checks.cpp | 3 +-- toolsrc/src/vcpkg/install.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/checks.cpp b/toolsrc/src/vcpkg/base/checks.cpp index 0266ad683..c7584258a 100644 --- a/toolsrc/src/vcpkg/base/checks.cpp +++ b/toolsrc/src/vcpkg/base/checks.cpp @@ -27,9 +27,8 @@ namespace vcpkg #if defined(_WIN32) ::TerminateProcess(::GetCurrentProcess(), exit_code); -#else - std::exit(exit_code); #endif + std::exit(exit_code); } void Checks::unreachable(const LineInfo& line_info) diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 974e5f798..f6330e408 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -174,7 +174,7 @@ namespace vcpkg::Install const std::vector package_file_paths = fs.get_files_recursive(package_dir); const size_t package_remove_char_count = package_dir.generic_string().size() + 1; // +1 for the slash auto package_files = Util::fmap(package_file_paths, [package_remove_char_count](const fs::path& path) { - return std::move(std::string(path.generic_string(), package_remove_char_count)); + return std::move(std::string(path.generic_string(), package_remove_char_count)); }); return SortedVector(std::move(package_files)); -- cgit v1.2.3 From edaf3bf91e6b3c33943d5006f6b34fe98b18e1d9 Mon Sep 17 00:00:00 2001 From: Victor Romero Date: Wed, 14 Aug 2019 15:38:07 -0700 Subject: [depend-info] Fix bugs, add `--sort`, `--show-depth` and `--max-recurse` options (#7643) * [depend-info] Follow same rules as vcpkg install * [depend-info] Add --max-depth and --sort options * [depend-info] Improve output readability (a tiny bit) * [depend-info] Add --show-depth option * [depend-info] Fix build on VS 2015 * [depend-info] Fix output of --dot and --dgml --- toolsrc/src/vcpkg/commands.cpp | 2 +- toolsrc/src/vcpkg/commands.dependinfo.cpp | 343 ++++++++++++++++++------------ 2 files changed, 209 insertions(+), 136 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/commands.cpp b/toolsrc/src/vcpkg/commands.cpp index 54e9346ba..3ac568979 100644 --- a/toolsrc/src/vcpkg/commands.cpp +++ b/toolsrc/src/vcpkg/commands.cpp @@ -24,6 +24,7 @@ namespace vcpkg::Commands {"env", &Env::perform_and_exit}, {"build-external", &BuildExternal::perform_and_exit}, {"export", &Export::perform_and_exit}, + {"depend-info", &DependInfo::perform_and_exit}, }; return t; } @@ -38,7 +39,6 @@ namespace vcpkg::Commands {"integrate", &Integrate::perform_and_exit}, {"owns", &Owns::perform_and_exit}, {"update", &Update::perform_and_exit}, - {"depend-info", &DependInfo::perform_and_exit}, {"edit", &Edit::perform_and_exit}, {"create", &Create::perform_and_exit}, {"import", &Import::perform_and_exit}, diff --git a/toolsrc/src/vcpkg/commands.dependinfo.cpp b/toolsrc/src/vcpkg/commands.dependinfo.cpp index 7c04a5a2f..8ca88dd56 100644 --- a/toolsrc/src/vcpkg/commands.dependinfo.cpp +++ b/toolsrc/src/vcpkg/commands.dependinfo.cpp @@ -4,65 +4,129 @@ #include #include #include +#include #include +#include +#include #include -#include - -#include -#include #include +using vcpkg::Dependencies::AnyAction; +using vcpkg::Dependencies::create_feature_install_plan; +using vcpkg::Dependencies::InstallPlanAction; using vcpkg::Dependencies::PathsPortFileProvider; namespace vcpkg::Commands::DependInfo { constexpr StringLiteral OPTION_DOT = "--dot"; constexpr StringLiteral OPTION_DGML = "--dgml"; - constexpr StringLiteral OPTION_NO_RECURSE = "--no-recurse"; + constexpr StringLiteral OPTION_SHOW_DEPTH = "--show-depth"; + constexpr StringLiteral OPTION_MAX_RECURSE = "--max-recurse"; + constexpr StringLiteral OPTION_SORT = "--sort"; + + constexpr int NO_RECURSE_LIMIT_VALUE = -1; + + constexpr std::array DEPEND_SWITCHES = {{{OPTION_DOT, "Creates graph on basis of dot"}, + {OPTION_DGML, "Creates graph on basis of dgml"}, + {OPTION_SHOW_DEPTH, "Show recursion depth in output"}}}; - constexpr std::array DEPEND_SWITCHES = {{ - {OPTION_DOT, "Creates graph on basis of dot"}, - {OPTION_DGML, "Creates graph on basis of dgml"}, - {OPTION_NO_RECURSE, - "Computes only immediate dependencies of packages explicitly specified on the command-line"}, - }}; + constexpr std::array DEPEND_SETTINGS = { + {{OPTION_MAX_RECURSE, "Set max recursion depth, a value of -1 indicates no limit"}, + {OPTION_SORT, + "Set sort order for the list of dependencies, accepted values are: lexicographical, topological (default), " + "reverse"}}}; const CommandStructure COMMAND_STRUCTURE = { - Help::create_example_string(R"###(depend-info [pat])###"), + Help::create_example_string("depend-info sqlite3"), 0, SIZE_MAX, - {DEPEND_SWITCHES, {}}, + {DEPEND_SWITCHES, DEPEND_SETTINGS}, nullptr, }; - std::string replace_dashes_with_underscore(const std::string& input) + struct PackageDependInfo { - std::string output = input; - std::replace(output.begin(), output.end(), '-', '_'); - return output; + std::string package; + int depth; + std::set features; + std::vector dependencies; + }; + + enum SortMode + { + Lexicographical = 0, + Topological, + ReverseTopological, + Default = Topological + }; + + int get_max_depth(const ParsedArguments& options) + { + auto iter = options.settings.find(OPTION_MAX_RECURSE); + if (iter != options.settings.end()) + { + std::string value = iter->second; + try + { + return std::stoi(value); + } + catch (std::exception&) + { + Checks::exit_with_message(VCPKG_LINE_INFO, "Value of --max-depth must be an integer"); + } + } + // No --max-depth set, default to no limit. + return NO_RECURSE_LIMIT_VALUE; } - std::string create_dot_as_string(const std::vector& source_control_files) + SortMode get_sort_mode(const ParsedArguments& options) + { + constexpr StringLiteral OPTION_SORT_LEXICOGRAPHICAL = "lexicographical"; + constexpr StringLiteral OPTION_SORT_TOPOLOGICAL = "topological"; + constexpr StringLiteral OPTION_SORT_REVERSE = "reverse"; + + static const std::map sortModesMap{{OPTION_SORT_LEXICOGRAPHICAL, Lexicographical}, + {OPTION_SORT_TOPOLOGICAL, Topological}, + {OPTION_SORT_REVERSE, ReverseTopological}}; + + auto iter = options.settings.find(OPTION_SORT); + if (iter != options.settings.end()) + { + const std::string value = Strings::ascii_to_lowercase(std::string{iter->second}); + auto it = sortModesMap.find(value); + if (it != sortModesMap.end()) + { + return it->second; + } + Checks::exit_with_message(VCPKG_LINE_INFO, + "Value of --sort must be one of `%s`, `%s`, or `%s`", + OPTION_SORT_LEXICOGRAPHICAL, + OPTION_SORT_TOPOLOGICAL, + OPTION_SORT_REVERSE); + } + return Default; + } + + std::string create_dot_as_string(const std::vector& depend_info) { int empty_node_count = 0; std::string s; s.append("digraph G{ rankdir=LR; edge [minlen=3]; overlap=false;"); - for (const auto& source_control_file : source_control_files) + for (const auto& package : depend_info) { - const SourceParagraph& source_paragraph = *source_control_file->core_paragraph; - if (source_paragraph.depends.empty()) + if (package.dependencies.empty()) { empty_node_count++; continue; } - const std::string name = replace_dashes_with_underscore(source_paragraph.name); + const std::string name = Strings::replace_all(std::string{ package.package }, "-", "_"); s.append(Strings::format("%s;", name)); - for (const Dependency& d : source_paragraph.depends) + for (const auto &d : package.dependencies) { - const std::string dependency_name = replace_dashes_with_underscore(d.depend.name); + const std::string dependency_name = Strings::replace_all(std::string{ d }, "-", "_"); s.append(Strings::format("%s -> %s;", name, dependency_name)); } } @@ -71,39 +135,22 @@ namespace vcpkg::Commands::DependInfo return s; } - std::string create_dgml_as_string(const std::vector& source_control_files) + std::string create_dgml_as_string(const std::vector& depend_info) { std::string s; s.append(""); s.append(""); std::string nodes, links; - for (const auto& source_control_file : source_control_files) + for (const auto& package : depend_info) { - const SourceParagraph& source_paragraph = *source_control_file->core_paragraph; - const std::string name = source_paragraph.name; + const std::string name = package.package; nodes.append(Strings::format("", name)); // Iterate over dependencies. - for (const Dependency& d : source_paragraph.depends) - { - if (d.qualifier.empty()) - links.append(Strings::format("", name, d.depend.name)); - else - links.append(Strings::format( - "", name, d.depend.name)); - } - - // Iterate over feature dependencies. - const std::vector>& feature_paragraphs = - source_control_file->feature_paragraphs; - for (const auto& feature_paragraph : feature_paragraphs) + for (const auto& d : package.dependencies) { - for (const Dependency& d : feature_paragraph->depends) - { - links.append(Strings::format( - "", name, d.depend.name)); - } + links.append(Strings::format("", name, d)); } } @@ -116,136 +163,162 @@ namespace vcpkg::Commands::DependInfo } std::string create_graph_as_string(const std::unordered_set& switches, - const std::vector& source_control_files) + const std::vector& depend_info) { if (Util::Sets::contains(switches, OPTION_DOT)) { - return create_dot_as_string(source_control_files); + return create_dot_as_string(depend_info); } else if (Util::Sets::contains(switches, OPTION_DGML)) { - return create_dgml_as_string(source_control_files); + return create_dgml_as_string(depend_info); } return ""; } - void build_dependencies_list(std::set& packages_to_keep, - const std::string& requested_package, - const std::vector& source_control_files, - const std::unordered_set& switches) + void assign_depth_to_dependencies(const std::string& package, + const int depth, + const int max_depth, + std::map& dependencies_map) { - auto maybe_requested_spec = ParsedSpecifier::from_string(requested_package); - // TODO: move this check to the top-level invocation of this function since - // argument `requested_package` shall always be valid in inner-level invocation. - if (!maybe_requested_spec.has_value()) - { - System::print2(System::Color::warning, - "'", - requested_package, - "' is not a valid package specifier: ", - vcpkg::to_string(maybe_requested_spec.error()), - "\n"); - return; - } - auto requested_spec = maybe_requested_spec.get(); + auto iter = dependencies_map.find(package); + Checks::check_exit(VCPKG_LINE_INFO, iter != dependencies_map.end(), "Package not found in dependency graph"); - const auto source_control_file = - Util::find_if(source_control_files, [&requested_spec](const auto& source_control_file) { - return source_control_file->core_paragraph->name == requested_spec->name; - }); + PackageDependInfo& info = iter->second; - if (source_control_file != source_control_files.end()) + if (depth > info.depth) { - const auto new_package = packages_to_keep.insert(requested_spec->name).second; - - if (new_package && !Util::Sets::contains(switches, OPTION_NO_RECURSE)) + info.depth = depth; + if (depth < max_depth || max_depth == NO_RECURSE_LIMIT_VALUE) { - for (const auto& dependency : (*source_control_file)->core_paragraph->depends) - { - build_dependencies_list(packages_to_keep, dependency.depend.name, source_control_files, switches); - } - - // Collect features with `*` considered - std::set collected_features; - for (const auto& requested_feature_name : requested_spec->features) + for (auto&& dependency : info.dependencies) { - if (requested_feature_name == "*") - { - for (auto&& feature_paragraph : (*source_control_file)->feature_paragraphs) - { - collected_features.insert(std::addressof(Util::as_const(*feature_paragraph))); - } - continue; - } - auto maybe_feature = (*source_control_file)->find_feature(requested_feature_name); - if (auto&& feature_paragraph = maybe_feature.get()) - { - collected_features.insert(std::addressof(Util::as_const(*feature_paragraph))); - } - else - { - System::print2(System::Color::warning, - "dependency '", - requested_feature_name, - "' of package '", - requested_spec->name, - "' does not exist\n"); - continue; - } - } - for (auto feature_paragraph : collected_features) - { - for (const auto& dependency : feature_paragraph->depends) - { - build_dependencies_list( - packages_to_keep, dependency.depend.name, source_control_files, switches); - } + assign_depth_to_dependencies(dependency, depth + 1, max_depth, dependencies_map); } } } - else + }; + + std::vector extract_depend_info(const std::vector& install_actions, + const int max_depth) + { + std::map package_dependencies; + for (const InstallPlanAction* pia : install_actions) { - System::print2(System::Color::warning, "package '", requested_package, "' does not exist\n"); + const InstallPlanAction& install_action = *pia; + + const std::vector dependencies = + Util::fmap(install_action.computed_dependencies, [](const PackageSpec& spec) { return spec.name(); }); + + std::set features{install_action.feature_list}; + features.erase("core"); + + std::string port_name = install_action.spec.name(); + + PackageDependInfo info {port_name, -1, features, dependencies}; + package_dependencies.emplace(port_name, std::move(info)); } + + const InstallPlanAction& init = *install_actions.back(); + assign_depth_to_dependencies(init.spec.name(), 0, max_depth, package_dependencies); + + std::vector out = + Util::fmap(package_dependencies, [](auto&& kvpair) -> PackageDependInfo { return kvpair.second; }); + Util::erase_remove_if(out, [](auto&& info) { return info.depth < 0; }); + return out; } - void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet) { const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); + const int max_depth = get_max_depth(options); + const SortMode sort_mode = get_sort_mode(options); + const bool show_depth = Util::Sets::contains(options.switches, OPTION_SHOW_DEPTH); - // TODO: Optimize implementation, current implementation needs to load all ports from disk which is too slow. - PathsPortFileProvider provider(paths, args.overlay_ports.get()); - auto source_control_files = - Util::fmap(provider.load_all_control_files(), - [](auto&& scfl) -> const SourceControlFile* { return scfl->source_control_file.get(); }); + const std::vector 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); + }); - if (args.command_arguments.size() >= 1) + for (auto&& spec : specs) { - std::set packages_to_keep; - for (const auto& requested_package : args.command_arguments) + Input::check_triplet(spec.package_spec.triplet(), paths); + } + + PathsPortFileProvider provider(paths, args.overlay_ports.get()); + + // By passing an empty status_db, we should get a plan containing all dependencies. + // All actions in the plan should be install actions, as there's no installed packages to remove. + StatusParagraphs status_db; + std::vector action_plan = + create_feature_install_plan(provider, FullPackageSpec::to_feature_specs(specs), status_db); + std::vector install_actions = Util::fmap(action_plan, [&](const AnyAction& action) { + if (auto install_action = action.install_action.get()) { - build_dependencies_list(packages_to_keep, requested_package, source_control_files, options.switches); + return install_action; } + Checks::exit_with_message(VCPKG_LINE_INFO, "Only install actions should exist in the plan"); + }); - Util::erase_remove_if(source_control_files, [&packages_to_keep](const auto& source_control_file) { - return !Util::Sets::contains(packages_to_keep, source_control_file->core_paragraph->name); - }); - } + std::vector depend_info = extract_depend_info(install_actions, max_depth); if (Util::Sets::contains(options.switches, OPTION_DOT) || Util::Sets::contains(options.switches, OPTION_DGML)) { - const std::string graph_as_string = create_graph_as_string(options.switches, source_control_files); + const std::vector source_control_files = + Util::fmap(install_actions, [](const InstallPlanAction* install_action) { + const SourceControlFileLocation& scfl = + install_action->source_control_file_location.value_or_exit(VCPKG_LINE_INFO); + return const_cast(scfl.source_control_file.get()); + }); + + const std::string graph_as_string = create_graph_as_string(options.switches, depend_info); System::print2(graph_as_string, '\n'); Checks::exit_success(VCPKG_LINE_INFO); } - for (auto&& source_control_file : source_control_files) + + // TODO: Improve this code + auto lex = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool { + return lhs.package < rhs.package; + }; + auto topo = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool { + return lhs.depth > rhs.depth; + }; + auto reverse = [topo](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool { + return lhs.depth < rhs.depth; + }; + + switch (sort_mode) { - const SourceParagraph& source_paragraph = *source_control_file->core_paragraph.get(); - const auto s = Strings::join(", ", source_paragraph.depends, [](const Dependency& d) { return d.name(); }); - System::print2(source_paragraph.name, ": ", s, "\n"); + case SortMode::Lexicographical: std::sort(std::begin(depend_info), std::end(depend_info), lex); break; + case SortMode::ReverseTopological: + std::sort(std::begin(depend_info), std::end(depend_info), reverse); + break; + case SortMode::Topological: std::sort(std::begin(depend_info), std::end(depend_info), topo); break; + default: Checks::unreachable(VCPKG_LINE_INFO); } + for (auto&& info : depend_info) + { + if (info.depth >= 0) + { + std::string features = Strings::join(", ", info.features); + const std::string dependencies = Strings::join(", ", info.dependencies); + + if (show_depth) + { + System::print2(System::Color::error, "(", info.depth, ") "); + } + System::print2(System::Color::success, info.package); + if (!features.empty()) + { + System::print2("["); + System::print2(System::Color::warning, features); + System::print2("]"); + } + System::print2(": ", dependencies, "\n"); + } + } Checks::exit_success(VCPKG_LINE_INFO); } } -- cgit v1.2.3 From 300e21d59ebfe42e118cf4e97887f0680fbcfa2f Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 9 Aug 2019 11:16:35 -0700 Subject: [vcpkg] Major tool CMakeLists.txt updates - Add the "VCPKG_DEVELOPMENT_WARNINGS" flag - setting "WERROR" will also set this flag - This flag is set by default - on GCC/clang, this will pass '-Wall -Wextra -Wpedantic -Werror' - on GCC, this will additionally pass '-Wmissing-declarations' - on clang, this will additionally pass '-Wmissing-prototypes' - on MSVC, this will pass '-W4 -WX' - On Visual Studio 2017 and later, pass '-permissive-' - Change the source for fallout of these changes - add `format` subcommand - formats all C++ source and header files using clang-format - move `include/vcpkg-test/catch.h` to `include/catch2/catch.hpp` - pass CONFIGURE_DEPENDS to file(GLOB) --- toolsrc/src/vcpkg-test/arguments.cpp | 2 +- toolsrc/src/vcpkg-test/catch.cpp | 2 +- toolsrc/src/vcpkg-test/chrono.cpp | 2 +- toolsrc/src/vcpkg-test/dependencies.cpp | 2 +- toolsrc/src/vcpkg-test/files.cpp | 4 +- toolsrc/src/vcpkg-test/paragraph.cpp | 2 +- toolsrc/src/vcpkg-test/plan.cpp | 2 +- toolsrc/src/vcpkg-test/specifier.cpp | 4 +- toolsrc/src/vcpkg-test/statusparagraphs.cpp | 2 +- toolsrc/src/vcpkg-test/strings.cpp | 2 +- toolsrc/src/vcpkg-test/supports.cpp | 2 +- toolsrc/src/vcpkg-test/update.cpp | 2 +- toolsrc/src/vcpkg-test/util.cpp | 7 +- toolsrc/src/vcpkg.cpp | 4 +- toolsrc/src/vcpkg/base/hash.cpp | 2 + toolsrc/src/vcpkg/base/system.cpp | 8 +- toolsrc/src/vcpkg/base/system.print.cpp | 4 + toolsrc/src/vcpkg/build.cpp | 6 +- toolsrc/src/vcpkg/commands.autocomplete.cpp | 4 +- toolsrc/src/vcpkg/commands.dependinfo.cpp | 331 ++++++++-------- toolsrc/src/vcpkg/commands.edit.cpp | 4 +- toolsrc/src/vcpkg/commands.exportifw.cpp | 564 ++++++++++++++-------------- toolsrc/src/vcpkg/commands.xvsinstances.cpp | 1 + toolsrc/src/vcpkg/dependencies.cpp | 77 ++-- toolsrc/src/vcpkg/export.cpp | 9 + toolsrc/src/vcpkg/install.cpp | 2 +- toolsrc/src/vcpkg/logicexpression.cpp | 28 +- toolsrc/src/vcpkg/metrics.cpp | 4 +- toolsrc/src/vcpkg/paragraphs.cpp | 2 +- toolsrc/src/vcpkg/postbuildlint.cpp | 4 +- toolsrc/src/vcpkg/statusparagraphs.cpp | 5 +- toolsrc/src/vcpkg/tools.cpp | 6 + toolsrc/src/vcpkg/vcpkgpaths.cpp | 4 +- toolsrc/src/vcpkg/versiont.cpp | 1 - 34 files changed, 572 insertions(+), 533 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/arguments.cpp b/toolsrc/src/vcpkg-test/arguments.cpp index 3fe5fa420..326b07579 100644 --- a/toolsrc/src/vcpkg-test/arguments.cpp +++ b/toolsrc/src/vcpkg-test/arguments.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/toolsrc/src/vcpkg-test/catch.cpp b/toolsrc/src/vcpkg-test/catch.cpp index 8b5d1aa15..50331c644 100644 --- a/toolsrc/src/vcpkg-test/catch.cpp +++ b/toolsrc/src/vcpkg-test/catch.cpp @@ -1,5 +1,5 @@ #define CATCH_CONFIG_RUNNER -#include +#include #include diff --git a/toolsrc/src/vcpkg-test/chrono.cpp b/toolsrc/src/vcpkg-test/chrono.cpp index 306217ad0..fb8a0dee9 100644 --- a/toolsrc/src/vcpkg-test/chrono.cpp +++ b/toolsrc/src/vcpkg-test/chrono.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/toolsrc/src/vcpkg-test/dependencies.cpp b/toolsrc/src/vcpkg-test/dependencies.cpp index 5ed05cc07..2344bb990 100644 --- a/toolsrc/src/vcpkg-test/dependencies.cpp +++ b/toolsrc/src/vcpkg-test/dependencies.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/toolsrc/src/vcpkg-test/files.cpp b/toolsrc/src/vcpkg-test/files.cpp index d40edb3bd..d8bc5ba74 100644 --- a/toolsrc/src/vcpkg-test/files.cpp +++ b/toolsrc/src/vcpkg-test/files.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -107,7 +107,7 @@ namespace CHECK_EC_ON_FILE(base, ec); } - for (int i = 0; i < width; ++i) + for (std::uint64_t i = 0; i < width; ++i) { create_directory_tree(urbg, fs, diff --git a/toolsrc/src/vcpkg-test/paragraph.cpp b/toolsrc/src/vcpkg-test/paragraph.cpp index a95879cfa..85c37851d 100644 --- a/toolsrc/src/vcpkg-test/paragraph.cpp +++ b/toolsrc/src/vcpkg-test/paragraph.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/toolsrc/src/vcpkg-test/plan.cpp b/toolsrc/src/vcpkg-test/plan.cpp index 049ef2066..e354b7551 100644 --- a/toolsrc/src/vcpkg-test/plan.cpp +++ b/toolsrc/src/vcpkg-test/plan.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/toolsrc/src/vcpkg-test/specifier.cpp b/toolsrc/src/vcpkg-test/specifier.cpp index 330a96d78..33df8ba83 100644 --- a/toolsrc/src/vcpkg-test/specifier.cpp +++ b/toolsrc/src/vcpkg-test/specifier.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -131,4 +131,4 @@ TEST_CASE ("specifier parsing", "[specifier]") REQUIRE(str == L"abc -x86-windows"); } #endif -}; +} diff --git a/toolsrc/src/vcpkg-test/statusparagraphs.cpp b/toolsrc/src/vcpkg-test/statusparagraphs.cpp index c0833e8ba..88b499118 100644 --- a/toolsrc/src/vcpkg-test/statusparagraphs.cpp +++ b/toolsrc/src/vcpkg-test/statusparagraphs.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/toolsrc/src/vcpkg-test/strings.cpp b/toolsrc/src/vcpkg-test/strings.cpp index 6b744eee6..d58d1b172 100644 --- a/toolsrc/src/vcpkg-test/strings.cpp +++ b/toolsrc/src/vcpkg-test/strings.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/toolsrc/src/vcpkg-test/supports.cpp b/toolsrc/src/vcpkg-test/supports.cpp index 8bd386da0..f4d8dc65a 100644 --- a/toolsrc/src/vcpkg-test/supports.cpp +++ b/toolsrc/src/vcpkg-test/supports.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/toolsrc/src/vcpkg-test/update.cpp b/toolsrc/src/vcpkg-test/update.cpp index 70b2f04c1..6f1a87d23 100644 --- a/toolsrc/src/vcpkg-test/update.cpp +++ b/toolsrc/src/vcpkg-test/update.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/toolsrc/src/vcpkg-test/util.cpp b/toolsrc/src/vcpkg-test/util.cpp index a2343c21b..daa21567d 100644 --- a/toolsrc/src/vcpkg-test/util.cpp +++ b/toolsrc/src/vcpkg-test/util.cpp @@ -1,8 +1,9 @@ -#include +#include #include #include #include +#include #include // used to get the implementation specific compiler flags (i.e., __cpp_lib_filesystem) @@ -153,7 +154,7 @@ namespace vcpkg::Test ec.assign(errno, std::system_category()); } #else - static_cast(ec); + Util::unused(target, file, ec); vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, no_filesystem_message); #endif } @@ -175,7 +176,7 @@ namespace vcpkg::Test #elif FILESYSTEM_SYMLINK == FILESYSTEM_SYMLINK_UNIX ::vcpkg::Test::create_symlink(target, file, ec); #else - static_cast(ec); + Util::unused(target, file, ec); vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, no_filesystem_message); #endif } diff --git a/toolsrc/src/vcpkg.cpp b/toolsrc/src/vcpkg.cpp index 3fdbd0d3e..9cd0ddf19 100644 --- a/toolsrc/src/vcpkg.cpp +++ b/toolsrc/src/vcpkg.cpp @@ -53,7 +53,7 @@ static constexpr int SURVEY_INTERVAL_IN_HOURS = 24 * 30 * 6; // Initial survey appears after 10 days. Therefore, subtract 24 hours/day * 10 days static constexpr int SURVEY_INITIAL_OFFSET_IN_HOURS = SURVEY_INTERVAL_IN_HOURS - 24 * 10; -void invalid_command(const std::string& cmd) +static void invalid_command(const std::string& cmd) { System::print2(System::Color::error, "invalid command: ", cmd, '\n'); Help::print_usage(); @@ -285,6 +285,8 @@ static std::string trim_path_from_command_line(const std::string& full_command_l #endif #if defined(_WIN32) +// note: this prevents a false positive for -Wmissing-prototypes on clang-cl +int wmain(int, const wchar_t* const*); int wmain(const int argc, const wchar_t* const* const argv) #else int main(const int argc, const char* const* const argv) diff --git a/toolsrc/src/vcpkg/base/hash.cpp b/toolsrc/src/vcpkg/base/hash.cpp index e9a7fa2ef..62a01ed17 100644 --- a/toolsrc/src/vcpkg/base/hash.cpp +++ b/toolsrc/src/vcpkg/base/hash.cpp @@ -1,5 +1,7 @@ #include "pch.h" +#include + #include #include #include diff --git a/toolsrc/src/vcpkg/base/system.cpp b/toolsrc/src/vcpkg/base/system.cpp index 3d5c60088..d9c6349be 100644 --- a/toolsrc/src/vcpkg/base/system.cpp +++ b/toolsrc/src/vcpkg/base/system.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -381,6 +382,8 @@ namespace vcpkg "CreateProcessW() returned ", exit_code, " after ", static_cast(timer.microseconds()), " us\n"); return static_cast(exit_code); #else + // TODO: this should create a clean environment on Linux/macOS + Util::unused(extra_env, prepend_to_path); Debug::print("system(", cmd_line, ")\n"); fflush(nullptr); int rc = system(cmd_line.c_str()); @@ -549,10 +552,7 @@ namespace vcpkg return Strings::to_utf8(ret); } #else - Optional System::get_registry_string(void* base_hkey, StringView sub_key, StringView valuename) - { - return nullopt; - } + Optional System::get_registry_string(void*, StringView, StringView) { return nullopt; } #endif static const Optional& get_program_files() diff --git a/toolsrc/src/vcpkg/base/system.print.cpp b/toolsrc/src/vcpkg/base/system.print.cpp index c7c9981a7..fc8e4184c 100644 --- a/toolsrc/src/vcpkg/base/system.print.cpp +++ b/toolsrc/src/vcpkg/base/system.print.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include +#include namespace vcpkg::System { @@ -21,6 +22,9 @@ namespace vcpkg::System System::print2(message); SetConsoleTextAttribute(console_handle, original_color); #else + // TODO: add color handling code + // it should probably use VT-220 codes + Util::unused(c); System::print2(message); #endif } diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index d7ba5fd18..2114b7415 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -184,7 +184,7 @@ namespace vcpkg::Build static const std::string LIBRARY_LINKAGE = "LibraryLinkage"; } - CStringView to_vcvarsall_target(const std::string& cmake_system_name) + static CStringView to_vcvarsall_target(const std::string& cmake_system_name) { if (cmake_system_name.empty()) return ""; if (cmake_system_name == "Windows") return ""; @@ -193,7 +193,7 @@ namespace vcpkg::Build Checks::exit_with_message(VCPKG_LINE_INFO, "Unsupported vcvarsall target %s", cmake_system_name); } - CStringView to_vcvarsall_toolchain(const std::string& target_architecture, const Toolset& toolset) + static CStringView to_vcvarsall_toolchain(const std::string& target_architecture, const Toolset& toolset) { auto maybe_target_arch = System::to_cpu_architecture(target_architecture); Checks::check_exit( @@ -217,7 +217,7 @@ namespace vcpkg::Build })); } - std::unordered_map make_env_passthrough(const PreBuildInfo& pre_build_info) + static auto make_env_passthrough(const PreBuildInfo& pre_build_info) -> std::unordered_map { std::unordered_map env; diff --git a/toolsrc/src/vcpkg/commands.autocomplete.cpp b/toolsrc/src/vcpkg/commands.autocomplete.cpp index 3cf4dd98f..8449b7096 100644 --- a/toolsrc/src/vcpkg/commands.autocomplete.cpp +++ b/toolsrc/src/vcpkg/commands.autocomplete.cpp @@ -19,8 +19,8 @@ namespace vcpkg::Commands::Autocomplete Checks::exit_success(line_info); } - std::vector combine_port_with_triplets(const std::string& port, - const std::vector& triplets) + static std::vector combine_port_with_triplets(const std::string& port, + const std::vector& triplets) { return Util::fmap(triplets, [&](const std::string& triplet) { return Strings::format("%s:%s", port, triplet); }); diff --git a/toolsrc/src/vcpkg/commands.dependinfo.cpp b/toolsrc/src/vcpkg/commands.dependinfo.cpp index 8ca88dd56..faf207980 100644 --- a/toolsrc/src/vcpkg/commands.dependinfo.cpp +++ b/toolsrc/src/vcpkg/commands.dependinfo.cpp @@ -18,216 +18,222 @@ using vcpkg::Dependencies::PathsPortFileProvider; namespace vcpkg::Commands::DependInfo { - constexpr StringLiteral OPTION_DOT = "--dot"; - constexpr StringLiteral OPTION_DGML = "--dgml"; - constexpr StringLiteral OPTION_SHOW_DEPTH = "--show-depth"; - constexpr StringLiteral OPTION_MAX_RECURSE = "--max-recurse"; - constexpr StringLiteral OPTION_SORT = "--sort"; - - constexpr int NO_RECURSE_LIMIT_VALUE = -1; - - constexpr std::array DEPEND_SWITCHES = {{{OPTION_DOT, "Creates graph on basis of dot"}, - {OPTION_DGML, "Creates graph on basis of dgml"}, - {OPTION_SHOW_DEPTH, "Show recursion depth in output"}}}; - - constexpr std::array DEPEND_SETTINGS = { - {{OPTION_MAX_RECURSE, "Set max recursion depth, a value of -1 indicates no limit"}, - {OPTION_SORT, - "Set sort order for the list of dependencies, accepted values are: lexicographical, topological (default), " - "reverse"}}}; - - const CommandStructure COMMAND_STRUCTURE = { - Help::create_example_string("depend-info sqlite3"), - 0, - SIZE_MAX, - {DEPEND_SWITCHES, DEPEND_SETTINGS}, - nullptr, - }; - - struct PackageDependInfo + namespace { - std::string package; - int depth; - std::set features; - std::vector dependencies; - }; + constexpr StringLiteral OPTION_DOT = "--dot"; + constexpr StringLiteral OPTION_DGML = "--dgml"; + constexpr StringLiteral OPTION_SHOW_DEPTH = "--show-depth"; + constexpr StringLiteral OPTION_MAX_RECURSE = "--max-recurse"; + constexpr StringLiteral OPTION_SORT = "--sort"; + + constexpr int NO_RECURSE_LIMIT_VALUE = -1; + + constexpr std::array DEPEND_SWITCHES = { + {{OPTION_DOT, "Creates graph on basis of dot"}, + {OPTION_DGML, "Creates graph on basis of dgml"}, + {OPTION_SHOW_DEPTH, "Show recursion depth in output"}}}; + + constexpr std::array DEPEND_SETTINGS = { + {{OPTION_MAX_RECURSE, "Set max recursion depth, a value of -1 indicates no limit"}, + {OPTION_SORT, + "Set sort order for the list of dependencies, accepted values are: lexicographical, topological " + "(default), " + "reverse"}}}; + + struct PackageDependInfo + { + std::string package; + int depth; + std::set features; + std::vector dependencies; + }; - enum SortMode - { - Lexicographical = 0, - Topological, - ReverseTopological, - Default = Topological - }; + enum SortMode + { + Lexicographical = 0, + Topological, + ReverseTopological, + Default = Topological + }; - int get_max_depth(const ParsedArguments& options) - { - auto iter = options.settings.find(OPTION_MAX_RECURSE); - if (iter != options.settings.end()) + int get_max_depth(const ParsedArguments& options) { - std::string value = iter->second; - try + auto iter = options.settings.find(OPTION_MAX_RECURSE); + if (iter != options.settings.end()) { - return std::stoi(value); - } - catch (std::exception&) - { - Checks::exit_with_message(VCPKG_LINE_INFO, "Value of --max-depth must be an integer"); + std::string value = iter->second; + try + { + return std::stoi(value); + } + catch (std::exception&) + { + Checks::exit_with_message(VCPKG_LINE_INFO, "Value of --max-depth must be an integer"); + } } + // No --max-depth set, default to no limit. + return NO_RECURSE_LIMIT_VALUE; } - // No --max-depth set, default to no limit. - return NO_RECURSE_LIMIT_VALUE; - } - SortMode get_sort_mode(const ParsedArguments& options) - { - constexpr StringLiteral OPTION_SORT_LEXICOGRAPHICAL = "lexicographical"; - constexpr StringLiteral OPTION_SORT_TOPOLOGICAL = "topological"; - constexpr StringLiteral OPTION_SORT_REVERSE = "reverse"; + SortMode get_sort_mode(const ParsedArguments& options) + { + constexpr StringLiteral OPTION_SORT_LEXICOGRAPHICAL = "lexicographical"; + constexpr StringLiteral OPTION_SORT_TOPOLOGICAL = "topological"; + constexpr StringLiteral OPTION_SORT_REVERSE = "reverse"; - static const std::map sortModesMap{{OPTION_SORT_LEXICOGRAPHICAL, Lexicographical}, - {OPTION_SORT_TOPOLOGICAL, Topological}, - {OPTION_SORT_REVERSE, ReverseTopological}}; + static const std::map sortModesMap{{OPTION_SORT_LEXICOGRAPHICAL, Lexicographical}, + {OPTION_SORT_TOPOLOGICAL, Topological}, + {OPTION_SORT_REVERSE, ReverseTopological}}; - auto iter = options.settings.find(OPTION_SORT); - if (iter != options.settings.end()) - { - const std::string value = Strings::ascii_to_lowercase(std::string{iter->second}); - auto it = sortModesMap.find(value); - if (it != sortModesMap.end()) + auto iter = options.settings.find(OPTION_SORT); + if (iter != options.settings.end()) { - return it->second; + const std::string value = Strings::ascii_to_lowercase(std::string{iter->second}); + auto it = sortModesMap.find(value); + if (it != sortModesMap.end()) + { + return it->second; + } + Checks::exit_with_message(VCPKG_LINE_INFO, + "Value of --sort must be one of `%s`, `%s`, or `%s`", + OPTION_SORT_LEXICOGRAPHICAL, + OPTION_SORT_TOPOLOGICAL, + OPTION_SORT_REVERSE); } - Checks::exit_with_message(VCPKG_LINE_INFO, - "Value of --sort must be one of `%s`, `%s`, or `%s`", - OPTION_SORT_LEXICOGRAPHICAL, - OPTION_SORT_TOPOLOGICAL, - OPTION_SORT_REVERSE); + return Default; } - return Default; - } - std::string create_dot_as_string(const std::vector& depend_info) - { - int empty_node_count = 0; + std::string create_dot_as_string(const std::vector& depend_info) + { + int empty_node_count = 0; - std::string s; - s.append("digraph G{ rankdir=LR; edge [minlen=3]; overlap=false;"); + std::string s; + s.append("digraph G{ rankdir=LR; edge [minlen=3]; overlap=false;"); - for (const auto& package : depend_info) - { - if (package.dependencies.empty()) + for (const auto& package : depend_info) { - empty_node_count++; - continue; - } + if (package.dependencies.empty()) + { + empty_node_count++; + continue; + } - const std::string name = Strings::replace_all(std::string{ package.package }, "-", "_"); - s.append(Strings::format("%s;", name)); - for (const auto &d : package.dependencies) - { - const std::string dependency_name = Strings::replace_all(std::string{ d }, "-", "_"); - s.append(Strings::format("%s -> %s;", name, dependency_name)); + const std::string name = Strings::replace_all(std::string{package.package}, "-", "_"); + s.append(Strings::format("%s;", name)); + for (const auto& d : package.dependencies) + { + const std::string dependency_name = Strings::replace_all(std::string{d}, "-", "_"); + s.append(Strings::format("%s -> %s;", name, dependency_name)); + } } - } - - s.append(Strings::format("empty [label=\"%d singletons...\"]; }", empty_node_count)); - return s; - } - std::string create_dgml_as_string(const std::vector& depend_info) - { - std::string s; - s.append(""); - s.append(""); + s.append(Strings::format("empty [label=\"%d singletons...\"]; }", empty_node_count)); + return s; + } - std::string nodes, links; - for (const auto& package : depend_info) + std::string create_dgml_as_string(const std::vector& depend_info) { - const std::string name = package.package; - nodes.append(Strings::format("", name)); + std::string s; + s.append(""); + s.append(""); - // Iterate over dependencies. - for (const auto& d : package.dependencies) + std::string nodes, links; + for (const auto& package : depend_info) { - links.append(Strings::format("", name, d)); - } - } + const std::string name = package.package; + nodes.append(Strings::format("", name)); - s.append(Strings::format("%s", nodes)); + // Iterate over dependencies. + for (const auto& d : package.dependencies) + { + links.append(Strings::format("", name, d)); + } + } - s.append(Strings::format("%s", links)); + s.append(Strings::format("%s", nodes)); - s.append(""); - return s; - } + s.append(Strings::format("%s", links)); - std::string create_graph_as_string(const std::unordered_set& switches, - const std::vector& depend_info) - { - if (Util::Sets::contains(switches, OPTION_DOT)) - { - return create_dot_as_string(depend_info); + s.append(""); + return s; } - else if (Util::Sets::contains(switches, OPTION_DGML)) + + std::string create_graph_as_string(const std::unordered_set& switches, + const std::vector& depend_info) { - return create_dgml_as_string(depend_info); + if (Util::Sets::contains(switches, OPTION_DOT)) + { + return create_dot_as_string(depend_info); + } + else if (Util::Sets::contains(switches, OPTION_DGML)) + { + return create_dgml_as_string(depend_info); + } + return ""; } - return ""; - } - void assign_depth_to_dependencies(const std::string& package, - const int depth, - const int max_depth, - std::map& dependencies_map) - { - auto iter = dependencies_map.find(package); - Checks::check_exit(VCPKG_LINE_INFO, iter != dependencies_map.end(), "Package not found in dependency graph"); + void assign_depth_to_dependencies(const std::string& package, + const int depth, + const int max_depth, + std::map& dependencies_map) + { + auto iter = dependencies_map.find(package); + Checks::check_exit( + VCPKG_LINE_INFO, iter != dependencies_map.end(), "Package not found in dependency graph"); - PackageDependInfo& info = iter->second; + PackageDependInfo& info = iter->second; - if (depth > info.depth) - { - info.depth = depth; - if (depth < max_depth || max_depth == NO_RECURSE_LIMIT_VALUE) + if (depth > info.depth) { - for (auto&& dependency : info.dependencies) + info.depth = depth; + if (depth < max_depth || max_depth == NO_RECURSE_LIMIT_VALUE) { - assign_depth_to_dependencies(dependency, depth + 1, max_depth, dependencies_map); + for (auto&& dependency : info.dependencies) + { + assign_depth_to_dependencies(dependency, depth + 1, max_depth, dependencies_map); + } } } } - }; - std::vector extract_depend_info(const std::vector& install_actions, - const int max_depth) - { - std::map package_dependencies; - for (const InstallPlanAction* pia : install_actions) + std::vector extract_depend_info(const std::vector& install_actions, + const int max_depth) { - const InstallPlanAction& install_action = *pia; + std::map package_dependencies; + for (const InstallPlanAction* pia : install_actions) + { + const InstallPlanAction& install_action = *pia; - const std::vector dependencies = - Util::fmap(install_action.computed_dependencies, [](const PackageSpec& spec) { return spec.name(); }); + const std::vector dependencies = Util::fmap( + install_action.computed_dependencies, [](const PackageSpec& spec) { return spec.name(); }); - std::set features{install_action.feature_list}; - features.erase("core"); + std::set features{install_action.feature_list}; + features.erase("core"); - std::string port_name = install_action.spec.name(); + std::string port_name = install_action.spec.name(); - PackageDependInfo info {port_name, -1, features, dependencies}; - package_dependencies.emplace(port_name, std::move(info)); - } + PackageDependInfo info{port_name, -1, features, dependencies}; + package_dependencies.emplace(port_name, std::move(info)); + } - const InstallPlanAction& init = *install_actions.back(); - assign_depth_to_dependencies(init.spec.name(), 0, max_depth, package_dependencies); + const InstallPlanAction& init = *install_actions.back(); + assign_depth_to_dependencies(init.spec.name(), 0, max_depth, package_dependencies); - std::vector out = - Util::fmap(package_dependencies, [](auto&& kvpair) -> PackageDependInfo { return kvpair.second; }); - Util::erase_remove_if(out, [](auto&& info) { return info.depth < 0; }); - return out; + std::vector out = + Util::fmap(package_dependencies, [](auto&& kvpair) -> PackageDependInfo { return kvpair.second; }); + Util::erase_remove_if(out, [](auto&& info) { return info.depth < 0; }); + return out; + } } + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string("depend-info sqlite3"), + 0, + SIZE_MAX, + {DEPEND_SWITCHES, DEPEND_SETTINGS}, + nullptr, + }; + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet) { const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); @@ -276,7 +282,6 @@ namespace vcpkg::Commands::DependInfo Checks::exit_success(VCPKG_LINE_INFO); } - // TODO: Improve this code auto lex = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool { return lhs.package < rhs.package; @@ -284,7 +289,7 @@ namespace vcpkg::Commands::DependInfo auto topo = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool { return lhs.depth > rhs.depth; }; - auto reverse = [topo](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool { + auto reverse = [](const PackageDependInfo& lhs, const PackageDependInfo& rhs) -> bool { return lhs.depth < rhs.depth; }; diff --git a/toolsrc/src/vcpkg/commands.edit.cpp b/toolsrc/src/vcpkg/commands.edit.cpp index f2f0b1569..6e98f5818 100644 --- a/toolsrc/src/vcpkg/commands.edit.cpp +++ b/toolsrc/src/vcpkg/commands.edit.cpp @@ -9,11 +9,11 @@ namespace vcpkg::Commands::Edit { +#if defined(_WIN32) static std::vector find_from_registry() { std::vector output; -#if defined(_WIN32) struct RegKey { HKEY root; @@ -42,9 +42,9 @@ namespace vcpkg::Commands::Edit output.push_back(install_path / "Code.exe"); } } -#endif return output; } +#endif static constexpr StringLiteral OPTION_BUILDTREES = "--buildtrees"; diff --git a/toolsrc/src/vcpkg/commands.exportifw.cpp b/toolsrc/src/vcpkg/commands.exportifw.cpp index 3d963a297..bc75069cd 100644 --- a/toolsrc/src/vcpkg/commands.exportifw.cpp +++ b/toolsrc/src/vcpkg/commands.exportifw.cpp @@ -13,86 +13,94 @@ namespace vcpkg::Export::IFW using Dependencies::ExportPlanType; using Install::InstallDir; - static std::string create_release_date() + namespace { - const tm date_time = Chrono::get_current_date_time_local(); + std::string create_release_date() + { + const tm date_time = Chrono::get_current_date_time_local(); - // Format is: YYYY-mm-dd - // 10 characters + 1 null terminating character will be written for a total of 11 chars - char mbstr[11]; - const size_t bytes_written = std::strftime(mbstr, sizeof(mbstr), "%Y-%m-%d", &date_time); - Checks::check_exit(VCPKG_LINE_INFO, - bytes_written == 10, - "Expected 10 bytes to be written, but %u were written", - bytes_written); - const std::string date_time_as_string(mbstr); - return date_time_as_string; - } + // Format is: YYYY-mm-dd + // 10 characters + 1 null terminating character will be written for a total of 11 chars + char mbstr[11]; + const size_t bytes_written = std::strftime(mbstr, sizeof(mbstr), "%Y-%m-%d", &date_time); + Checks::check_exit(VCPKG_LINE_INFO, + bytes_written == 10, + "Expected 10 bytes to be written, but %u were written", + bytes_written); + const std::string date_time_as_string(mbstr); + return date_time_as_string; + } - std::string safe_rich_from_plain_text(const std::string& text) - { - // match standalone ampersand, no HTML number or name - std::regex standalone_ampersand(R"###(&(?!(#[0-9]+|\w+);))###"); + std::string safe_rich_from_plain_text(const std::string& text) + { + // match standalone ampersand, no HTML number or name + std::regex standalone_ampersand(R"###(&(?!(#[0-9]+|\w+);))###"); - return std::regex_replace(text, standalone_ampersand, "&"); - } + return std::regex_replace(text, standalone_ampersand, "&"); + } - fs::path get_packages_dir_path(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths) - { - return ifw_options.maybe_packages_dir_path.has_value() - ? fs::path(ifw_options.maybe_packages_dir_path.value_or_exit(VCPKG_LINE_INFO)) - : paths.root / (export_id + "-ifw-packages"); - } + fs::path get_packages_dir_path(const std::string& export_id, + const Options& ifw_options, + const VcpkgPaths& paths) + { + return ifw_options.maybe_packages_dir_path.has_value() + ? fs::path(ifw_options.maybe_packages_dir_path.value_or_exit(VCPKG_LINE_INFO)) + : paths.root / (export_id + "-ifw-packages"); + } - fs::path get_repository_dir_path(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths) - { - return ifw_options.maybe_repository_dir_path.has_value() - ? fs::path(ifw_options.maybe_repository_dir_path.value_or_exit(VCPKG_LINE_INFO)) - : paths.root / (export_id + "-ifw-repository"); - } + fs::path get_repository_dir_path(const std::string& export_id, + const Options& ifw_options, + const VcpkgPaths& paths) + { + return ifw_options.maybe_repository_dir_path.has_value() + ? fs::path(ifw_options.maybe_repository_dir_path.value_or_exit(VCPKG_LINE_INFO)) + : paths.root / (export_id + "-ifw-repository"); + } - fs::path get_config_file_path(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths) - { - return ifw_options.maybe_config_file_path.has_value() - ? fs::path(ifw_options.maybe_config_file_path.value_or_exit(VCPKG_LINE_INFO)) - : paths.root / (export_id + "-ifw-configuration.xml"); - } + fs::path get_config_file_path(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths) + { + return ifw_options.maybe_config_file_path.has_value() + ? fs::path(ifw_options.maybe_config_file_path.value_or_exit(VCPKG_LINE_INFO)) + : paths.root / (export_id + "-ifw-configuration.xml"); + } - fs::path get_installer_file_path(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths) - { - return ifw_options.maybe_installer_file_path.has_value() - ? fs::path(ifw_options.maybe_installer_file_path.value_or_exit(VCPKG_LINE_INFO)) - : paths.root / (export_id + "-ifw-installer.exe"); - } + fs::path get_installer_file_path(const std::string& export_id, + const Options& ifw_options, + const VcpkgPaths& paths) + { + return ifw_options.maybe_installer_file_path.has_value() + ? fs::path(ifw_options.maybe_installer_file_path.value_or_exit(VCPKG_LINE_INFO)) + : paths.root / (export_id + "-ifw-installer.exe"); + } - fs::path export_real_package(const fs::path& ifw_packages_dir_path, - const ExportPlanAction& action, - Files::Filesystem& fs) - { - std::error_code ec; + fs::path export_real_package(const fs::path& ifw_packages_dir_path, + const ExportPlanAction& action, + Files::Filesystem& fs) + { + std::error_code ec; - const BinaryParagraph& binary_paragraph = action.core_paragraph().value_or_exit(VCPKG_LINE_INFO); + const BinaryParagraph& binary_paragraph = action.core_paragraph().value_or_exit(VCPKG_LINE_INFO); - // Prepare meta dir - const fs::path package_xml_file_path = - ifw_packages_dir_path / - Strings::format("packages.%s.%s", action.spec.name(), action.spec.triplet().canonical_name()) / "meta" / - "package.xml"; - const fs::path package_xml_dir_path = package_xml_file_path.parent_path(); - fs.create_directories(package_xml_dir_path, ec); - Checks::check_exit(VCPKG_LINE_INFO, - !ec, - "Could not create directory for package file %s", - package_xml_file_path.generic_u8string()); + // Prepare meta dir + const fs::path package_xml_file_path = + ifw_packages_dir_path / + Strings::format("packages.%s.%s", action.spec.name(), action.spec.triplet().canonical_name()) / "meta" / + "package.xml"; + const fs::path package_xml_dir_path = package_xml_file_path.parent_path(); + fs.create_directories(package_xml_dir_path, ec); + Checks::check_exit(VCPKG_LINE_INFO, + !ec, + "Could not create directory for package file %s", + package_xml_file_path.generic_u8string()); - auto deps = Strings::join( - ",", binary_paragraph.depends, [](const std::string& dep) { return "packages." + dep + ":"; }); + auto deps = Strings::join( + ",", binary_paragraph.depends, [](const std::string& dep) { return "packages." + dep + ":"; }); - if (!deps.empty()) deps = "\n " + deps + ""; + if (!deps.empty()) deps = "\n " + deps + ""; - fs.write_contents(package_xml_file_path, - Strings::format( - R"###( + fs.write_contents(package_xml_file_path, + Strings::format( + R"###( %s %s @@ -101,111 +109,89 @@ namespace vcpkg::Export::IFW true )###", - action.spec.to_string(), - binary_paragraph.version, - create_release_date(), - action.spec.name(), - action.spec.triplet().canonical_name(), - deps), - VCPKG_LINE_INFO); - - // Return dir path for export package data - return ifw_packages_dir_path / - Strings::format("packages.%s.%s", action.spec.name(), action.spec.triplet().canonical_name()) / "data" / - "installed"; - } - - void export_unique_packages(const fs::path& raw_exported_dir_path, - std::map unique_packages, - Files::Filesystem& fs) - { - std::error_code ec; - - // packages + action.spec.to_string(), + binary_paragraph.version, + create_release_date(), + action.spec.name(), + action.spec.triplet().canonical_name(), + deps), + VCPKG_LINE_INFO); - fs::path package_xml_file_path = raw_exported_dir_path / "packages" / "meta" / "package.xml"; - fs::path package_xml_dir_path = package_xml_file_path.parent_path(); - fs.create_directories(package_xml_dir_path, ec); - Checks::check_exit(VCPKG_LINE_INFO, - !ec, - "Could not create directory for package file %s", - package_xml_file_path.generic_u8string()); - fs.write_contents(package_xml_file_path, - Strings::format( - R"###( - - Packages - 1.0.0 - %s - -)###", - create_release_date()), - VCPKG_LINE_INFO); + // Return dir path for export package data + return ifw_packages_dir_path / + Strings::format("packages.%s.%s", action.spec.name(), action.spec.triplet().canonical_name()) / + "data" / "installed"; + } - for (const auto& unique_package : unique_packages) + void export_unique_packages(const fs::path& raw_exported_dir_path, + std::map unique_packages, + Files::Filesystem& fs) { - const ExportPlanAction& action = *(unique_package.second); - const BinaryParagraph& binary_paragraph = action.core_paragraph().value_or_exit(VCPKG_LINE_INFO); + std::error_code ec; + + // packages - package_xml_file_path = - raw_exported_dir_path / Strings::format("packages.%s", unique_package.first) / "meta" / "package.xml"; - package_xml_dir_path = package_xml_file_path.parent_path(); + fs::path package_xml_file_path = raw_exported_dir_path / "packages" / "meta" / "package.xml"; + fs::path package_xml_dir_path = package_xml_file_path.parent_path(); fs.create_directories(package_xml_dir_path, ec); Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not create directory for package file %s", package_xml_file_path.generic_u8string()); - fs.write_contents(package_xml_file_path, Strings::format( R"###( - %s - %s - %s + Packages + 1.0.0 %s )###", - action.spec.name(), - safe_rich_from_plain_text(binary_paragraph.description), - binary_paragraph.version, create_release_date()), VCPKG_LINE_INFO); - } - } - - void export_unique_triplets(const fs::path& raw_exported_dir_path, - std::set unique_triplets, - Files::Filesystem& fs) - { - std::error_code ec; - - // triplets - fs::path package_xml_file_path = raw_exported_dir_path / "triplets" / "meta" / "package.xml"; - fs::path package_xml_dir_path = package_xml_file_path.parent_path(); - fs.create_directories(package_xml_dir_path, ec); - Checks::check_exit(VCPKG_LINE_INFO, - !ec, - "Could not create directory for package file %s", - package_xml_file_path.generic_u8string()); - fs.write_contents(package_xml_file_path, - Strings::format( - R"###( + for (const auto& unique_package : unique_packages) + { + const ExportPlanAction& action = *(unique_package.second); + const BinaryParagraph& binary_paragraph = action.core_paragraph().value_or_exit(VCPKG_LINE_INFO); + + package_xml_file_path = raw_exported_dir_path / Strings::format("packages.%s", unique_package.first) / + "meta" / "package.xml"; + package_xml_dir_path = package_xml_file_path.parent_path(); + fs.create_directories(package_xml_dir_path, ec); + Checks::check_exit(VCPKG_LINE_INFO, + !ec, + "Could not create directory for package file %s", + package_xml_file_path.generic_u8string()); + + fs.write_contents(package_xml_file_path, + Strings::format( + R"###( - Triplets - 1.0.0 + %s + %s + %s %s )###", - create_release_date()), - VCPKG_LINE_INFO); + action.spec.name(), + safe_rich_from_plain_text(binary_paragraph.description), + binary_paragraph.version, + create_release_date()), + VCPKG_LINE_INFO); + } + } - for (const std::string& triplet : unique_triplets) + void export_unique_triplets(const fs::path& raw_exported_dir_path, + std::set unique_triplets, + Files::Filesystem& fs) { - package_xml_file_path = - raw_exported_dir_path / Strings::format("triplets.%s", triplet) / "meta" / "package.xml"; - package_xml_dir_path = package_xml_file_path.parent_path(); + std::error_code ec; + + // triplets + + fs::path package_xml_file_path = raw_exported_dir_path / "triplets" / "meta" / "package.xml"; + fs::path package_xml_dir_path = package_xml_file_path.parent_path(); fs.create_directories(package_xml_dir_path, ec); Checks::check_exit(VCPKG_LINE_INFO, !ec, @@ -215,73 +201,95 @@ namespace vcpkg::Export::IFW Strings::format( R"###( - %s + Triplets 1.0.0 %s )###", - triplet, create_release_date()), VCPKG_LINE_INFO); + + for (const std::string& triplet : unique_triplets) + { + package_xml_file_path = + raw_exported_dir_path / Strings::format("triplets.%s", triplet) / "meta" / "package.xml"; + package_xml_dir_path = package_xml_file_path.parent_path(); + fs.create_directories(package_xml_dir_path, ec); + Checks::check_exit(VCPKG_LINE_INFO, + !ec, + "Could not create directory for package file %s", + package_xml_file_path.generic_u8string()); + fs.write_contents(package_xml_file_path, + Strings::format( + R"###( + + %s + 1.0.0 + %s + +)###", + triplet, + create_release_date()), + VCPKG_LINE_INFO); + } } - } - void export_integration(const fs::path& raw_exported_dir_path, Files::Filesystem& fs) - { - std::error_code ec; + void export_integration(const fs::path& raw_exported_dir_path, Files::Filesystem& fs) + { + std::error_code ec; - // integration - fs::path package_xml_file_path = raw_exported_dir_path / "integration" / "meta" / "package.xml"; - fs::path package_xml_dir_path = package_xml_file_path.parent_path(); - fs.create_directories(package_xml_dir_path, ec); - Checks::check_exit(VCPKG_LINE_INFO, - !ec, - "Could not create directory for package file %s", - package_xml_file_path.generic_u8string()); + // integration + fs::path package_xml_file_path = raw_exported_dir_path / "integration" / "meta" / "package.xml"; + fs::path package_xml_dir_path = package_xml_file_path.parent_path(); + fs.create_directories(package_xml_dir_path, ec); + Checks::check_exit(VCPKG_LINE_INFO, + !ec, + "Could not create directory for package file %s", + package_xml_file_path.generic_u8string()); - fs.write_contents(package_xml_file_path, - Strings::format( - R"###( + fs.write_contents(package_xml_file_path, + Strings::format( + R"###( Integration 1.0.0 %s )###", - create_release_date()), - VCPKG_LINE_INFO); - } + create_release_date()), + VCPKG_LINE_INFO); + } - void export_config(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths) - { - std::error_code ec; - Files::Filesystem& fs = paths.get_filesystem(); + void export_config(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths) + { + std::error_code ec; + Files::Filesystem& fs = paths.get_filesystem(); - const fs::path config_xml_file_path = get_config_file_path(export_id, ifw_options, paths); + const fs::path config_xml_file_path = get_config_file_path(export_id, ifw_options, paths); - fs::path config_xml_dir_path = config_xml_file_path.parent_path(); - fs.create_directories(config_xml_dir_path, ec); - Checks::check_exit(VCPKG_LINE_INFO, - !ec, - "Could not create directory for configuration file %s", - config_xml_file_path.generic_u8string()); + fs::path config_xml_dir_path = config_xml_file_path.parent_path(); + fs.create_directories(config_xml_dir_path, ec); + Checks::check_exit(VCPKG_LINE_INFO, + !ec, + "Could not create directory for configuration file %s", + config_xml_file_path.generic_u8string()); - std::string formatted_repo_url; - std::string ifw_repo_url = ifw_options.maybe_repository_url.value_or(""); - if (!ifw_repo_url.empty()) - { - formatted_repo_url = Strings::format(R"###( + std::string formatted_repo_url; + std::string ifw_repo_url = ifw_options.maybe_repository_url.value_or(""); + if (!ifw_repo_url.empty()) + { + formatted_repo_url = Strings::format(R"###( %s )###", - ifw_repo_url); - } + ifw_repo_url); + } - fs.write_contents(config_xml_file_path, - Strings::format( - R"###( + fs.write_contents(config_xml_file_path, + Strings::format( + R"###( vcpkg 1.0.0 @@ -289,38 +297,38 @@ namespace vcpkg::Export::IFW @RootDir@/src/vcpkg%s )###", - formatted_repo_url), - VCPKG_LINE_INFO); - } + formatted_repo_url), + VCPKG_LINE_INFO); + } - void export_maintenance_tool(const fs::path& ifw_packages_dir_path, const VcpkgPaths& paths) - { - System::print2("Exporting maintenance tool...\n"); + void export_maintenance_tool(const fs::path& ifw_packages_dir_path, const VcpkgPaths& paths) + { + System::print2("Exporting maintenance tool...\n"); - std::error_code ec; - Files::Filesystem& fs = paths.get_filesystem(); + std::error_code ec; + Files::Filesystem& fs = paths.get_filesystem(); - const fs::path& installerbase_exe = paths.get_tool_exe(Tools::IFW_INSTALLER_BASE); - fs::path tempmaintenancetool = ifw_packages_dir_path / "maintenance" / "data" / "tempmaintenancetool.exe"; - fs.create_directories(tempmaintenancetool.parent_path(), ec); - Checks::check_exit(VCPKG_LINE_INFO, - !ec, - "Could not create directory for package file %s", - tempmaintenancetool.generic_u8string()); - fs.copy_file(installerbase_exe, tempmaintenancetool, fs::copy_options::overwrite_existing, ec); - Checks::check_exit( - VCPKG_LINE_INFO, !ec, "Could not write package file %s", tempmaintenancetool.generic_u8string()); + const fs::path& installerbase_exe = paths.get_tool_exe(Tools::IFW_INSTALLER_BASE); + fs::path tempmaintenancetool = ifw_packages_dir_path / "maintenance" / "data" / "tempmaintenancetool.exe"; + fs.create_directories(tempmaintenancetool.parent_path(), ec); + Checks::check_exit(VCPKG_LINE_INFO, + !ec, + "Could not create directory for package file %s", + tempmaintenancetool.generic_u8string()); + fs.copy_file(installerbase_exe, tempmaintenancetool, fs::copy_options::overwrite_existing, ec); + Checks::check_exit( + VCPKG_LINE_INFO, !ec, "Could not write package file %s", tempmaintenancetool.generic_u8string()); - fs::path package_xml_file_path = ifw_packages_dir_path / "maintenance" / "meta" / "package.xml"; - fs::path package_xml_dir_path = package_xml_file_path.parent_path(); - fs.create_directories(package_xml_dir_path, ec); - Checks::check_exit(VCPKG_LINE_INFO, - !ec, - "Could not create directory for package file %s", - package_xml_file_path.generic_u8string()); - fs.write_contents(package_xml_file_path, - Strings::format( - R"###( + fs::path package_xml_file_path = ifw_packages_dir_path / "maintenance" / "meta" / "package.xml"; + fs::path package_xml_dir_path = package_xml_file_path.parent_path(); + fs.create_directories(package_xml_dir_path, ec); + Checks::check_exit(VCPKG_LINE_INFO, + !ec, + "Could not create directory for package file %s", + package_xml_file_path.generic_u8string()); + fs.write_contents(package_xml_file_path, + Strings::format( + R"###( Maintenance Tool Maintenance Tool @@ -332,82 +340,84 @@ namespace vcpkg::Export::IFW true )###", - create_release_date()), - VCPKG_LINE_INFO); - const fs::path script_source = paths.root / "scripts" / "ifw" / "maintenance.qs"; - const fs::path script_destination = ifw_packages_dir_path / "maintenance" / "meta" / "maintenance.qs"; - fs.copy_file(script_source, script_destination, fs::copy_options::overwrite_existing, ec); - Checks::check_exit( - VCPKG_LINE_INFO, !ec, "Could not write package file %s", script_destination.generic_u8string()); + create_release_date()), + VCPKG_LINE_INFO); + const fs::path script_source = paths.root / "scripts" / "ifw" / "maintenance.qs"; + const fs::path script_destination = ifw_packages_dir_path / "maintenance" / "meta" / "maintenance.qs"; + fs.copy_file(script_source, script_destination, fs::copy_options::overwrite_existing, ec); + Checks::check_exit( + VCPKG_LINE_INFO, !ec, "Could not write package file %s", script_destination.generic_u8string()); - System::print2("Exporting maintenance tool... done\n"); - } + System::print2("Exporting maintenance tool... done\n"); + } - void do_repository(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths) - { - const fs::path& repogen_exe = paths.get_tool_exe(Tools::IFW_REPOGEN); - const fs::path packages_dir = get_packages_dir_path(export_id, ifw_options, paths); - const fs::path repository_dir = get_repository_dir_path(export_id, ifw_options, paths); + void do_repository(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths) + { + const fs::path& repogen_exe = paths.get_tool_exe(Tools::IFW_REPOGEN); + const fs::path packages_dir = get_packages_dir_path(export_id, ifw_options, paths); + const fs::path repository_dir = get_repository_dir_path(export_id, ifw_options, paths); - System::print2("Generating repository ", repository_dir.generic_u8string(), "...\n"); + System::print2("Generating repository ", repository_dir.generic_u8string(), "...\n"); - std::error_code ec; - fs::path failure_point; - Files::Filesystem& fs = paths.get_filesystem(); + std::error_code ec; + fs::path failure_point; + Files::Filesystem& fs = paths.get_filesystem(); - fs.remove_all(repository_dir, ec, failure_point); - Checks::check_exit(VCPKG_LINE_INFO, - !ec, - "Could not remove outdated repository directory %s due to file %s", - repository_dir.generic_u8string(), - failure_point.string()); + fs.remove_all(repository_dir, ec, failure_point); + Checks::check_exit(VCPKG_LINE_INFO, + !ec, + "Could not remove outdated repository directory %s due to file %s", + repository_dir.generic_u8string(), + failure_point.string()); - const auto cmd_line = Strings::format(R"("%s" --packages "%s" "%s" > nul)", - repogen_exe.u8string(), - packages_dir.u8string(), - repository_dir.u8string()); + const auto cmd_line = Strings::format(R"("%s" --packages "%s" "%s" > nul)", + repogen_exe.u8string(), + packages_dir.u8string(), + repository_dir.u8string()); - const int exit_code = System::cmd_execute_clean(cmd_line); - Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: IFW repository generating failed"); + const int exit_code = System::cmd_execute_clean(cmd_line); + Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: IFW repository generating failed"); - System::printf( - System::Color::success, "Generating repository %s... done.\n", repository_dir.generic_u8string()); - } + System::printf( + System::Color::success, "Generating repository %s... done.\n", repository_dir.generic_u8string()); + } - void do_installer(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths) - { - const fs::path& binarycreator_exe = paths.get_tool_exe(Tools::IFW_BINARYCREATOR); - const fs::path config_file = get_config_file_path(export_id, ifw_options, paths); - const fs::path packages_dir = get_packages_dir_path(export_id, ifw_options, paths); - const fs::path repository_dir = get_repository_dir_path(export_id, ifw_options, paths); - const fs::path installer_file = get_installer_file_path(export_id, ifw_options, paths); + void do_installer(const std::string& export_id, const Options& ifw_options, const VcpkgPaths& paths) + { + const fs::path& binarycreator_exe = paths.get_tool_exe(Tools::IFW_BINARYCREATOR); + const fs::path config_file = get_config_file_path(export_id, ifw_options, paths); + const fs::path packages_dir = get_packages_dir_path(export_id, ifw_options, paths); + const fs::path repository_dir = get_repository_dir_path(export_id, ifw_options, paths); + const fs::path installer_file = get_installer_file_path(export_id, ifw_options, paths); - System::printf("Generating installer %s...\n", installer_file.generic_u8string()); + System::printf("Generating installer %s...\n", installer_file.generic_u8string()); - std::string cmd_line; + std::string cmd_line; - std::string ifw_repo_url = ifw_options.maybe_repository_url.value_or(""); - if (!ifw_repo_url.empty()) - { - cmd_line = Strings::format(R"("%s" --online-only --config "%s" --repository "%s" "%s" > nul)", - binarycreator_exe.u8string(), - config_file.u8string(), - repository_dir.u8string(), - installer_file.u8string()); - } - else - { - cmd_line = Strings::format(R"("%s" --config "%s" --packages "%s" "%s" > nul)", - binarycreator_exe.u8string(), - config_file.u8string(), - packages_dir.u8string(), - installer_file.u8string()); - } + std::string ifw_repo_url = ifw_options.maybe_repository_url.value_or(""); + if (!ifw_repo_url.empty()) + { + cmd_line = Strings::format(R"("%s" --online-only --config "%s" --repository "%s" "%s" > nul)", + binarycreator_exe.u8string(), + config_file.u8string(), + repository_dir.u8string(), + installer_file.u8string()); + } + else + { + cmd_line = Strings::format(R"("%s" --config "%s" --packages "%s" "%s" > nul)", + binarycreator_exe.u8string(), + config_file.u8string(), + packages_dir.u8string(), + installer_file.u8string()); + } - const int exit_code = System::cmd_execute_clean(cmd_line); - Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: IFW installer generating failed"); + const int exit_code = System::cmd_execute_clean(cmd_line); + Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: IFW installer generating failed"); - System::printf(System::Color::success, "Generating installer %s... done.\n", installer_file.generic_u8string()); + System::printf( + System::Color::success, "Generating installer %s... done.\n", installer_file.generic_u8string()); + } } void do_export(const std::vector& export_plan, diff --git a/toolsrc/src/vcpkg/commands.xvsinstances.cpp b/toolsrc/src/vcpkg/commands.xvsinstances.cpp index 542ebd56c..a110bbb18 100644 --- a/toolsrc/src/vcpkg/commands.xvsinstances.cpp +++ b/toolsrc/src/vcpkg/commands.xvsinstances.cpp @@ -28,6 +28,7 @@ namespace vcpkg::Commands::X_VSInstances Checks::exit_success(VCPKG_LINE_INFO); #else + Util::unused(args, paths); Checks::exit_with_message(VCPKG_LINE_INFO, "This command is not supported on non-windows platforms."); #endif } diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp index 09f35d2b1..ab14934a2 100644 --- a/toolsrc/src/vcpkg/dependencies.cpp +++ b/toolsrc/src/vcpkg/dependencies.cpp @@ -13,45 +13,48 @@ namespace vcpkg::Dependencies { - struct ClusterInstalled + namespace { - InstalledPackageView ipv; - std::set remove_edges; - std::set original_features; - }; + struct ClusterInstalled + { + InstalledPackageView ipv; + std::set remove_edges; + std::set original_features; + }; - struct ClusterSource - { - const SourceControlFileLocation* scfl = nullptr; - std::unordered_map> build_edges; - }; + struct ClusterSource + { + const SourceControlFileLocation* scfl = nullptr; + std::unordered_map> build_edges; + }; - /// - /// Representation of a package and its features in a ClusterGraph. - /// - struct Cluster : Util::MoveOnlyBase - { - PackageSpec spec; + /// + /// Representation of a package and its features in a ClusterGraph. + /// + struct Cluster : Util::MoveOnlyBase + { + PackageSpec spec; - Optional installed; - Optional source; + Optional installed; + Optional source; - // Note: this map can contain "special" strings such as "" and "*" - std::unordered_map plus; - std::set to_install_features; - bool minus = false; - bool transient_uninstalled = true; - RequestType request_type = RequestType::AUTO_SELECTED; - }; + // Note: this map can contain "special" strings such as "" and "*" + std::unordered_map plus; + std::set to_install_features; + bool minus = false; + bool transient_uninstalled = true; + RequestType request_type = RequestType::AUTO_SELECTED; + }; - struct ClusterPtr - { - Cluster* ptr; + struct ClusterPtr + { + Cluster* ptr; - Cluster* operator->() const { return ptr; } - }; + Cluster* operator->() const { return ptr; } + }; - bool operator==(const ClusterPtr& l, const ClusterPtr& r) { return l.ptr == r.ptr; } + bool operator==(const ClusterPtr& l, const ClusterPtr& r) { return l.ptr == r.ptr; } + } } namespace std @@ -122,11 +125,11 @@ namespace vcpkg::Dependencies const PortFileProvider& m_provider; }; - std::string to_output_string(RequestType request_type, - const CStringView s, - const Build::BuildPackageOptions& options, - const fs::path& install_port_path, - const fs::path& default_port_path) + static std::string to_output_string(RequestType request_type, + const CStringView s, + const Build::BuildPackageOptions& options, + const fs::path& install_port_path, + const fs::path& default_port_path) { if (!default_port_path.empty() && !Strings::case_insensitive_ascii_starts_with(install_port_path.u8string(), default_port_path.u8string())) @@ -670,7 +673,7 @@ namespace vcpkg::Dependencies } } - //The feature was not previously installed. Mark the cluster + // The feature was not previously installed. Mark the cluster //(aka the entire port) to be removed before re-adding it. mark_minus(cluster, graph, graph_plan, prevent_default_features); diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp index f306bf4e6..8f5034eee 100644 --- a/toolsrc/src/vcpkg/export.cpp +++ b/toolsrc/src/vcpkg/export.cpp @@ -360,6 +360,12 @@ namespace vcpkg::Export } }; +#if defined(_MSC_VER) && _MSC_VER <= 1900 +// there's a bug in VS 2015 that causes a bunch of "unreferenced local variable" warnings +#pragma warning(push) +#pragma warning(disable : 4189) +#endif + options_implies(OPTION_NUGET, ret.nuget, { @@ -376,6 +382,9 @@ namespace vcpkg::Export {OPTION_IFW_CONFIG_FILE_PATH, ret.ifw_options.maybe_config_file_path}, {OPTION_IFW_INSTALLER_FILE_PATH, ret.ifw_options.maybe_installer_file_path}, }); +#if defined(_MSC_VER) && _MSC_VER <= 1900 +#pragma warning(pop) +#endif return ret; } diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index f6330e408..1812f1624 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -174,7 +174,7 @@ namespace vcpkg::Install const std::vector package_file_paths = fs.get_files_recursive(package_dir); const size_t package_remove_char_count = package_dir.generic_string().size() + 1; // +1 for the slash auto package_files = Util::fmap(package_file_paths, [package_remove_char_count](const fs::path& path) { - return std::move(std::string(path.generic_string(), package_remove_char_count)); + return std::string(path.generic_string(), package_remove_char_count); }); return SortedVector(std::move(package_files)); diff --git a/toolsrc/src/vcpkg/logicexpression.cpp b/toolsrc/src/vcpkg/logicexpression.cpp index 0cf08ee03..ccb8b00c4 100644 --- a/toolsrc/src/vcpkg/logicexpression.cpp +++ b/toolsrc/src/vcpkg/logicexpression.cpp @@ -54,9 +54,12 @@ namespace vcpkg { public: ExpressionParser(const std::string& str, const std::string& evaluation_context) - : raw_text(str), evaluation_context(evaluation_context) + : raw_text(str) + , evaluation_context(evaluation_context) + , current_iter(raw_text.begin()) + , current_char(get_current_char()) { - go_to_begin(); + skip_whitespace(); final_result = logic_expression(); @@ -77,16 +80,17 @@ namespace vcpkg bool has_error() const { return err == nullptr; } private: - bool final_result; - - std::string::const_iterator current_iter; const std::string& raw_text; + const std::string& evaluation_context; + std::string::const_iterator current_iter; char current_char; - const std::string& evaluation_context; + bool final_result; std::unique_ptr err; + char get_current_char() const { return (current_iter != raw_text.end() ? *current_iter : '\0'); } + void add_error(std::string message, int column = -1) { // avoid castcading errors by only saving the first @@ -105,16 +109,6 @@ namespace vcpkg int current_column() const { return static_cast(current_iter - raw_text.begin()); } - void go_to_begin() - { - current_iter = raw_text.begin(); - current_char = (current_iter != raw_text.end() ? *current_iter : current_char); - - if (current_char == ' ' || current_char == '\t') - { - next_skip_whitespace(); - } - } void skip_to_end() { current_iter = raw_text.end(); @@ -126,7 +120,7 @@ namespace vcpkg if (current_char != '\0') { current_iter++; - current_char = (current_iter != raw_text.end() ? *current_iter : '\0'); + current_char = get_current_char(); } return current(); } diff --git a/toolsrc/src/vcpkg/metrics.cpp b/toolsrc/src/vcpkg/metrics.cpp index 9dd520ed6..11f613830 100644 --- a/toolsrc/src/vcpkg/metrics.cpp +++ b/toolsrc/src/vcpkg/metrics.cpp @@ -307,7 +307,9 @@ namespace vcpkg::Metrics void Metrics::upload(const std::string& payload) { -#if defined(_WIN32) +#if !defined(_WIN32) + Util::unused(payload); +#else HINTERNET connect = nullptr, request = nullptr; BOOL results = FALSE; diff --git a/toolsrc/src/vcpkg/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp index 1232b940a..9cb7caff1 100644 --- a/toolsrc/src/vcpkg/paragraphs.cpp +++ b/toolsrc/src/vcpkg/paragraphs.cpp @@ -164,7 +164,7 @@ namespace vcpkg::Paragraphs } }; - Expected parse_single_paragraph(const std::string& str) + static Expected parse_single_paragraph(const std::string& str) { const std::vector p = Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs(); diff --git a/toolsrc/src/vcpkg/postbuildlint.cpp b/toolsrc/src/vcpkg/postbuildlint.cpp index c760a034f..a85d879fe 100644 --- a/toolsrc/src/vcpkg/postbuildlint.cpp +++ b/toolsrc/src/vcpkg/postbuildlint.cpp @@ -39,7 +39,7 @@ namespace vcpkg::PostBuildLint } }; - Span get_outdated_dynamic_crts(const Optional& toolset_version) + static Span get_outdated_dynamic_crts(const Optional& toolset_version) { static const std::vector V_NO_120 = { {"msvcp100.dll", R"(msvcp100\.dll)"}, @@ -462,7 +462,7 @@ namespace vcpkg::PostBuildLint return LintStatus::ERROR_DETECTED; } #endif - + Util::unused(expected_architecture, files); return LintStatus::SUCCESS; } diff --git a/toolsrc/src/vcpkg/statusparagraphs.cpp b/toolsrc/src/vcpkg/statusparagraphs.cpp index c642af59b..3c81728bb 100644 --- a/toolsrc/src/vcpkg/statusparagraphs.cpp +++ b/toolsrc/src/vcpkg/statusparagraphs.cpp @@ -7,8 +7,9 @@ namespace vcpkg { StatusParagraphs::StatusParagraphs() = default; - StatusParagraphs::StatusParagraphs(std::vector>&& ps) - : paragraphs(std::move(ps)){}; + StatusParagraphs::StatusParagraphs(std::vector>&& ps) : paragraphs(std::move(ps)) + { + } std::vector*> StatusParagraphs::find_all(const std::string& name, const Triplet& triplet) diff --git a/toolsrc/src/vcpkg/tools.cpp b/toolsrc/src/vcpkg/tools.cpp index 7d56854c6..9354493bd 100644 --- a/toolsrc/src/vcpkg/tools.cpp +++ b/toolsrc/src/vcpkg/tools.cpp @@ -274,6 +274,9 @@ namespace vcpkg const auto& program_files_32_bit = System::get_program_files_32_bit(); if (const auto pf = program_files_32_bit.get()) out_candidate_paths.push_back(*pf / "CMake" / "bin" / "cmake.exe"); +#else + // TODO: figure out if this should do anything on non-Windows + Util::unused(out_candidate_paths); #endif } virtual Optional get_version(const fs::path& path_to_exe) const override @@ -362,6 +365,9 @@ Type 'NuGet help ' for help on a specific command. const auto& program_files_32_bit = System::get_program_files_32_bit(); if (const auto pf = program_files_32_bit.get()) out_candidate_paths.push_back(*pf / "git" / "cmd" / "git.exe"); +#else + // TODO: figure out if this should do anything on non-windows + Util::unused(out_candidate_paths); #endif } diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index bc46d2cfc..4f01ed03b 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -155,9 +155,9 @@ namespace vcpkg { return m_triplets_cache.get_lazy( triplet, [&]() -> auto { - for (auto&& triplet_dir : triplets_dirs) + for (const auto& triplet_dir : triplets_dirs) { - auto&& path = triplet_dir / (triplet.canonical_name() + ".cmake"); + auto path = triplet_dir / (triplet.canonical_name() + ".cmake"); if (this->get_filesystem().exists(path)) { return path; diff --git a/toolsrc/src/vcpkg/versiont.cpp b/toolsrc/src/vcpkg/versiont.cpp index d20e6b577..2c025fa1d 100644 --- a/toolsrc/src/vcpkg/versiont.cpp +++ b/toolsrc/src/vcpkg/versiont.cpp @@ -11,7 +11,6 @@ namespace vcpkg const std::string& VersionT::to_string() const { return value; } bool operator==(const VersionT& left, const VersionT& right) { return left.to_string() == right.to_string(); } bool operator!=(const VersionT& left, const VersionT& right) { return left.to_string() != right.to_string(); } - std::string to_printf_arg(const VersionT& version) { return version.to_string(); } VersionDiff::VersionDiff() noexcept : left(), right() {} VersionDiff::VersionDiff(const VersionT& left, const VersionT& right) : left(left), right(right) {} -- cgit v1.2.3 From 5a1e9920236c9d820705e8b0d32455f8062d5a42 Mon Sep 17 00:00:00 2001 From: Phil Christensen Date: Mon, 19 Aug 2019 13:49:44 -0700 Subject: [vcpkg] allow multiple spaces in a comma list (#7754) --- toolsrc/src/vcpkg/parse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/parse.cpp b/toolsrc/src/vcpkg/parse.cpp index 9c9968249..0509339c5 100644 --- a/toolsrc/src/vcpkg/parse.cpp +++ b/toolsrc/src/vcpkg/parse.cpp @@ -66,7 +66,7 @@ namespace vcpkg::Parse // skip comma and space ++pos; - if (str[pos] == ' ') + while (str[pos] == ' ') { ++pos; } -- cgit v1.2.3 From 4da95d667c8600c80b4b5731631ebb7bcbc91f1b Mon Sep 17 00:00:00 2001 From: Curtis J Bezault Date: Tue, 20 Aug 2019 08:47:26 -0700 Subject: [vcpkg]Port toolchains (#7687) * checkpoint commit * Only set VCPKG_ENV_OVERRIDES_FILE if it exists * First pass at working port-toolchain * Update VERSION.txt * Return rvalue * Fix compilation error * Some fixes are requested by @ubsan * Fix another compilation error --- toolsrc/src/vcpkg/build.cpp | 84 +++++++++++++++++++++++++------------- toolsrc/src/vcpkg/dependencies.cpp | 2 +- 2 files changed, 56 insertions(+), 30 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 2114b7415..aeb01b27d 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -311,8 +311,8 @@ namespace vcpkg::Build const std::set& feature_list, const Triplet& triplet) { - return Util::fmap(get_dependencies(scf, feature_list, triplet), - [&](const Features& feat) { return feat.name; }); + return Util::sort_unique_erase( + Util::fmap(get_dependencies(scf, feature_list, triplet), [&](const Features& feat) { return feat.name; })); } static std::vector compute_required_feature_specs(const BuildPackageConfig& config, @@ -397,7 +397,6 @@ namespace vcpkg::Build {"CURRENT_PORT_DIR", config.port_dir}, {"TARGET_TRIPLET", triplet.canonical_name()}, {"TARGET_TRIPLET_FILE", paths.get_triplet_file_path(triplet).u8string()}, - {"ENV_OVERRIDES_FILE", config.port_dir / "environment-overrides.cmake"}, {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()}, {"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"}, {"DOWNLOADS", paths.downloads}, @@ -413,6 +412,33 @@ namespace vcpkg::Build variables.push_back({"GIT", git_exe_path}); } + const Files::Filesystem& fs = paths.get_filesystem(); + if (fs.is_regular_file(config.port_dir / "environment-overrides.cmake")) + { + variables.emplace_back("VCPKG_ENV_OVERRIDES_FILE", config.port_dir / "environment-overrides.cmake"); + } + + std::vector dependencies = + filter_dependencies_to_specs(config.scfl.source_control_file->core_paragraph->depends, triplet); + + std::vector port_toolchains; + for (const FeatureSpec& dependency : dependencies) + { + const fs::path port_toolchain_path = paths.installed / dependency.triplet().canonical_name() / "share" / + dependency.spec().name() / "port-toolchain.cmake"; + + if (fs.is_regular_file(port_toolchain_path)) + { + System::print2(port_toolchain_path.u8string()); + port_toolchains.emplace_back(port_toolchain_path.u8string()); + } + } + + if (!port_toolchains.empty()) + { + variables.emplace_back("VCPKG_PORT_TOOLCHAINS", Strings::join(";", port_toolchains)); + } + return variables; } @@ -620,58 +646,53 @@ namespace vcpkg::Build const int max_port_file_count = 100; // the order of recursive_directory_iterator is undefined so save the names to sort - std::vector> hashes_files; + std::vector port_files; for (auto& port_file : fs::stdfs::recursive_directory_iterator(config.port_dir)) { if (fs::is_regular_file(fs.status(VCPKG_LINE_INFO, port_file))) { - hashes_files.emplace_back(vcpkg::Hash::get_file_hash(fs, port_file, "SHA1"), - port_file.path().filename().u8string()); + port_files.emplace_back(port_file.path().filename().u8string(), + vcpkg::Hash::get_file_hash(fs, port_file, "SHA1")); - if (hashes_files.size() > max_port_file_count) + if (port_files.size() > max_port_file_count) { - abi_tag_entries.emplace_back(AbiEntry{"no_hash_max_portfile", ""}); + abi_tag_entries.emplace_back("no_hash_max_portfile", ""); break; } } } - if (hashes_files.size() <= max_port_file_count) + if (port_files.size() <= max_port_file_count) { - Util::sort(hashes_files); + Util::sort(port_files, [](const AbiEntry& l, const AbiEntry& r) { + return l.value < r.value || (l.value == r.value && l.key < r.key); + }); - for (auto& hash_file : hashes_files) - { - // We've already sorted by hash so it's safe to write down the - // filename, which will be consistent across machines. - abi_tag_entries.emplace_back(AbiEntry{std::move(hash_file.second), std::move(hash_file.first)}); - } + std::move(port_files.begin(), port_files.end(), std::back_inserter(abi_tag_entries)); } - abi_tag_entries.emplace_back(AbiEntry{"cmake", paths.get_tool_version(Tools::CMAKE)}); + abi_tag_entries.emplace_back("cmake", paths.get_tool_version(Tools::CMAKE)); #if defined(_WIN32) - abi_tag_entries.emplace_back(AbiEntry{"powershell", paths.get_tool_version("powershell-core")}); + abi_tag_entries.emplace_back("powershell", paths.get_tool_version("powershell-core")); #endif - abi_tag_entries.emplace_back(AbiEntry{ + abi_tag_entries.emplace_back( "vcpkg_fixup_cmake_targets", - vcpkg::Hash::get_file_hash(fs, paths.scripts / "cmake" / "vcpkg_fixup_cmake_targets.cmake", "SHA1")}); - - abi_tag_entries.emplace_back(AbiEntry{"triplet", pre_build_info.triplet_abi_tag}); + vcpkg::Hash::get_file_hash(fs, paths.scripts / "cmake" / "vcpkg_fixup_cmake_targets.cmake", "SHA1")); - const std::string features = Strings::join(";", config.feature_list); - abi_tag_entries.emplace_back(AbiEntry{"features", features}); + abi_tag_entries.emplace_back("triplet", pre_build_info.triplet_abi_tag); + abi_tag_entries.emplace_back("features", Strings::join(";", config.feature_list)); if (pre_build_info.public_abi_override) { - abi_tag_entries.emplace_back(AbiEntry{ + abi_tag_entries.emplace_back( "public_abi_override", - Hash::get_string_hash(pre_build_info.public_abi_override.value_or_exit(VCPKG_LINE_INFO), "SHA1")}); + Hash::get_string_hash(pre_build_info.public_abi_override.value_or_exit(VCPKG_LINE_INFO), "SHA1")); } if (config.build_package_options.use_head_version == UseHeadVersion::YES) - abi_tag_entries.emplace_back(AbiEntry{"head", ""}); + abi_tag_entries.emplace_back("head", ""); const std::string full_abi_info = Strings::join("", abi_tag_entries, [](const AbiEntry& p) { return p.key + " " + p.value + "\n"; }); @@ -765,6 +786,7 @@ namespace vcpkg::Build const std::string& name = config.scf.core_paragraph->name; std::vector required_fspecs = compute_required_feature_specs(config, status_db); + std::vector required_fspecs_copy = required_fspecs; // extract out the actual package ids auto dep_pspecs = Util::fmap(required_fspecs, [](FeatureSpec const& fspec) { return fspec.spec(); }); @@ -1027,8 +1049,12 @@ namespace vcpkg::Build if (port) { - args.emplace_back("CMAKE_ENV_OVERRIDES_FILE", - port.value_or_exit(VCPKG_LINE_INFO).source_location / "environment-overrides.cmake"); + const SourceControlFileLocation& scfl = port.value_or_exit(VCPKG_LINE_INFO); + + if (paths.get_filesystem().is_regular_file(scfl.source_location / "environment-overrides.cmake")) + { + args.emplace_back("VCPKG_ENV_OVERRIDES_FILE", scfl.source_location / "environment-overrides.cmake"); + } } const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, ports_cmake_script_path, args); diff --git a/toolsrc/src/vcpkg/dependencies.cpp b/toolsrc/src/vcpkg/dependencies.cpp index ab14934a2..7c3f2df4c 100644 --- a/toolsrc/src/vcpkg/dependencies.cpp +++ b/toolsrc/src/vcpkg/dependencies.cpp @@ -674,7 +674,7 @@ namespace vcpkg::Dependencies } // The feature was not previously installed. Mark the cluster - //(aka the entire port) to be removed before re-adding it. + // (aka the entire port) to be removed before re-adding it. mark_minus(cluster, graph, graph_plan, prevent_default_features); return follow_plus_dependencies(feature, cluster, graph, graph_plan, prevent_default_features); -- cgit v1.2.3 From 051a6fd5b3d83fedc83592236413c9b8c0015c6d Mon Sep 17 00:00:00 2001 From: Phil Christensen Date: Wed, 21 Aug 2019 13:48:47 -0700 Subject: [boost] split Build-Depends on multipls lines --- toolsrc/src/vcpkg/parse.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/parse.cpp b/toolsrc/src/vcpkg/parse.cpp index 0509339c5..8f90aef15 100644 --- a/toolsrc/src/vcpkg/parse.cpp +++ b/toolsrc/src/vcpkg/parse.cpp @@ -44,6 +44,11 @@ namespace vcpkg::Parse return nullptr; } + static bool is_whitespace(char c) + { + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; + } + std::vector parse_comma_list(const std::string& str) { if (str.empty()) @@ -66,7 +71,7 @@ namespace vcpkg::Parse // skip comma and space ++pos; - while (str[pos] == ' ') + while (is_whitespace(str[pos])) { ++pos; } -- cgit v1.2.3 From 94ef325828961dc5c9f721a0eb9fcc5ba8a2b765 Mon Sep 17 00:00:00 2001 From: Curtis J Bezault Date: Wed, 21 Aug 2019 14:23:15 -0700 Subject: [vcpkg] Fix gcc-9 warning (#7816) * drop one usage of span in export. Span is not appropriate for rvalues * Add back reference * Fix @ubsan 's comments --- toolsrc/src/vcpkg/export.cpp | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp index 8f5034eee..5ceb47adf 100644 --- a/toolsrc/src/vcpkg/export.cpp +++ b/toolsrc/src/vcpkg/export.cpp @@ -339,26 +339,27 @@ namespace vcpkg::Export struct OptionPair { - const std::string& name; + const StringLiteral& name; Optional& out_opt; }; - const auto options_implies = - [&](const std::string& main_opt_name, bool main_opt, Span implying_opts) { - if (main_opt) - { - for (auto&& opt : implying_opts) - opt.out_opt = maybe_lookup(options.settings, opt.name); - } - else - { - for (auto&& opt : implying_opts) - Checks::check_exit(VCPKG_LINE_INFO, - !maybe_lookup(options.settings, opt.name), - "%s is only valid with %s", - opt.name, - main_opt_name); - } - }; + const auto options_implies = [&](const StringLiteral& main_opt_name, + bool is_main_opt, + const std::initializer_list& implying_opts) { + if (is_main_opt) + { + for (auto&& opt : implying_opts) + opt.out_opt = maybe_lookup(options.settings, opt.name); + } + else + { + for (auto&& opt : implying_opts) + Checks::check_exit(VCPKG_LINE_INFO, + !maybe_lookup(options.settings, opt.name), + "%s is only valid with %s", + opt.name, + main_opt_name); + } + }; #if defined(_MSC_VER) && _MSC_VER <= 1900 // there's a bug in VS 2015 that causes a bunch of "unreferenced local variable" warnings -- cgit v1.2.3 From cc35672763a340b4d6d836a2b9e4ec0e3d703e50 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Tue, 20 Aug 2019 18:43:51 -0700 Subject: =?UTF-8?q?(#7798)=20[vcpkg]=20Fix=20the=20build=20on=20FreeBSD=20?= =?UTF-8?q?=F0=9F=98=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a `#else` line to `toolsrc/src/vcpkg/base/files.cpp`. On Linux and macOS, there are specific ways to copy from file descriptor to file descriptor, but on FreeBSD there isn't (as far as I could tell). This change does a copy using the POSIX standard `read` and `write` calls. (This change was to `RealFilesystem::rename_or_copy`). We expect to have people on FreeBSD install CMake themselves, and use `./bootstrap.sh -useSystemBinaries`, in order to build vcpkg. Since CMake 3.15.2 exists in the FreeBSD 12 (latest stable) package manager, it's trivial to install it. --- toolsrc/src/vcpkg/base/files.cpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index bbf37fd25..5ebe8d834 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -8,9 +8,8 @@ #include #include -#if defined(__linux__) || defined(__APPLE__) +#if !defined(_WIN32) #include -#include #include #include #include @@ -396,7 +395,7 @@ namespace vcpkg::Files { this->rename(oldpath, newpath, ec); Util::unused(temp_suffix); -#if defined(__linux__) || defined(__APPLE__) +#if !defined(_WIN32) if (ec) { auto dst = newpath; @@ -419,6 +418,33 @@ namespace vcpkg::Files auto written_bytes = sendfile(o_fd, i_fd, &bytes, info.st_size); #elif defined(__APPLE__) auto written_bytes = fcopyfile(i_fd, o_fd, 0, COPYFILE_ALL); +#else + ssize_t written_bytes = 0; + { + constexpr std::size_t buffer_length = 4096; + auto buffer = std::make_unique(buffer_length); + while (auto read_bytes = read(i_fd, buffer.get(), buffer_length)) + { + if (read_bytes == -1) + { + written_bytes = -1; + break; + } + auto remaining = read_bytes; + while (remaining > 0) { + auto read_result = write(o_fd, buffer.get(), remaining); + if (read_result == -1) + { + written_bytes = -1; + // break two loops + goto copy_failure; + } + remaining -= read_result; + } + } + + copy_failure: ; + } #endif if (written_bytes == -1) { -- cgit v1.2.3 From 13c95f16bfab4e516d088e15a1e77733b3f8745f Mon Sep 17 00:00:00 2001 From: Phil Christensen Date: Fri, 23 Aug 2019 10:20:18 -0700 Subject: clean up list parsing logic and add clear warnings --- toolsrc/src/vcpkg/parse.cpp | 88 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 20 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/parse.cpp b/toolsrc/src/vcpkg/parse.cpp index 8f90aef15..91b2b2786 100644 --- a/toolsrc/src/vcpkg/parse.cpp +++ b/toolsrc/src/vcpkg/parse.cpp @@ -3,6 +3,7 @@ #include #include +#include namespace vcpkg::Parse { @@ -58,26 +59,73 @@ namespace vcpkg::Parse std::vector out; - size_t cur = 0; - do - { - auto pos = str.find(',', cur); - if (pos == std::string::npos) - { - out.push_back(str.substr(cur)); - break; - } - out.push_back(str.substr(cur, pos - cur)); - - // skip comma and space - ++pos; - while (is_whitespace(str[pos])) - { - ++pos; - } - - cur = pos; - } while (cur != std::string::npos); + auto iter = str.cbegin(); + + do { + // Trim leading whitespace of each element + while (iter != str.cend() && is_whitespace(*iter)) + { + ++iter; + } + + // Allow commas inside of []. + bool bracket_nesting = false; + + auto element_begin = iter; + auto element_end = iter; + while (iter != str.cend() && (*iter != ',' || bracket_nesting)) + { + char value = *iter; + + // do not support nested [] + if (value == '[') + { + bracket_nesting = true; + } + else if (value == ']') + { + bracket_nesting = false; + } + + ++iter; + + // Trim ending whitespace + if (!is_whitespace(value)) + { + // Update element_end after iter is incremented so it will be one past. + element_end = iter; + } + } + + if (element_begin == element_end) + { + System::print2( System::Color::warning, + "Warning: empty element in list\n" + "> '", str, "'\n" + "> ", std::string(static_cast(element_begin - str.cbegin()), ' '), "^\n" + ); + } + else + { + out.push_back({ element_begin, element_end }); + } + + if (iter != str.cend()) + { + //Not at the end, must be at a comma that needs to be stepped over + ++iter; + + if (iter == str.end()) + { + System::print2(System::Color::warning, + "Warning: empty element in list\n" + "> '", str, "'\n" + "> ", std::string(str.length(), ' '), "^\n" + ); + } + } + + } while (iter != str.cend()); return out; } -- cgit v1.2.3 From 373aeff92288b6e0bb49db2db98432229a2c9988 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 24 Aug 2019 13:01:57 -0700 Subject: [vcpkg] Move do_build_package_and_clean_buildtrees() above generating cpkg_abi_info.txt so it will be included in the package. (#7864) --- toolsrc/src/vcpkg/build.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index aeb01b27d..a2e90f33b 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -872,14 +872,14 @@ namespace vcpkg::Build System::printf("Could not locate cached archive: %s\n", archive_path.u8string()); } + ExtendedBuildResult result = do_build_package_and_clean_buildtrees( + paths, pre_build_info, spec, pre_build_info.public_abi_override.value_or(abi_tag_and_file->tag), config); + fs.create_directories(abi_package_dir, ec); Checks::check_exit(VCPKG_LINE_INFO, !ec, "Coud not create directory %s", abi_package_dir.u8string()); fs.copy_file(abi_tag_and_file->tag_file, abi_file_in_package, fs::stdfs::copy_options::none, ec); Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not copy into file: %s", abi_file_in_package.u8string()); - ExtendedBuildResult result = do_build_package_and_clean_buildtrees( - paths, pre_build_info, spec, pre_build_info.public_abi_override.value_or(abi_tag_and_file->tag), config); - if (config.build_package_options.binary_caching == BinaryCaching::YES && result.code == BuildResult::SUCCEEDED) { const auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip"); -- cgit v1.2.3 From 782723959399a1a0725ac4921b1b7a7c9d10baf7 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 8 Aug 2019 16:14:59 -0700 Subject: =?UTF-8?q?(#7757)=20[vcpkg]=20Switch=20to=20internal=20hash=20alg?= =?UTF-8?q?orithms=20=F0=9F=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On non-Windows platforms, there is no standard way to get the hash of an item -- before this PR, what we did was check for the existence of a few common utility names (shasum, sha1, sha256, sha512), and then call that utility on a file we created containing the contents we wish to hash. This PR adds internal hashers for sha1, sha256, and sha512, and standardizes the interface to allow anyone to implement hashers in the future. These hashers are not extremely optimized, so it's likely that in the future we could get more optimized, but for now we just call out to BCryptHasher on Windows, since it's standard and easy to use (and about 2x faster for sha1 and sha256, and 1.5x faster for sha512). However, they are reasonably fast for being unoptimized. I attempted a few minor optimizations, which actually made the code slower! So as of right now, it's implemented as just a basic conversion of the code on Wikipedia to C++. I have tested these on the standard NIST test vectors (and those test vectors are located in vcpkg-test/hash.cpp). --- toolsrc/src/vcpkg-test/hash.cpp | 276 +++++++++++ toolsrc/src/vcpkg/base/downloads.cpp | 2 +- toolsrc/src/vcpkg/base/hash.cpp | 830 +++++++++++++++++++++++++++------- toolsrc/src/vcpkg/base/stringview.cpp | 6 +- toolsrc/src/vcpkg/build.cpp | 29 +- toolsrc/src/vcpkg/commands.cpp | 11 +- toolsrc/src/vcpkg/metrics.cpp | 2 +- 7 files changed, 984 insertions(+), 172 deletions(-) create mode 100644 toolsrc/src/vcpkg-test/hash.cpp (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/hash.cpp b/toolsrc/src/vcpkg-test/hash.cpp new file mode 100644 index 000000000..9f3ccc25e --- /dev/null +++ b/toolsrc/src/vcpkg-test/hash.cpp @@ -0,0 +1,276 @@ +#include + +#include + +#include +#include +#include +#include + +namespace Hash = vcpkg::Hash; +using vcpkg::StringView; + +// Require algorithm: Hash::Algorithm::Tag to be in scope +#define CHECK_HASH(size, value, real_hash) \ + do \ + { \ + unsigned char data[size]; \ + std::fill(std::begin(data), std::end(data), static_cast(value)); \ + const auto hash = Hash::get_bytes_hash(data, data + size, algorithm); \ + REQUIRE(hash == real_hash); \ + } while (0) + +#define CHECK_HASH_OF(data, real_hash) \ + do \ + { \ + const auto hash = Hash::get_bytes_hash(std::begin(data), std::end(data), algorithm); \ + REQUIRE(hash == real_hash); \ + } while (0) + +#define CHECK_HASH_STRING(data, real_hash) \ + do \ + { \ + const auto hash = Hash::get_string_hash(data, algorithm); \ + REQUIRE(hash == real_hash); \ + } while (0) + +// Requires hasher: std::unique_ptr to be in scope +#define CHECK_HASH_LARGE(size, value, real_hash) \ + do \ + { \ + hasher->clear(); \ + std::uint64_t remaining = size; \ + unsigned char buffer[512]; \ + std::fill(std::begin(buffer), std::end(buffer), static_cast(value)); \ + while (remaining) \ + { \ + if (remaining < 512) \ + { \ + hasher->add_bytes(std::begin(buffer), std::begin(buffer) + remaining); \ + remaining = 0; \ + } \ + else \ + { \ + hasher->add_bytes(std::begin(buffer), std::end(buffer)); \ + remaining -= 512; \ + } \ + } \ + REQUIRE(hasher->get_hash() == real_hash); \ + } while (0) + +TEST_CASE ("SHA1: basic tests", "[hash][sha1]") +{ + const auto algorithm = Hash::Algorithm::Sha1; + + CHECK_HASH_STRING("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"); + CHECK_HASH_STRING(";", "2d14ab97cc3dc294c51c0d6814f4ea45f4b4e312"); + CHECK_HASH_STRING("asdifasdfnas", "b77eb8a1b4c2ef6716d7d302647e4511b1a638a6"); + CHECK_HASH_STRING("asdfanvoinaoifawenflawenfiwnofvnasfjvnaslkdfjlkasjdfanm," + "werflawoienfowanevoinwai32910u2740918741o;j;wejfqwioaher9283hrpf;asd", + "c69bcd30c196c7050906d212722dd7a7659aad04"); +} + +TEST_CASE ("SHA1: NIST test cases (small)", "[hash][sha1]") +{ + const auto algorithm = Hash::Algorithm::Sha1; + + CHECK_HASH_STRING("abc", "a9993e364706816aba3e25717850c26c9cd0d89d"); + CHECK_HASH_STRING("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "84983e441c3bd26ebaae4aa1f95129e5e54670f1"); +} + +TEST_CASE ("SHA256: basic tests", "[hash][sha256]") +{ + const auto algorithm = Hash::Algorithm::Sha256; + + CHECK_HASH_STRING("", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + CHECK_HASH_STRING(";", "41b805ea7ac014e23556e98bb374702a08344268f92489a02f0880849394a1e4"); + CHECK_HASH_STRING("asdifasdfnas", "2bb1fb910831fdc11d5a3996425a84ace27aeb81c9c20ace9f60ac1b3218b291"); + CHECK_HASH_STRING("asdfanvoinaoifawenflawenfiwnofvnasfjvnaslkdfjlkasjdfanm," + "werflawoienfowanevoinwai32910u2740918741o;j;wejfqwioaher9283hrpf;asd", + "10c98034b424d4e40ca933bc524ea38b4e53290d76e8b38edc4ea2fec7f529aa"); +} + +TEST_CASE ("SHA256: NIST test cases (small)", "[hash][sha256]") +{ + const auto algorithm = Hash::Algorithm::Sha256; + + CHECK_HASH(1, 0xbd, "68325720aabd7c82f30f554b313d0570c95accbb7dc4b5aae11204c08ffe732b"); + { + const unsigned char data[] = {0xc9, 0x8c, 0x8e, 0x55}; + CHECK_HASH_OF(data, "7abc22c0ae5af26ce93dbb94433a0e0b2e119d014f8e7f65bd56c61ccccd9504"); + } + CHECK_HASH(55, 0, "02779466cdec163811d078815c633f21901413081449002f24aa3e80f0b88ef7"); + CHECK_HASH(56, 0, "d4817aa5497628e7c77e6b606107042bbba3130888c5f47a375e6179be789fbb"); + CHECK_HASH(57, 0, "65a16cb7861335d5ace3c60718b5052e44660726da4cd13bb745381b235a1785"); + CHECK_HASH(64, 0, "f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b"); + CHECK_HASH(1000, 0, "541b3e9daa09b20bf85fa273e5cbd3e80185aa4ec298e765db87742b70138a53"); + CHECK_HASH(1000, 'A', "c2e686823489ced2017f6059b8b239318b6364f6dcd835d0a519105a1eadd6e4"); + CHECK_HASH(1005, 'U', "f4d62ddec0f3dd90ea1380fa16a5ff8dc4c54b21740650f24afc4120903552b0"); +} + +TEST_CASE ("SHA512: NIST test cases (small)", "[hash][sha512]") +{ + const auto algorithm = Hash::Algorithm::Sha512; + + CHECK_HASH_STRING("", + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f" + "63b931bd47417a81a538327af927da3e"); + + CHECK_HASH(111, + 0, + "77ddd3a542e530fd047b8977c657ba6ce72f1492e360b2b2212cd264e75ec03882e4ff0525517ab4207d14c70c2259ba88d4d33" + "5ee0e7e20543d22102ab1788c"); + CHECK_HASH(112, + 0, + "2be2e788c8a8adeaa9c89a7f78904cacea6e39297d75e0573a73c756234534d6627ab4156b48a6657b29ab8beb73334040ad39e" + "ad81446bb09c70704ec707952"); + CHECK_HASH(113, + 0, + "0e67910bcf0f9ccde5464c63b9c850a12a759227d16b040d98986d54253f9f34322318e56b8feb86c5fb2270ed87f31252f7f68" + "493ee759743909bd75e4bb544"); + CHECK_HASH(122, + 0, + "4f3f095d015be4a7a7cc0b8c04da4aa09e74351e3a97651f744c23716ebd9b3e822e5077a01baa5cc0ed45b9249e88ab343d433" + "3539df21ed229da6f4a514e0f"); + CHECK_HASH(1000, + 0, + "ca3dff61bb23477aa6087b27508264a6f9126ee3a004f53cb8db942ed345f2f2d229b4b59c859220a1cf1913f34248e3803bab6" + "50e849a3d9a709edc09ae4a76"); + CHECK_HASH(1000, + 'A', + "329c52ac62d1fe731151f2b895a00475445ef74f50b979c6f7bb7cae349328c1d4cb4f7261a0ab43f936a24b000651d4a824fcd" + "d577f211aef8f806b16afe8af"); + CHECK_HASH(1005, + 'U', + "59f5e54fe299c6a8764c6b199e44924a37f59e2b56c3ebad939b7289210dc8e4c21b9720165b0f4d4374c90f1bf4fb4a5ace17a" + "1161798015052893a48c3d161"); +} + +TEST_CASE ("SHA256: NIST test cases (large)", "[.][hash-expensive][sha256-expensive]") +{ + auto hasher = Hash::get_hasher_for(Hash::Algorithm::Sha256); + CHECK_HASH_LARGE(1'000'000, 0, "d29751f2649b32ff572b5e0a9f541ea660a50f94ff0beedfb0b692b924cc8025"); + CHECK_HASH_LARGE(0x2000'0000, 'Z', "15a1868c12cc53951e182344277447cd0979536badcc512ad24c67e9b2d4f3dd"); + CHECK_HASH_LARGE(0x4100'0000, 0, "461c19a93bd4344f9215f5ec64357090342bc66b15a148317d276e31cbc20b53"); + CHECK_HASH_LARGE(0x6000'003E, 'B', "c23ce8a7895f4b21ec0daf37920ac0a262a220045a03eb2dfed48ef9b05aabea"); +} + +TEST_CASE ("SHA512: NIST test cases (large)", "[.][hash-expensive][sha512-expensive]") +{ + auto hasher = Hash::get_hasher_for(Hash::Algorithm::Sha512); + CHECK_HASH_LARGE(1'000'000, + 0, + "ce044bc9fd43269d5bbc946cbebc3bb711341115cc4abdf2edbc3ff2c57ad4b15deb699bda257fea5aef9c6e55fcf4cf9" + "dc25a8c3ce25f2efe90908379bff7ed"); + CHECK_HASH_LARGE(0x2000'0000, + 'Z', + "da172279f3ebbda95f6b6e1e5f0ebec682c25d3d93561a1624c2fa9009d64c7e9923f3b46bcaf11d39a531f43297992ba" + "4155c7e827bd0f1e194ae7ed6de4cac"); + CHECK_HASH_LARGE(0x4100'0000, + 0, + "14b1be901cb43549b4d831e61e5f9df1c791c85b50e85f9d6bc64135804ad43ce8402750edbe4e5c0fc170b99cf78b9f4" + "ecb9c7e02a157911d1bd1832d76784f"); + CHECK_HASH_LARGE(0x6000'003E, + 'B', + "fd05e13eb771f05190bd97d62647157ea8f1f6949a52bb6daaedbad5f578ec59b1b8d6c4a7ecb2feca6892b4dc1387716" + "70a0f3bd577eea326aed40ab7dd58b1"); +} + +#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) +using Catch::Benchmark::Chronometer; +void benchmark_hasher(Chronometer& meter, Hash::Hasher& hasher, std::uint64_t size, unsigned char byte) noexcept +{ + unsigned char buffer[1024]; + std::fill(std::begin(buffer), std::end(buffer), byte); + + meter.measure([&] { + hasher.clear(); + std::uint64_t remaining = size; + while (remaining) + { + if (remaining < 512) + { + hasher.add_bytes(std::begin(buffer), std::begin(buffer) + remaining); + remaining = 0; + } + else + { + hasher.add_bytes(std::begin(buffer), std::end(buffer)); + remaining -= 512; + } + } + hasher.get_hash(); + }); +} + +TEST_CASE ("SHA1: benchmark", "[.][hash][sha256][!benchmark]") +{ + using Catch::Benchmark::Chronometer; + + auto hasher = Hash::get_hasher_for(Hash::Algorithm::Sha1); + + BENCHMARK_ADVANCED("0 x 1'000'000")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 1'000'000, 0); + }; + BENCHMARK_ADVANCED("'Z' x 0x2000'0000")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 0x2000'0000, 'Z'); + }; + BENCHMARK_ADVANCED("0 x 0x4100'0000")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 0x4100'0000, 0); + }; + BENCHMARK_ADVANCED("'B' x 0x6000'003E")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 0x6000'003E, 'B'); + }; +} + +TEST_CASE ("SHA256: benchmark", "[.][hash][sha256][!benchmark]") +{ + using Catch::Benchmark::Chronometer; + + auto hasher = Hash::get_hasher_for(Hash::Algorithm::Sha256); + + BENCHMARK_ADVANCED("0 x 1'000'000")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 1'000'000, 0); + }; + BENCHMARK_ADVANCED("'Z' x 0x2000'0000")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 0x2000'0000, 'Z'); + }; + BENCHMARK_ADVANCED("0 x 0x4100'0000")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 0x4100'0000, 0); + }; + BENCHMARK_ADVANCED("'B' x 0x6000'003E")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 0x6000'003E, 'B'); + }; +} + +TEST_CASE ("SHA512: large -- benchmark", "[.][hash][sha512][!benchmark]") +{ + auto hasher = Hash::get_hasher_for(Hash::Algorithm::Sha512); + + BENCHMARK_ADVANCED("0 x 1'000'000")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 1'000'000, 0); + }; + BENCHMARK_ADVANCED("'Z' x 0x2000'0000")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 0x2000'0000, 'Z'); + }; + BENCHMARK_ADVANCED("0 x 0x4100'0000")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 0x4100'0000, 0); + }; + BENCHMARK_ADVANCED("'B' x 0x6000'003E")(Catch::Benchmark::Chronometer meter) + { + benchmark_hasher(meter, *hasher, 0x6000'003E, 'B'); + }; +} +#endif diff --git a/toolsrc/src/vcpkg/base/downloads.cpp b/toolsrc/src/vcpkg/base/downloads.cpp index 4bb2178e5..df6b1be09 100644 --- a/toolsrc/src/vcpkg/base/downloads.cpp +++ b/toolsrc/src/vcpkg/base/downloads.cpp @@ -127,7 +127,7 @@ namespace vcpkg::Downloads const fs::path& path, const std::string& sha512) { - std::string actual_hash = vcpkg::Hash::get_file_hash(fs, path, "SHA512"); + std::string actual_hash = vcpkg::Hash::get_file_hash(VCPKG_LINE_INFO, fs, path, Hash::Algorithm::Sha512); // // This is the NEW hash for 7zip diff --git a/toolsrc/src/vcpkg/base/hash.cpp b/toolsrc/src/vcpkg/base/hash.cpp index 62a01ed17..11df3e329 100644 --- a/toolsrc/src/vcpkg/base/hash.cpp +++ b/toolsrc/src/vcpkg/base/hash.cpp @@ -14,238 +14,758 @@ #ifndef NT_SUCCESS #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) #endif + #endif namespace vcpkg::Hash { - static void verify_has_only_allowed_chars(const std::string& s) + using uchar = unsigned char; + + Optional algorithm_from_string(StringView sv) noexcept + { + if (Strings::case_insensitive_ascii_equals(sv, "SHA1")) + { + return {Algorithm::Sha1}; + } + if (Strings::case_insensitive_ascii_equals(sv, "SHA256")) + { + return {Algorithm::Sha256}; + } + if (Strings::case_insensitive_ascii_equals(sv, "SHA512")) + { + return {Algorithm::Sha512}; + } + + return {}; + } + + const char* to_string(Algorithm algo) noexcept { - static const std::regex ALLOWED_CHARS{"^[a-zA-Z0-9-]*$"}; - Checks::check_exit(VCPKG_LINE_INFO, - std::regex_match(s, ALLOWED_CHARS), - "Only alphanumeric chars and dashes are currently allowed. String was:\n" - " % s", - s); + switch (algo) + { + case Algorithm::Sha1: return "SHA1"; + case Algorithm::Sha256: return "SHA256"; + case Algorithm::Sha512: return "SHA512"; + default: vcpkg::Checks::exit_fail(VCPKG_LINE_INFO); + } } -#if defined(_WIN32) + namespace { - std::string to_hex(const unsigned char* string, const size_t bytes) + struct UInt128 { - static constexpr char HEX_MAP[] = "0123456789abcdef"; + std::uint64_t top; + std::uint64_t bottom; - std::string output; - output.resize(2 * bytes); + UInt128() = default; + UInt128(std::uint64_t value) : top(0), bottom(value) {} - size_t current_char = 0; - for (size_t i = 0; i < bytes; i++) + UInt128& operator<<=(int by) noexcept + { + if (by == 0) + { + return *this; + } + + if (by < 64) + { + top <<= by; + const auto shift_up = bottom >> (64 - by); + top |= shift_up; + bottom <<= by; + } + else + { + top = bottom; + top <<= (by - 64); + } + + return *this; + } + + UInt128& operator>>=(int by) noexcept + { + if (by == 0) + { + return *this; + } + + if (by < 64) + { + bottom >>= by; + const auto shift_down = top << (64 - by); + bottom |= shift_down; + top >>= by; + } + else + { + bottom = top; + bottom >>= (by - 64); + } + + return *this; + } + + UInt128& operator+=(std::size_t lhs) noexcept + { + // bottom + lhs > uint64::max + if (bottom > std::numeric_limits::max() - lhs) + { + top += 1; + } + bottom += lhs; + return *this; + } + }; + + } + template + void top_bits(T) = delete; + + static constexpr uchar top_bits(uchar x) noexcept { return x; } + static constexpr uchar top_bits(std::uint32_t x) noexcept { return (x >> 24) & 0xFF; } + static constexpr uchar top_bits(std::uint64_t x) noexcept { return (x >> 56) & 0xFF; } + static constexpr uchar top_bits(UInt128 x) noexcept { return top_bits(x.top); } + + // treats UIntTy as big endian for the purpose of this mapping + template + static std::string to_hex(const UIntTy* start, const UIntTy* end) noexcept + { + static constexpr char HEX_MAP[] = "0123456789abcdef"; + + std::string output; + output.resize(2 * sizeof(UIntTy) * (end - start)); + + std::size_t output_index = 0; + for (const UIntTy* it = start; it != end; ++it) + { + // holds *it in a big-endian buffer, for copying into output + uchar buff[sizeof(UIntTy)]; + UIntTy tmp = *it; + for (uchar& ch : buff) + { + ch = top_bits(tmp); + tmp <<= 8; + } + + for (const auto byte : buff) { // high - output[current_char] = HEX_MAP[(string[i] & 0xF0) >> 4]; - ++current_char; + output[output_index] = HEX_MAP[(byte & 0xF0) >> 4]; + ++output_index; // low - output[current_char] = HEX_MAP[(string[i] & 0x0F)]; - ++current_char; + output[output_index] = HEX_MAP[byte & 0x0F]; + ++output_index; } - - return output; } - class BCryptHasher + return output; + } + + namespace + { +#if defined(_WIN32) + BCRYPT_ALG_HANDLE get_alg_handle(LPCWSTR algorithm_identifier) noexcept { - struct BCryptAlgorithmHandle : Util::ResourceBase + BCRYPT_ALG_HANDLE result; + auto error = BCryptOpenAlgorithmProvider(&result, algorithm_identifier, nullptr, 0); + if (!NT_SUCCESS(error)) { - BCRYPT_ALG_HANDLE handle = nullptr; + Checks::exit_with_message(VCPKG_LINE_INFO, "Failure to open algorithm: %ls", algorithm_identifier); + } + + return result; + } - ~BCryptAlgorithmHandle() + struct BCryptHasher : Hasher + { + static const BCRYPT_ALG_HANDLE sha1_alg_handle; + static const BCRYPT_ALG_HANDLE sha256_alg_handle; + static const BCRYPT_ALG_HANDLE sha512_alg_handle; + + explicit BCryptHasher(Algorithm algo) noexcept + { + switch (algo) { - if (handle) BCryptCloseAlgorithmProvider(handle, 0); + case Algorithm::Sha1: alg_handle = sha1_alg_handle; break; + case Algorithm::Sha256: alg_handle = sha256_alg_handle; break; + case Algorithm::Sha512: alg_handle = sha512_alg_handle; break; + default: Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown algorithm"); } - }; - struct BCryptHashHandle : Util::ResourceBase + clear(); + } + + virtual void add_bytes(const void* start_, const void* end_) noexcept override { - BCRYPT_HASH_HANDLE handle = nullptr; + // BCryptHashData takes its input as non-const, but does not modify it + uchar* start = const_cast(static_cast(start_)); + const uchar* end = static_cast(end_); + Checks::check_exit(VCPKG_LINE_INFO, end - start >= 0); + + // only matters on 64-bit -- BCryptHasher takes an unsigned long + // length, so if you have an array bigger than 2**32-1 elements, + // you have a problem. +#if defined(_M_AMD64) || defined(_M_ARM64) + constexpr std::ptrdiff_t max = std::numeric_limits::max(); + Checks::check_exit(VCPKG_LINE_INFO, end - start <= max); +#endif - ~BCryptHashHandle() - { - if (handle) BCryptDestroyHash(handle); - } - }; + const auto length = static_cast(end - start); + const NTSTATUS error_code = BCryptHashData(hash_handle, start, length, 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to process a chunk"); + } - static void initialize_hash_handle(BCryptHashHandle& hash_handle, - const BCryptAlgorithmHandle& algorithm_handle) + virtual void clear() noexcept override { - const NTSTATUS error_code = - BCryptCreateHash(algorithm_handle.handle, &hash_handle.handle, nullptr, 0, nullptr, 0, 0); + if (hash_handle) BCryptDestroyHash(hash_handle); + const NTSTATUS error_code = BCryptCreateHash(alg_handle, &hash_handle, nullptr, 0, nullptr, 0, 0); Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to initialize the hasher"); } - static void hash_data(BCryptHashHandle& hash_handle, const unsigned char* buffer, const size_t& data_size) + virtual std::string get_hash() noexcept override { - const NTSTATUS error_code = BCryptHashData( - hash_handle.handle, const_cast(buffer), static_cast(data_size), 0); - Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to hash data"); + const auto hash_size = get_hash_buffer_size(); + const auto buffer = std::make_unique(hash_size); + const auto hash = buffer.get(); + + const NTSTATUS error_code = BCryptFinishHash(hash_handle, hash, hash_size, 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to finalize the hash"); + return to_hex(hash, hash + hash_size); } - static std::string finalize_hash_handle(const BCryptHashHandle& hash_handle, const ULONG length_in_bytes) + ~BCryptHasher() { BCryptDestroyHash(hash_handle); } + + private: + unsigned long get_hash_buffer_size() const { - std::unique_ptr hash_buffer = std::make_unique(length_in_bytes); - const NTSTATUS error_code = BCryptFinishHash(hash_handle.handle, hash_buffer.get(), length_in_bytes, 0); - Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to finalize the hash"); - return to_hex(hash_buffer.get(), length_in_bytes); - } - - public: - explicit BCryptHasher(std::string hash_type) - { - NTSTATUS error_code = BCryptOpenAlgorithmProvider( - &this->algorithm_handle.handle, - Strings::to_utf16(Strings::ascii_to_uppercase(std::move(hash_type))).c_str(), - nullptr, - 0); - Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to open the algorithm provider"); - - DWORD hash_buffer_bytes; - DWORD cb_data; - error_code = BCryptGetProperty(this->algorithm_handle.handle, - BCRYPT_HASH_LENGTH, - reinterpret_cast(&hash_buffer_bytes), - sizeof(DWORD), - &cb_data, - 0); + unsigned long hash_buffer_bytes; + unsigned long cb_data; + const NTSTATUS error_code = BCryptGetProperty(alg_handle, + BCRYPT_HASH_LENGTH, + reinterpret_cast(&hash_buffer_bytes), + sizeof(hash_buffer_bytes), + &cb_data, + 0); Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to get hash length"); - this->length_in_bytes = hash_buffer_bytes; + + return hash_buffer_bytes; } - std::string hash_file(const fs::path& path) const - { - BCryptHashHandle hash_handle; - initialize_hash_handle(hash_handle, this->algorithm_handle); + BCRYPT_HASH_HANDLE hash_handle = nullptr; + BCRYPT_ALG_HANDLE alg_handle = nullptr; + }; + + const BCRYPT_ALG_HANDLE BCryptHasher::sha1_alg_handle = get_alg_handle(BCRYPT_SHA1_ALGORITHM); + const BCRYPT_ALG_HANDLE BCryptHasher::sha256_alg_handle = get_alg_handle(BCRYPT_SHA256_ALGORITHM); + const BCRYPT_ALG_HANDLE BCryptHasher::sha512_alg_handle = get_alg_handle(BCRYPT_SHA512_ALGORITHM); +#else + + template + static WordTy shl(WordTy value, int by) noexcept + { + return value << by; + } + + static std::uint32_t shr32(std::uint32_t value, int by) noexcept { return value >> by; } + static std::uint32_t rol32(std::uint32_t value, int by) noexcept + { + return (value << by) | (value >> (32 - by)); + } + static std::uint32_t ror32(std::uint32_t value, int by) noexcept + { + return (value >> by) | (value << (32 - by)); + } + + static std::uint64_t shr64(std::uint64_t value, int by) noexcept { return value >> by; } + static std::uint64_t ror64(std::uint64_t value, int by) noexcept + { + return (value >> by) | (value << (64 - by)); + } + + template + struct ShaHasher final : Hasher + { + ShaHasher() = default; - FILE* file = nullptr; - const auto ec = _wfopen_s(&file, path.c_str(), L"rb"); - Checks::check_exit(VCPKG_LINE_INFO, ec == 0, "Failed to open file: %s", path.u8string()); - if (file != nullptr) + virtual void add_bytes(const void* start, const void* end) noexcept override + { + for (;;) { - unsigned char buffer[4096]; - while (const auto actual_size = fread(buffer, 1, sizeof(buffer), file)) + start = add_to_unprocessed(start, end); + if (!start) { - hash_data(hash_handle, buffer, actual_size); + break; // done } - fclose(file); + + m_impl.process_full_chunk(m_chunk); + m_current_chunk_size = 0; } + } + + virtual void clear() noexcept override + { + m_impl.clear(); - return finalize_hash_handle(hash_handle, length_in_bytes); + // m_chunk is theoretically uninitialized, so no need to reset it + m_current_chunk_size = 0; + m_message_length = 0; } - std::string hash_string(const std::string& s) const + virtual std::string get_hash() noexcept override { - BCryptHashHandle hash_handle; - initialize_hash_handle(hash_handle, this->algorithm_handle); - hash_data(hash_handle, reinterpret_cast(s.c_str()), s.size()); - return finalize_hash_handle(hash_handle, length_in_bytes); + process_last_chunk(); + return to_hex(m_impl.begin(), m_impl.end()); } private: - BCryptAlgorithmHandle algorithm_handle; - ULONG length_in_bytes; - }; - } + // if unprocessed gets filled, + // returns a pointer to the remainder of the block (which might be end) + // else, returns nullptr + const void* add_to_unprocessed(const void* start_, const void* end_) noexcept + { + const uchar* start = static_cast(start_); + const uchar* end = static_cast(end_); - std::string get_file_hash(const Files::Filesystem& fs, const fs::path& path, const std::string& hash_type) - { - Checks::check_exit(VCPKG_LINE_INFO, fs.exists(path), "File %s does not exist", path.u8string()); - return BCryptHasher{hash_type}.hash_file(path); - } + const auto remaining = chunk_size - m_current_chunk_size; - std::string get_string_hash(const std::string& s, const std::string& hash_type) - { - verify_has_only_allowed_chars(s); - return BCryptHasher{hash_type}.hash_string(s); - } + const std::size_t message_length = end - start; + if (message_length >= remaining) + { + std::copy(start, start + remaining, chunk_begin()); + m_current_chunk_size += remaining; + m_message_length += remaining * 8; + return start + remaining; + } + else + { + std::copy(start, end, chunk_begin()); + m_current_chunk_size += message_length; + m_message_length += message_length * 8; + return nullptr; + } + } -#else - static std::string get_digest_size(const std::string& hash_type) - { - if (!Strings::case_insensitive_ascii_starts_with(hash_type, "SHA")) + // called before `get_hash` + void process_last_chunk() noexcept + { + const auto message_length = m_message_length; + + // append the bit '1' to the message + { + const uchar temp = 0x80; + add_to_unprocessed(&temp, &temp + 1); + } + + // append 0 to the message so that the resulting length is just enough + // to add the message length + if (chunk_size - m_current_chunk_size < sizeof(m_message_length)) + { + // not enough space to add the message length + // just resize and process full chunk + std::fill(chunk_begin(), m_chunk.end(), static_cast(0)); + m_impl.process_full_chunk(m_chunk); + m_current_chunk_size = 0; + } + + const auto before_length = m_chunk.end() - sizeof(m_message_length); + std::fill(chunk_begin(), before_length, static_cast(0)); + std::generate(before_length, m_chunk.end(), [length = message_length]() mutable { + const auto result = top_bits(length); + length <<= 8; + return result; + }); + + m_impl.process_full_chunk(m_chunk); + } + + auto chunk_begin() { return m_chunk.begin() + m_current_chunk_size; } + + using underlying_type = typename ShaAlgorithm::underlying_type; + using message_length_type = typename ShaAlgorithm::message_length_type; + constexpr static std::size_t chunk_size = ShaAlgorithm::chunk_size; + + ShaAlgorithm m_impl{}; + + std::array m_chunk{}; + std::size_t m_current_chunk_size = 0; + message_length_type m_message_length = 0; + }; + template + inline void sha_fill_initial_words(const uchar* chunk, WordTy* words) { - Checks::exit_with_message( - VCPKG_LINE_INFO, "shasum only supports SHA hashes, but %s was provided", hash_type); + // break chunk into 16 N-bit words + for (std::size_t word = 0; word < 16; ++word) + { + words[word] = 0; + // big-endian -- so the earliest i becomes the most significant + for (std::size_t byte = 0; byte < sizeof(WordTy); ++byte) + { + const auto bits_to_shift = static_cast(8 * (sizeof(WordTy) - 1 - byte)); + words[word] |= shl(chunk[word * sizeof(WordTy) + byte], bits_to_shift); + } + } } - return hash_type.substr(3, hash_type.length() - 3); - } + struct Sha1Algorithm + { + using underlying_type = std::uint32_t; + using message_length_type = std::uint64_t; + constexpr static std::size_t chunk_size = 64; // = 512 / 8 + constexpr static std::size_t number_of_rounds = 80; - static std::string parse_shasum_output(const std::string& shasum_output) - { - std::vector split = Strings::split(shasum_output, " "); - // Checking if >= 3 because filenames with spaces will show up as multiple tokens. - // The hash is the first token so we don't need to parse the filename anyway. - Checks::check_exit(VCPKG_LINE_INFO, - split.size() >= 3, - "Expected output of the form [hash filename\n] (3+ tokens), but got\n" - "[%s] (%s tokens)", - shasum_output, - std::to_string(split.size())); - - return split[0]; - } + Sha1Algorithm() noexcept { clear(); } - std::string get_file_hash(const Files::Filesystem& fs, const fs::path& path, const std::string& hash_type) - { - const std::string digest_size = get_digest_size(hash_type); - Checks::check_exit(VCPKG_LINE_INFO, fs.exists(path), "File %s does not exist", path.u8string()); + void process_full_chunk(const std::array& chunk) noexcept + { + std::uint32_t words[80]; + + sha_fill_initial_words(&chunk[0], words); + for (std::size_t i = 16; i < number_of_rounds; ++i) + { + const auto sum = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16]; + words[i] = rol32(sum, 1); + } + + std::uint32_t a = m_digest[0]; + std::uint32_t b = m_digest[1]; + std::uint32_t c = m_digest[2]; + std::uint32_t d = m_digest[3]; + std::uint32_t e = m_digest[4]; + + for (std::size_t i = 0; i < number_of_rounds; ++i) + { + std::uint32_t f; + std::uint32_t k; + + if (i < 20) + { + f = (b & c) | (~b & d); + k = 0x5A827999; + } + else if (i < 40) + { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } + else if (i < 60) + { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } + else + { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + + auto tmp = rol32(a, 5) + f + e + k + words[i]; + e = d; + d = c; + c = rol32(b, 30); + b = a; + a = tmp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } - // Try hash-specific tools, like sha512sum + void clear() noexcept + { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + } + + const std::uint32_t* begin() const noexcept { return &m_digest[0]; } + const std::uint32_t* end() const noexcept { return &m_digest[5]; } + + std::uint32_t m_digest[5]; + }; + + struct Sha256Algorithm { - const auto ec_data = System::cmd_execute_and_capture_output( - Strings::format(R"(sha%ssum "%s")", digest_size, path.u8string())); - if (ec_data.exit_code == 0) + using underlying_type = std::uint32_t; + using message_length_type = std::uint64_t; + constexpr static std::size_t chunk_size = 64; + + constexpr static std::size_t number_of_rounds = 64; + + Sha256Algorithm() noexcept { clear(); } + + void process_full_chunk(const std::array& chunk) noexcept { - return parse_shasum_output(ec_data.output); + std::uint32_t words[64]; + + sha_fill_initial_words(&chunk[0], words); + + for (std::size_t i = 16; i < number_of_rounds; ++i) + { + const auto w0 = words[i - 15]; + const auto s0 = ror32(w0, 7) ^ ror32(w0, 18) ^ shr32(w0, 3); + const auto w1 = words[i - 2]; + const auto s1 = ror32(w1, 17) ^ ror32(w1, 19) ^ shr32(w1, 10); + words[i] = words[i - 16] + s0 + words[i - 7] + s1; + } + + std::uint32_t local[8]; + std::copy(begin(), end(), std::begin(local)); + + for (std::size_t i = 0; i < number_of_rounds; ++i) + { + const auto a = local[0]; + const auto b = local[1]; + const auto c = local[2]; + + const auto s0 = ror32(a, 2) ^ ror32(a, 13) ^ ror32(a, 22); + const auto maj = (a & b) ^ (a & c) ^ (b & c); + const auto tmp1 = s0 + maj; + + const auto e = local[4]; + + const auto s1 = ror32(e, 6) ^ ror32(e, 11) ^ ror32(e, 25); + const auto ch = (e & local[5]) ^ (~e & local[6]); + const auto tmp2 = local[7] + s1 + ch + round_constants[i] + words[i]; + + for (std::size_t j = 7; j > 0; --j) + { + local[j] = local[j - 1]; + } + local[4] += tmp2; + local[0] = tmp1 + tmp2; + } + + for (std::size_t i = 0; i < 8; ++i) + { + m_digest[i] += local[i]; + } } - } - // Try shasum + void clear() noexcept + { + m_digest[0] = 0x6a09e667; + m_digest[1] = 0xbb67ae85; + m_digest[2] = 0x3c6ef372; + m_digest[3] = 0xa54ff53a; + m_digest[4] = 0x510e527f; + m_digest[5] = 0x9b05688c; + m_digest[6] = 0x1f83d9ab; + m_digest[7] = 0x5be0cd19; + } + + constexpr static std::array round_constants = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + + std::uint32_t* begin() noexcept { return &m_digest[0]; } + std::uint32_t* end() noexcept { return &m_digest[8]; } + + std::uint32_t m_digest[8]; + }; + + struct Sha512Algorithm { - const auto ec_data = System::cmd_execute_and_capture_output( - Strings::format(R"(shasum -a %s "%s")", digest_size, path.u8string())); - if (ec_data.exit_code == 0) + using underlying_type = std::uint64_t; + using message_length_type = UInt128; + constexpr static std::size_t chunk_size = 128; // = 1024 / 8 + + constexpr static std::size_t number_of_rounds = 80; + + Sha512Algorithm() noexcept { clear(); } + + void process_full_chunk(const std::array& chunk) noexcept + { + std::uint64_t words[80]; + + sha_fill_initial_words(&chunk[0], words); + + for (std::size_t i = 16; i < number_of_rounds; ++i) + { + const auto w0 = words[i - 15]; + const auto s0 = ror64(w0, 1) ^ ror64(w0, 8) ^ shr64(w0, 7); + const auto w1 = words[i - 2]; + const auto s1 = ror64(w1, 19) ^ ror64(w1, 61) ^ shr64(w1, 6); + words[i] = words[i - 16] + s0 + words[i - 7] + s1; + } + + std::uint64_t local[8]; + std::copy(begin(), end(), std::begin(local)); + + for (std::size_t i = 0; i < number_of_rounds; ++i) + { + const auto a = local[0]; + const auto b = local[1]; + const auto c = local[2]; + + const auto s0 = ror64(a, 28) ^ ror64(a, 34) ^ ror64(a, 39); + const auto maj = (a & b) ^ (a & c) ^ (b & c); + const auto tmp0 = s0 + maj; + + const auto e = local[4]; + + const auto s1 = ror64(e, 14) ^ ror64(e, 18) ^ ror64(e, 41); + const auto ch = (e & local[5]) ^ (~e & local[6]); + const auto tmp1 = local[7] + s1 + ch + round_constants[i] + words[i]; + + for (std::size_t j = 7; j > 0; --j) + { + local[j] = local[j - 1]; + } + local[4] += tmp1; + local[0] = tmp0 + tmp1; + } + + for (std::size_t i = 0; i < 8; ++i) + { + m_digest[i] += local[i]; + } + } + + void clear() noexcept { - return parse_shasum_output(ec_data.output); + m_digest[0] = 0x6a09e667f3bcc908; + m_digest[1] = 0xbb67ae8584caa73b; + m_digest[2] = 0x3c6ef372fe94f82b; + m_digest[3] = 0xa54ff53a5f1d36f1; + m_digest[4] = 0x510e527fade682d1; + m_digest[5] = 0x9b05688c2b3e6c1f; + m_digest[6] = 0x1f83d9abfb41bd6b; + m_digest[7] = 0x5be0cd19137e2179; } - } - Checks::exit_with_message(VCPKG_LINE_INFO, "Could not hash file %s with %s", path.u8string(), hash_type); + constexpr static std::array round_constants = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, + 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, + 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, + 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, + 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, + 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, + 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, + 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, + 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, + 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, + 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817}; + + std::uint64_t* begin() noexcept { return &m_digest[0]; } + std::uint64_t* end() noexcept { return &m_digest[8]; } + + std::uint64_t m_digest[8]; + }; + + // This is required on older compilers, since it was required in C++14 + constexpr std::array Sha256Algorithm::round_constants; + constexpr std::array Sha512Algorithm::round_constants; +#endif } - std::string get_string_hash(const std::string& s, const std::string& hash_type) + std::unique_ptr get_hasher_for(Algorithm algo) noexcept { - const std::string digest_size = get_digest_size(hash_type); - verify_has_only_allowed_chars(s); +#if defined(_WIN32) + return std::make_unique(algo); +#else + switch (algo) + { + case Algorithm::Sha1: return std::make_unique>(); + case Algorithm::Sha256: return std::make_unique>(); + case Algorithm::Sha512: return std::make_unique>(); + default: vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown hashing algorithm: %s", algo); + } +#endif + } - // Try hash-specific tools, like sha512sum + template + static std::string do_hash(Algorithm algo, const F& f) noexcept + { +#if defined(_WIN32) + auto hasher = BCryptHasher(algo); + return f(hasher); +#else + switch (algo) { - const auto ec_data = - System::cmd_execute_and_capture_output(Strings::format(R"(echo -n "%s" | sha%ssum)", s, digest_size)); - if (ec_data.exit_code == 0) + case Algorithm::Sha1: + { + auto hasher = ShaHasher(); + return f(hasher); + } + case Algorithm::Sha256: + { + auto hasher = ShaHasher(); + return f(hasher); + } + case Algorithm::Sha512: { - return parse_shasum_output(ec_data.output); + auto hasher = ShaHasher(); + return f(hasher); } + default: vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown hashing algorithm: %s", algo); } +#endif + } + + std::string get_bytes_hash(const void* first, const void* last, Algorithm algo) noexcept + { + return do_hash(algo, [first, last](Hasher& hasher) { + hasher.add_bytes(first, last); + return hasher.get_hash(); + }); + } - // Try shasum + std::string get_string_hash(StringView sv, Algorithm algo) noexcept + { + return get_bytes_hash(sv.data(), sv.data() + sv.size(), algo); + } + + // TODO: use Files::Filesystem to open a file + std::string get_file_hash(const Files::Filesystem&, + const fs::path& path, + Algorithm algo, + std::error_code& ec) noexcept + { + auto file = std::fstream(path.c_str(), std::ios_base::in | std::ios_base::binary); + if (!file) { - const auto ec_data = System::cmd_execute_and_capture_output( - Strings::format(R"(echo -n "%s" | shasum -a %s)", s, digest_size)); - if (ec_data.exit_code == 0) - { - return parse_shasum_output(ec_data.output); - } + ec.assign(ENOENT, std::system_category()); + return {}; } - Checks::exit_with_message(VCPKG_LINE_INFO, "Could not hash input string with %s", hash_type); + return do_hash(algo, [&file, &ec](Hasher& hasher) { + constexpr std::size_t buffer_size = 4096; + auto buffer = std::make_unique(buffer_size); + for (;;) + { + file.read(buffer.get(), buffer_size); + if (file.eof()) + { + hasher.add_bytes(buffer.get(), buffer.get() + file.gcount()); + return hasher.get_hash(); + } + else if (file) + { + hasher.add_bytes(buffer.get(), buffer.get() + buffer_size); + } + else + { + ec = std::io_errc::stream; + return std::string(); + } + } + }); } -#endif } diff --git a/toolsrc/src/vcpkg/base/stringview.cpp b/toolsrc/src/vcpkg/base/stringview.cpp index d0b2cd43a..839d72ce8 100644 --- a/toolsrc/src/vcpkg/base/stringview.cpp +++ b/toolsrc/src/vcpkg/base/stringview.cpp @@ -76,8 +76,10 @@ namespace vcpkg std::string StringView::to_string() const { return std::string(m_ptr, m_size); } void StringView::to_string(std::string& s) const { s.append(m_ptr, m_size); } - bool StringView::operator==(StringView other) const + bool operator==(StringView lhs, StringView rhs) noexcept { - return other.size() == size() && memcmp(data(), other.data(), size()) == 0; + return lhs.size() == lhs.size() && memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; } + + bool operator!=(StringView lhs, StringView rhs) noexcept { return !(lhs == rhs); } } diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index a2e90f33b..9245ddfbc 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -486,32 +486,33 @@ namespace vcpkg::Build } else { - hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1"); + const auto algo = Hash::Algorithm::Sha1; + hash = Hash::get_file_hash(VCPKG_LINE_INFO, fs, triplet_file_path, algo); if (auto p = pre_build_info.external_toolchain_file.get()) { hash += "-"; - hash += Hash::get_file_hash(fs, *p, "SHA1"); + hash += Hash::get_file_hash(VCPKG_LINE_INFO, fs, *p, algo); } else if (pre_build_info.cmake_system_name == "Linux") { hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1"); + hash += Hash::get_file_hash(VCPKG_LINE_INFO, fs, paths.scripts / "toolchains" / "linux.cmake", algo); } else if (pre_build_info.cmake_system_name == "Darwin") { hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1"); + hash += Hash::get_file_hash(VCPKG_LINE_INFO, fs, paths.scripts / "toolchains" / "osx.cmake", algo); } else if (pre_build_info.cmake_system_name == "FreeBSD") { hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1"); + hash += Hash::get_file_hash(VCPKG_LINE_INFO, fs, paths.scripts / "toolchains" / "freebsd.cmake", algo); } else if (pre_build_info.cmake_system_name == "Android") { hash += "-"; - hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1"); + hash += Hash::get_file_hash(VCPKG_LINE_INFO, fs, paths.scripts / "toolchains" / "android.cmake", algo); } s_hash_cache.emplace(triplet_file_path, hash); @@ -651,8 +652,9 @@ namespace vcpkg::Build { if (fs::is_regular_file(fs.status(VCPKG_LINE_INFO, port_file))) { - port_files.emplace_back(port_file.path().filename().u8string(), - vcpkg::Hash::get_file_hash(fs, port_file, "SHA1")); + port_files.emplace_back( + port_file.path().filename().u8string(), + vcpkg::Hash::get_file_hash(VCPKG_LINE_INFO, fs, port_file, Hash::Algorithm::Sha1)); if (port_files.size() > max_port_file_count) { @@ -679,7 +681,10 @@ namespace vcpkg::Build abi_tag_entries.emplace_back( "vcpkg_fixup_cmake_targets", - vcpkg::Hash::get_file_hash(fs, paths.scripts / "cmake" / "vcpkg_fixup_cmake_targets.cmake", "SHA1")); + vcpkg::Hash::get_file_hash(VCPKG_LINE_INFO, + fs, + paths.scripts / "cmake" / "vcpkg_fixup_cmake_targets.cmake", + Hash::Algorithm::Sha1)); abi_tag_entries.emplace_back("triplet", pre_build_info.triplet_abi_tag); abi_tag_entries.emplace_back("features", Strings::join(";", config.feature_list)); @@ -688,7 +693,8 @@ namespace vcpkg::Build { abi_tag_entries.emplace_back( "public_abi_override", - Hash::get_string_hash(pre_build_info.public_abi_override.value_or_exit(VCPKG_LINE_INFO), "SHA1")); + Hash::get_string_hash(pre_build_info.public_abi_override.value_or_exit(VCPKG_LINE_INFO), + Hash::Algorithm::Sha1)); } if (config.build_package_options.use_head_version == UseHeadVersion::YES) @@ -717,7 +723,8 @@ namespace vcpkg::Build const auto abi_file_path = paths.buildtrees / name / (triplet.canonical_name() + ".vcpkg_abi_info.txt"); fs.write_contents(abi_file_path, full_abi_info, VCPKG_LINE_INFO); - return AbiTagAndFile{Hash::get_file_hash(fs, abi_file_path, "SHA1"), abi_file_path}; + return AbiTagAndFile{Hash::get_file_hash(VCPKG_LINE_INFO, fs, abi_file_path, Hash::Algorithm::Sha1), + abi_file_path}; } System::print2( diff --git a/toolsrc/src/vcpkg/commands.cpp b/toolsrc/src/vcpkg/commands.cpp index 3ac568979..962dbd48b 100644 --- a/toolsrc/src/vcpkg/commands.cpp +++ b/toolsrc/src/vcpkg/commands.cpp @@ -99,8 +99,15 @@ namespace vcpkg::Commands::Hash Util::unused(args.parse_arguments(COMMAND_STRUCTURE)); const fs::path file_to_hash = args.command_arguments[0]; - const std::string algorithm = args.command_arguments.size() == 2 ? args.command_arguments[1] : "SHA512"; - const std::string hash = vcpkg::Hash::get_file_hash(paths.get_filesystem(), file_to_hash, algorithm); + + auto algorithm = vcpkg::Hash::Algorithm::Sha512; + if (args.command_arguments.size() == 2) + { + algorithm = vcpkg::Hash::algorithm_from_string(args.command_arguments[1]).value_or_exit(VCPKG_LINE_INFO); + } + + const std::string hash = + vcpkg::Hash::get_file_hash(VCPKG_LINE_INFO, paths.get_filesystem(), file_to_hash, algorithm); System::print2(hash, '\n'); Checks::exit_success(VCPKG_LINE_INFO); } diff --git a/toolsrc/src/vcpkg/metrics.cpp b/toolsrc/src/vcpkg/metrics.cpp index 11f613830..b8c55919e 100644 --- a/toolsrc/src/vcpkg/metrics.cpp +++ b/toolsrc/src/vcpkg/metrics.cpp @@ -266,7 +266,7 @@ namespace vcpkg::Metrics const auto match = *next; if (match[0] != "00-00-00-00-00-00") { - return vcpkg::Hash::get_string_hash(match[0], "SHA256"); + return vcpkg::Hash::get_string_hash(match[0].str(), Hash::Algorithm::Sha256); } ++next; } -- cgit v1.2.3 From 6d8e66ff4fe40ef0937e33e809287476e2c04ee5 Mon Sep 17 00:00:00 2001 From: Phil Christensen Date: Mon, 26 Aug 2019 16:21:57 -0700 Subject: Run clang-format and add more error messages --- toolsrc/src/vcpkg/parse.cpp | 154 +++++++++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 72 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/parse.cpp b/toolsrc/src/vcpkg/parse.cpp index 91b2b2786..a3f4186fc 100644 --- a/toolsrc/src/vcpkg/parse.cpp +++ b/toolsrc/src/vcpkg/parse.cpp @@ -2,8 +2,8 @@ #include -#include #include +#include namespace vcpkg::Parse { @@ -45,10 +45,7 @@ namespace vcpkg::Parse return nullptr; } - static bool is_whitespace(char c) - { - return c == ' ' || c == '\t' || c == '\n' || c == '\r'; - } + static bool is_whitespace(char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r'; } std::vector parse_comma_list(const std::string& str) { @@ -59,73 +56,86 @@ namespace vcpkg::Parse std::vector out; - auto iter = str.cbegin(); - - do { - // Trim leading whitespace of each element - while (iter != str.cend() && is_whitespace(*iter)) - { - ++iter; - } - - // Allow commas inside of []. - bool bracket_nesting = false; - - auto element_begin = iter; - auto element_end = iter; - while (iter != str.cend() && (*iter != ',' || bracket_nesting)) - { - char value = *iter; - - // do not support nested [] - if (value == '[') - { - bracket_nesting = true; - } - else if (value == ']') - { - bracket_nesting = false; - } - - ++iter; - - // Trim ending whitespace - if (!is_whitespace(value)) - { - // Update element_end after iter is incremented so it will be one past. - element_end = iter; - } - } - - if (element_begin == element_end) - { - System::print2( System::Color::warning, - "Warning: empty element in list\n" - "> '", str, "'\n" - "> ", std::string(static_cast(element_begin - str.cbegin()), ' '), "^\n" - ); - } - else - { - out.push_back({ element_begin, element_end }); - } - - if (iter != str.cend()) - { - //Not at the end, must be at a comma that needs to be stepped over - ++iter; - - if (iter == str.end()) - { - System::print2(System::Color::warning, - "Warning: empty element in list\n" - "> '", str, "'\n" - "> ", std::string(str.length(), ' '), "^\n" - ); - } - } - - } while (iter != str.cend()); + auto iter = str.cbegin(); + + do + { + // Trim leading whitespace of each element + while (iter != str.cend() && is_whitespace(*iter)) + { + ++iter; + } + + // Allow commas inside of []. + bool bracket_nesting = false; + + auto element_begin = iter; + auto element_end = iter; + while (iter != str.cend() && (*iter != ',' || bracket_nesting)) + { + char value = *iter; + + // do not support nested [] + if (value == '[') + { + Checks::check_exit(VCPKG_LINE_INFO, + !bracket_nesting, + "Lists do not support nested brackets, Did you forget a ']'?\n" + "> '%s'\n" + "> %s^\n", + str, + std::string(static_cast(iter - str.cbegin()), ' ')); + bracket_nesting = true; + } + else if (value == ']') + { + Checks::check_exit(VCPKG_LINE_INFO, + bracket_nesting, + "Found unmatched ']'. Did you forget a '['?\n" + "> '%s'\n" + "> %s^\n", + str, + std::string(static_cast(iter - str.cbegin()), ' ')); + bracket_nesting = false; + } + + ++iter; + + // Trim ending whitespace + if (!is_whitespace(value)) + { + // Update element_end after iter is incremented so it will be one past. + element_end = iter; + } + } + + Checks::check_exit(VCPKG_LINE_INFO, + element_begin != element_end, + "Empty element in list\n" + "> '%s'\n" + "> %s^\n", + str, + std::string(static_cast(element_begin - str.cbegin()), ' ')); + + out.push_back({element_begin, element_end}); + + if (iter != str.cend()) + { + Checks::check_exit(VCPKG_LINE_INFO, *iter == ',', "Internal parsing error - expected comma"); + + // Not at the end, must be at a comma that needs to be stepped over + ++iter; + + Checks::check_exit(VCPKG_LINE_INFO, + iter != str.end(), + "Empty element in list\n" + "> '%s'\n" + "> %s^\n", + str, + std::string(str.length(), ' ')); + } + + } while (iter != str.cend()); return out; } -- cgit v1.2.3 From 8bae937e1725a85cb7829ad3113debbeef43674a Mon Sep 17 00:00:00 2001 From: Phil Christensen Date: Mon, 26 Aug 2019 16:39:38 -0700 Subject: avoid assembling error strings unless there is an error --- toolsrc/src/vcpkg/parse.cpp | 65 +++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 29 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/parse.cpp b/toolsrc/src/vcpkg/parse.cpp index a3f4186fc..6015d9927 100644 --- a/toolsrc/src/vcpkg/parse.cpp +++ b/toolsrc/src/vcpkg/parse.cpp @@ -78,24 +78,28 @@ namespace vcpkg::Parse // do not support nested [] if (value == '[') { - Checks::check_exit(VCPKG_LINE_INFO, - !bracket_nesting, - "Lists do not support nested brackets, Did you forget a ']'?\n" - "> '%s'\n" - "> %s^\n", - str, - std::string(static_cast(iter - str.cbegin()), ' ')); + if (bracket_nesting) + { + Checks::exit_with_message(VCPKG_LINE_INFO, + "Lists do not support nested brackets, Did you forget a ']'?\n" + "> '%s'\n" + "> %s^\n", + str, + std::string(static_cast(iter - str.cbegin()), ' ')); + } bracket_nesting = true; } else if (value == ']') { - Checks::check_exit(VCPKG_LINE_INFO, - bracket_nesting, - "Found unmatched ']'. Did you forget a '['?\n" - "> '%s'\n" - "> %s^\n", - str, - std::string(static_cast(iter - str.cbegin()), ' ')); + if (!bracket_nesting) + { + Checks::exit_with_message(VCPKG_LINE_INFO, + "Found unmatched ']'. Did you forget a '['?\n" + "> '%s'\n" + "> %s^\n", + str, + std::string(static_cast(iter - str.cbegin()), ' ')); + } bracket_nesting = false; } @@ -109,14 +113,15 @@ namespace vcpkg::Parse } } - Checks::check_exit(VCPKG_LINE_INFO, - element_begin != element_end, - "Empty element in list\n" - "> '%s'\n" - "> %s^\n", - str, - std::string(static_cast(element_begin - str.cbegin()), ' ')); - + if (element_begin == element_end) + { + Checks::exit_with_message(VCPKG_LINE_INFO, + "Empty element in list\n" + "> '%s'\n" + "> %s^\n", + str, + std::string(static_cast(element_begin - str.cbegin()), ' ')); + } out.push_back({element_begin, element_end}); if (iter != str.cend()) @@ -126,13 +131,15 @@ namespace vcpkg::Parse // Not at the end, must be at a comma that needs to be stepped over ++iter; - Checks::check_exit(VCPKG_LINE_INFO, - iter != str.end(), - "Empty element in list\n" - "> '%s'\n" - "> %s^\n", - str, - std::string(str.length(), ' ')); + if (iter == str.end()) + { + Checks::exit_with_message(VCPKG_LINE_INFO, + "Empty element in list\n" + "> '%s'\n" + "> %s^\n", + str, + std::string(str.length(), ' ')); + } } } while (iter != str.cend()); -- cgit v1.2.3 From 32a53e1f3755960b09fc228dce23885aa7efcb8f Mon Sep 17 00:00:00 2001 From: nicole mazzuca Date: Tue, 27 Aug 2019 14:03:49 -0700 Subject: =?UTF-8?q?[vcpkg]=20fix=20bug=20in=20StringView::operator=3D=3D?= =?UTF-8?q?=20=F0=9F=98=B1=20(#7930)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this change, `lhs == rhs` missed the check for `lhs.size() == rhs.size()`, and then did a `memcmp` on the buffers up to `lhs.size()`. This means that, if `lhs.size() < rhs.size()`, it would allow two unequal strings to compare equal if, up to `lhs.size()` they are the same; and if `lhs.size() > rhs.size()`, then it would read out of bounds. --- toolsrc/src/vcpkg-test/stringview.cpp | 17 +++++++++++++++++ toolsrc/src/vcpkg/base/stringview.cpp | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 toolsrc/src/vcpkg-test/stringview.cpp (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/stringview.cpp b/toolsrc/src/vcpkg-test/stringview.cpp new file mode 100644 index 000000000..4df8e6be5 --- /dev/null +++ b/toolsrc/src/vcpkg-test/stringview.cpp @@ -0,0 +1,17 @@ +#include + +#include + +template +static vcpkg::StringView sv(const char (&cstr)[N]) { + return cstr; +} + +TEST_CASE("string view operator==", "[stringview]") { + // these are due to a bug in operator== + // see commit 782723959399a1a0725ac49 + REQUIRE(sv("hey") != sv("heys")); + REQUIRE(sv("heys") != sv("hey")); + REQUIRE(sv("hey") == sv("hey")); + REQUIRE(sv("hey") != sv("hex")); +} diff --git a/toolsrc/src/vcpkg/base/stringview.cpp b/toolsrc/src/vcpkg/base/stringview.cpp index 839d72ce8..6b159db48 100644 --- a/toolsrc/src/vcpkg/base/stringview.cpp +++ b/toolsrc/src/vcpkg/base/stringview.cpp @@ -78,7 +78,7 @@ namespace vcpkg bool operator==(StringView lhs, StringView rhs) noexcept { - return lhs.size() == lhs.size() && memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; + return lhs.size() == rhs.size() && memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; } bool operator!=(StringView lhs, StringView rhs) noexcept { return !(lhs == rhs); } -- cgit v1.2.3 From 65d4bc146bf7c1c21989b680497b1f6f9a09c967 Mon Sep 17 00:00:00 2001 From: Victor Romero Date: Wed, 28 Aug 2019 11:47:17 -0700 Subject: [vcpkg install] Enable Download Mode (#7797) * [portfile functions] Override execute_process() to accept ALLOW_IN_DOWNLOAD_MODE option * [vcpkg install] Set VCPKG_DOWNLOAD_MODE when using --only-downloads option * [vcpkg_find_acquire_program] Allow in Download Mode * Don't stop when build fails for a package * Download sources for all packages in dependency graph * Improve output messages * Enable acquiring MSYS packages in download mode * Documentation * Update documentation * execute_process() always fails on Download Mode * Regenerate docs and fix formatting * Run clang-format * Use _execute_process on vcpkg_from_ helpers --- toolsrc/src/vcpkg/build.cpp | 39 +++++++++++++++++++++++++++------- toolsrc/src/vcpkg/commands.ci.cpp | 2 ++ toolsrc/src/vcpkg/commands.upgrade.cpp | 1 + toolsrc/src/vcpkg/export.cpp | 1 + toolsrc/src/vcpkg/install.cpp | 18 +++++++++++++--- 5 files changed, 50 insertions(+), 11 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 9245ddfbc..e5c00b929 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -53,6 +53,7 @@ namespace vcpkg::Build::Command const Build::BuildPackageOptions build_package_options{ Build::UseHeadVersion::NO, Build::AllowDownloads::YES, + Build::OnlyDownloads::NO, Build::CleanBuildtrees::NO, Build::CleanPackages::NO, Build::CleanDownloads::NO, @@ -407,6 +408,11 @@ namespace vcpkg::Build {"VCPKG_CONCURRENCY", std::to_string(get_concurrency())}, }; + if (Util::Enum::to_bool(config.build_package_options.only_downloads)) + { + variables.push_back({"VCPKG_DOWNLOAD_MODE", "true"}); + } + if (!System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value()) { variables.push_back({"GIT", git_exe_path}); @@ -528,6 +534,7 @@ namespace vcpkg::Build const BuildPackageConfig& config) { auto& fs = paths.get_filesystem(); + #if defined(_WIN32) const fs::path& powershell_exe_path = paths.get_tool_exe("powershell-core"); if (!fs.exists(powershell_exe_path.parent_path() / "powershell.exe")) @@ -559,6 +566,14 @@ namespace vcpkg::Build #else const int return_code = System::cmd_execute_clean(command, env); #endif + // With the exception of empty packages, builds in "Download Mode" always result in failure. + if (config.build_package_options.only_downloads == Build::OnlyDownloads::YES) + { + // TODO: Capture executed command output and evaluate whether the failure was intended. + // If an unintended error occurs then return a BuildResult::DOWNLOAD_FAILURE status. + return BuildResult::DOWNLOADED; + } + const auto buildtimeus = timer.microseconds(); const auto spec_string = spec.to_string(); @@ -793,20 +808,23 @@ namespace vcpkg::Build const std::string& name = config.scf.core_paragraph->name; std::vector required_fspecs = compute_required_feature_specs(config, status_db); - std::vector required_fspecs_copy = required_fspecs; // extract out the actual package ids auto dep_pspecs = Util::fmap(required_fspecs, [](FeatureSpec const& fspec) { return fspec.spec(); }); Util::sort_unique_erase(dep_pspecs); // Find all features that aren't installed. This mutates required_fspecs. - Util::erase_remove_if(required_fspecs, [&](FeatureSpec const& fspec) { - return status_db.is_installed(fspec) || fspec.name() == name; - }); - - if (!required_fspecs.empty()) + // Skip this validation when running in Download Mode. + if (config.build_package_options.only_downloads != Build::OnlyDownloads::YES) { - return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)}; + Util::erase_remove_if(required_fspecs, [&](FeatureSpec const& fspec) { + return status_db.is_installed(fspec) || fspec.name() == name; + }); + + if (!required_fspecs.empty()) + { + return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)}; + } } const PackageSpec spec = @@ -817,7 +835,10 @@ namespace vcpkg::Build // dep_pspecs was not destroyed for (auto&& pspec : dep_pspecs) { - if (pspec == spec) continue; + if (pspec == spec || Util::Enum::to_bool(config.build_package_options.only_downloads)) + { + continue; + } const auto status_it = status_db.find_installed(pspec); Checks::check_exit(VCPKG_LINE_INFO, status_it != status_db.end()); dependency_abis.emplace_back( @@ -949,6 +970,7 @@ namespace vcpkg::Build static const std::string POST_BUILD_CHECKS_FAILED_STRING = "POST_BUILD_CHECKS_FAILED"; static const std::string CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING = "CASCADED_DUE_TO_MISSING_DEPENDENCIES"; static const std::string EXCLUDED_STRING = "EXCLUDED"; + static const std::string DOWNLOADED_STRING = "DOWNLOADED"; switch (build_result) { @@ -959,6 +981,7 @@ namespace vcpkg::Build case BuildResult::FILE_CONFLICTS: return FILE_CONFLICTS_STRING; case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: return CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING; case BuildResult::EXCLUDED: return EXCLUDED_STRING; + case BuildResult::DOWNLOADED: return DOWNLOADED_STRING; default: Checks::unreachable(VCPKG_LINE_INFO); } } diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index f0f162f5c..6e0a71adf 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -212,6 +212,7 @@ namespace vcpkg::Commands::CI const Build::BuildPackageOptions build_options = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, + Build::OnlyDownloads::NO, Build::CleanBuildtrees::YES, Build::CleanPackages::YES, Build::CleanDownloads::NO, @@ -356,6 +357,7 @@ namespace vcpkg::Commands::CI const Build::BuildPackageOptions install_plan_options = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, + Build::OnlyDownloads::NO, Build::CleanBuildtrees::YES, Build::CleanPackages::YES, Build::CleanDownloads::NO, diff --git a/toolsrc/src/vcpkg/commands.upgrade.cpp b/toolsrc/src/vcpkg/commands.upgrade.cpp index 1e64b2eb6..b1dbf6194 100644 --- a/toolsrc/src/vcpkg/commands.upgrade.cpp +++ b/toolsrc/src/vcpkg/commands.upgrade.cpp @@ -154,6 +154,7 @@ namespace vcpkg::Commands::Upgrade const Build::BuildPackageOptions install_plan_options = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, + Build::OnlyDownloads::NO, Build::CleanBuildtrees::NO, Build::CleanPackages::NO, Build::CleanDownloads::NO, diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp index 5ceb47adf..349d9aefd 100644 --- a/toolsrc/src/vcpkg/export.cpp +++ b/toolsrc/src/vcpkg/export.cpp @@ -73,6 +73,7 @@ namespace vcpkg::Export static constexpr Build::BuildPackageOptions BUILD_OPTIONS = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, + Build::OnlyDownloads::NO, Build::CleanBuildtrees::NO, Build::CleanPackages::NO, Build::CleanDownloads::NO, diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 1812f1624..009965887 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -342,6 +342,13 @@ namespace vcpkg::Install return Build::build_package(paths, build_config, status_db); }(); + if (BuildResult::DOWNLOADED == result.code) + { + System::print2( + System::Color::success, "Downloaded sources for package ", display_name_with_features, "\n"); + return result; + } + if (result.code != Build::BuildResult::SUCCEEDED) { System::print2(System::Color::error, Build::create_error_message(result.code, action.spec), "\n"); @@ -467,16 +474,18 @@ namespace vcpkg::Install static constexpr StringLiteral OPTION_DRY_RUN = "--dry-run"; static constexpr StringLiteral OPTION_USE_HEAD_VERSION = "--head"; static constexpr StringLiteral OPTION_NO_DOWNLOADS = "--no-downloads"; + static constexpr StringLiteral OPTION_ONLY_DOWNLOADS = "--only-downloads"; static constexpr StringLiteral OPTION_RECURSE = "--recurse"; static constexpr StringLiteral OPTION_KEEP_GOING = "--keep-going"; 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 std::array INSTALL_SWITCHES = {{ + static constexpr std::array INSTALL_SWITCHES = {{ {OPTION_DRY_RUN, "Do not actually build or install"}, {OPTION_USE_HEAD_VERSION, "Install the libraries on the command line using the latest upstream sources"}, {OPTION_NO_DOWNLOADS, "Do not download new sources"}, + {OPTION_ONLY_DOWNLOADS, "Download sources but don't build packages"}, {OPTION_RECURSE, "Allow removal of packages as part of installation"}, {OPTION_KEEP_GOING, "Continue installing packages on failure"}, {OPTION_USE_ARIA2, "Use aria2 to perform download tasks"}, @@ -631,10 +640,12 @@ namespace vcpkg::Install const bool dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN); const bool use_head_version = Util::Sets::contains(options.switches, (OPTION_USE_HEAD_VERSION)); const bool no_downloads = Util::Sets::contains(options.switches, (OPTION_NO_DOWNLOADS)); + const bool only_downloads = Util::Sets::contains(options.switches, (OPTION_ONLY_DOWNLOADS)); const bool is_recursive = Util::Sets::contains(options.switches, (OPTION_RECURSE)); const bool use_aria2 = Util::Sets::contains(options.switches, (OPTION_USE_ARIA2)); const bool clean_after_build = Util::Sets::contains(options.switches, (OPTION_CLEAN_AFTER_BUILD)); - const KeepGoing keep_going = to_keep_going(Util::Sets::contains(options.switches, OPTION_KEEP_GOING)); + const KeepGoing keep_going = + to_keep_going(Util::Sets::contains(options.switches, OPTION_KEEP_GOING) || only_downloads); auto& fs = paths.get_filesystem(); @@ -647,11 +658,12 @@ namespace vcpkg::Install const Build::BuildPackageOptions install_plan_options = { Util::Enum::to_enum(use_head_version), Util::Enum::to_enum(!no_downloads), + Util::Enum::to_enum(only_downloads), clean_after_build ? Build::CleanBuildtrees::YES : Build::CleanBuildtrees::NO, clean_after_build ? Build::CleanPackages::YES : Build::CleanPackages::NO, clean_after_build ? Build::CleanDownloads::YES : Build::CleanDownloads::NO, download_tool, - GlobalState::g_binary_caching ? Build::BinaryCaching::YES : Build::BinaryCaching::NO, + (GlobalState::g_binary_caching && !only_downloads) ? Build::BinaryCaching::YES : Build::BinaryCaching::NO, Build::FailOnTombstone::NO, }; -- cgit v1.2.3 From 4b404e8cfbdde4277733adaacc399fa4e1b57320 Mon Sep 17 00:00:00 2001 From: Victor Romero Date: Wed, 28 Aug 2019 11:59:30 -0700 Subject: Revert "[vcpkg install] Enable Download Mode (#7797)" (#7949) This reverts commit 65d4bc146bf7c1c21989b680497b1f6f9a09c967. --- toolsrc/src/vcpkg/build.cpp | 39 +++++++--------------------------- toolsrc/src/vcpkg/commands.ci.cpp | 2 -- toolsrc/src/vcpkg/commands.upgrade.cpp | 1 - toolsrc/src/vcpkg/export.cpp | 1 - toolsrc/src/vcpkg/install.cpp | 18 +++------------- 5 files changed, 11 insertions(+), 50 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index e5c00b929..9245ddfbc 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -53,7 +53,6 @@ namespace vcpkg::Build::Command const Build::BuildPackageOptions build_package_options{ Build::UseHeadVersion::NO, Build::AllowDownloads::YES, - Build::OnlyDownloads::NO, Build::CleanBuildtrees::NO, Build::CleanPackages::NO, Build::CleanDownloads::NO, @@ -408,11 +407,6 @@ namespace vcpkg::Build {"VCPKG_CONCURRENCY", std::to_string(get_concurrency())}, }; - if (Util::Enum::to_bool(config.build_package_options.only_downloads)) - { - variables.push_back({"VCPKG_DOWNLOAD_MODE", "true"}); - } - if (!System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value()) { variables.push_back({"GIT", git_exe_path}); @@ -534,7 +528,6 @@ namespace vcpkg::Build const BuildPackageConfig& config) { auto& fs = paths.get_filesystem(); - #if defined(_WIN32) const fs::path& powershell_exe_path = paths.get_tool_exe("powershell-core"); if (!fs.exists(powershell_exe_path.parent_path() / "powershell.exe")) @@ -566,14 +559,6 @@ namespace vcpkg::Build #else const int return_code = System::cmd_execute_clean(command, env); #endif - // With the exception of empty packages, builds in "Download Mode" always result in failure. - if (config.build_package_options.only_downloads == Build::OnlyDownloads::YES) - { - // TODO: Capture executed command output and evaluate whether the failure was intended. - // If an unintended error occurs then return a BuildResult::DOWNLOAD_FAILURE status. - return BuildResult::DOWNLOADED; - } - const auto buildtimeus = timer.microseconds(); const auto spec_string = spec.to_string(); @@ -808,23 +793,20 @@ namespace vcpkg::Build const std::string& name = config.scf.core_paragraph->name; std::vector required_fspecs = compute_required_feature_specs(config, status_db); + std::vector required_fspecs_copy = required_fspecs; // extract out the actual package ids auto dep_pspecs = Util::fmap(required_fspecs, [](FeatureSpec const& fspec) { return fspec.spec(); }); Util::sort_unique_erase(dep_pspecs); // Find all features that aren't installed. This mutates required_fspecs. - // Skip this validation when running in Download Mode. - if (config.build_package_options.only_downloads != Build::OnlyDownloads::YES) - { - Util::erase_remove_if(required_fspecs, [&](FeatureSpec const& fspec) { - return status_db.is_installed(fspec) || fspec.name() == name; - }); + Util::erase_remove_if(required_fspecs, [&](FeatureSpec const& fspec) { + return status_db.is_installed(fspec) || fspec.name() == name; + }); - if (!required_fspecs.empty()) - { - return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)}; - } + if (!required_fspecs.empty()) + { + return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)}; } const PackageSpec spec = @@ -835,10 +817,7 @@ namespace vcpkg::Build // dep_pspecs was not destroyed for (auto&& pspec : dep_pspecs) { - if (pspec == spec || Util::Enum::to_bool(config.build_package_options.only_downloads)) - { - continue; - } + if (pspec == spec) continue; const auto status_it = status_db.find_installed(pspec); Checks::check_exit(VCPKG_LINE_INFO, status_it != status_db.end()); dependency_abis.emplace_back( @@ -970,7 +949,6 @@ namespace vcpkg::Build static const std::string POST_BUILD_CHECKS_FAILED_STRING = "POST_BUILD_CHECKS_FAILED"; static const std::string CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING = "CASCADED_DUE_TO_MISSING_DEPENDENCIES"; static const std::string EXCLUDED_STRING = "EXCLUDED"; - static const std::string DOWNLOADED_STRING = "DOWNLOADED"; switch (build_result) { @@ -981,7 +959,6 @@ namespace vcpkg::Build case BuildResult::FILE_CONFLICTS: return FILE_CONFLICTS_STRING; case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: return CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING; case BuildResult::EXCLUDED: return EXCLUDED_STRING; - case BuildResult::DOWNLOADED: return DOWNLOADED_STRING; default: Checks::unreachable(VCPKG_LINE_INFO); } } diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index 6e0a71adf..f0f162f5c 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -212,7 +212,6 @@ namespace vcpkg::Commands::CI const Build::BuildPackageOptions build_options = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, - Build::OnlyDownloads::NO, Build::CleanBuildtrees::YES, Build::CleanPackages::YES, Build::CleanDownloads::NO, @@ -357,7 +356,6 @@ namespace vcpkg::Commands::CI const Build::BuildPackageOptions install_plan_options = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, - Build::OnlyDownloads::NO, Build::CleanBuildtrees::YES, Build::CleanPackages::YES, Build::CleanDownloads::NO, diff --git a/toolsrc/src/vcpkg/commands.upgrade.cpp b/toolsrc/src/vcpkg/commands.upgrade.cpp index b1dbf6194..1e64b2eb6 100644 --- a/toolsrc/src/vcpkg/commands.upgrade.cpp +++ b/toolsrc/src/vcpkg/commands.upgrade.cpp @@ -154,7 +154,6 @@ namespace vcpkg::Commands::Upgrade const Build::BuildPackageOptions install_plan_options = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, - Build::OnlyDownloads::NO, Build::CleanBuildtrees::NO, Build::CleanPackages::NO, Build::CleanDownloads::NO, diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp index 349d9aefd..5ceb47adf 100644 --- a/toolsrc/src/vcpkg/export.cpp +++ b/toolsrc/src/vcpkg/export.cpp @@ -73,7 +73,6 @@ namespace vcpkg::Export static constexpr Build::BuildPackageOptions BUILD_OPTIONS = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, - Build::OnlyDownloads::NO, Build::CleanBuildtrees::NO, Build::CleanPackages::NO, Build::CleanDownloads::NO, diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 009965887..1812f1624 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -342,13 +342,6 @@ namespace vcpkg::Install return Build::build_package(paths, build_config, status_db); }(); - if (BuildResult::DOWNLOADED == result.code) - { - System::print2( - System::Color::success, "Downloaded sources for package ", display_name_with_features, "\n"); - return result; - } - if (result.code != Build::BuildResult::SUCCEEDED) { System::print2(System::Color::error, Build::create_error_message(result.code, action.spec), "\n"); @@ -474,18 +467,16 @@ namespace vcpkg::Install static constexpr StringLiteral OPTION_DRY_RUN = "--dry-run"; static constexpr StringLiteral OPTION_USE_HEAD_VERSION = "--head"; static constexpr StringLiteral OPTION_NO_DOWNLOADS = "--no-downloads"; - static constexpr StringLiteral OPTION_ONLY_DOWNLOADS = "--only-downloads"; static constexpr StringLiteral OPTION_RECURSE = "--recurse"; static constexpr StringLiteral OPTION_KEEP_GOING = "--keep-going"; 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 std::array INSTALL_SWITCHES = {{ + static constexpr std::array INSTALL_SWITCHES = {{ {OPTION_DRY_RUN, "Do not actually build or install"}, {OPTION_USE_HEAD_VERSION, "Install the libraries on the command line using the latest upstream sources"}, {OPTION_NO_DOWNLOADS, "Do not download new sources"}, - {OPTION_ONLY_DOWNLOADS, "Download sources but don't build packages"}, {OPTION_RECURSE, "Allow removal of packages as part of installation"}, {OPTION_KEEP_GOING, "Continue installing packages on failure"}, {OPTION_USE_ARIA2, "Use aria2 to perform download tasks"}, @@ -640,12 +631,10 @@ namespace vcpkg::Install const bool dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN); const bool use_head_version = Util::Sets::contains(options.switches, (OPTION_USE_HEAD_VERSION)); const bool no_downloads = Util::Sets::contains(options.switches, (OPTION_NO_DOWNLOADS)); - const bool only_downloads = Util::Sets::contains(options.switches, (OPTION_ONLY_DOWNLOADS)); const bool is_recursive = Util::Sets::contains(options.switches, (OPTION_RECURSE)); const bool use_aria2 = Util::Sets::contains(options.switches, (OPTION_USE_ARIA2)); const bool clean_after_build = Util::Sets::contains(options.switches, (OPTION_CLEAN_AFTER_BUILD)); - const KeepGoing keep_going = - to_keep_going(Util::Sets::contains(options.switches, OPTION_KEEP_GOING) || only_downloads); + const KeepGoing keep_going = to_keep_going(Util::Sets::contains(options.switches, OPTION_KEEP_GOING)); auto& fs = paths.get_filesystem(); @@ -658,12 +647,11 @@ namespace vcpkg::Install const Build::BuildPackageOptions install_plan_options = { Util::Enum::to_enum(use_head_version), Util::Enum::to_enum(!no_downloads), - Util::Enum::to_enum(only_downloads), clean_after_build ? Build::CleanBuildtrees::YES : Build::CleanBuildtrees::NO, clean_after_build ? Build::CleanPackages::YES : Build::CleanPackages::NO, clean_after_build ? Build::CleanDownloads::YES : Build::CleanDownloads::NO, download_tool, - (GlobalState::g_binary_caching && !only_downloads) ? Build::BinaryCaching::YES : Build::BinaryCaching::NO, + GlobalState::g_binary_caching ? Build::BinaryCaching::YES : Build::BinaryCaching::NO, Build::FailOnTombstone::NO, }; -- cgit v1.2.3 From f5c732b40d43f062278f247036b773477823813b Mon Sep 17 00:00:00 2001 From: Victor Romero Date: Wed, 28 Aug 2019 13:49:29 -0700 Subject: Download Mode (#7950) * [portfile functions] Override execute_process() to accept ALLOW_IN_DOWNLOAD_MODE option * [vcpkg install] Set VCPKG_DOWNLOAD_MODE when using --only-downloads option * [vcpkg_find_acquire_program] Allow in Download Mode * Don't stop when build fails for a package * Download sources for all packages in dependency graph * Improve output messages * Enable acquiring MSYS packages in download mode * Documentation * Update documentation * execute_process() always fails on Download Mode * Regenerate docs and fix formatting * Run clang-format * Use _execute_process on vcpkg_from_ helpers * Fix calls to _execute_process() when not in Download Mode --- toolsrc/src/vcpkg/build.cpp | 39 +++++++++++++++++++++++++++------- toolsrc/src/vcpkg/commands.ci.cpp | 2 ++ toolsrc/src/vcpkg/commands.upgrade.cpp | 1 + toolsrc/src/vcpkg/export.cpp | 1 + toolsrc/src/vcpkg/install.cpp | 18 +++++++++++++--- 5 files changed, 50 insertions(+), 11 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 9245ddfbc..e5c00b929 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -53,6 +53,7 @@ namespace vcpkg::Build::Command const Build::BuildPackageOptions build_package_options{ Build::UseHeadVersion::NO, Build::AllowDownloads::YES, + Build::OnlyDownloads::NO, Build::CleanBuildtrees::NO, Build::CleanPackages::NO, Build::CleanDownloads::NO, @@ -407,6 +408,11 @@ namespace vcpkg::Build {"VCPKG_CONCURRENCY", std::to_string(get_concurrency())}, }; + if (Util::Enum::to_bool(config.build_package_options.only_downloads)) + { + variables.push_back({"VCPKG_DOWNLOAD_MODE", "true"}); + } + if (!System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value()) { variables.push_back({"GIT", git_exe_path}); @@ -528,6 +534,7 @@ namespace vcpkg::Build const BuildPackageConfig& config) { auto& fs = paths.get_filesystem(); + #if defined(_WIN32) const fs::path& powershell_exe_path = paths.get_tool_exe("powershell-core"); if (!fs.exists(powershell_exe_path.parent_path() / "powershell.exe")) @@ -559,6 +566,14 @@ namespace vcpkg::Build #else const int return_code = System::cmd_execute_clean(command, env); #endif + // With the exception of empty packages, builds in "Download Mode" always result in failure. + if (config.build_package_options.only_downloads == Build::OnlyDownloads::YES) + { + // TODO: Capture executed command output and evaluate whether the failure was intended. + // If an unintended error occurs then return a BuildResult::DOWNLOAD_FAILURE status. + return BuildResult::DOWNLOADED; + } + const auto buildtimeus = timer.microseconds(); const auto spec_string = spec.to_string(); @@ -793,20 +808,23 @@ namespace vcpkg::Build const std::string& name = config.scf.core_paragraph->name; std::vector required_fspecs = compute_required_feature_specs(config, status_db); - std::vector required_fspecs_copy = required_fspecs; // extract out the actual package ids auto dep_pspecs = Util::fmap(required_fspecs, [](FeatureSpec const& fspec) { return fspec.spec(); }); Util::sort_unique_erase(dep_pspecs); // Find all features that aren't installed. This mutates required_fspecs. - Util::erase_remove_if(required_fspecs, [&](FeatureSpec const& fspec) { - return status_db.is_installed(fspec) || fspec.name() == name; - }); - - if (!required_fspecs.empty()) + // Skip this validation when running in Download Mode. + if (config.build_package_options.only_downloads != Build::OnlyDownloads::YES) { - return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)}; + Util::erase_remove_if(required_fspecs, [&](FeatureSpec const& fspec) { + return status_db.is_installed(fspec) || fspec.name() == name; + }); + + if (!required_fspecs.empty()) + { + return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)}; + } } const PackageSpec spec = @@ -817,7 +835,10 @@ namespace vcpkg::Build // dep_pspecs was not destroyed for (auto&& pspec : dep_pspecs) { - if (pspec == spec) continue; + if (pspec == spec || Util::Enum::to_bool(config.build_package_options.only_downloads)) + { + continue; + } const auto status_it = status_db.find_installed(pspec); Checks::check_exit(VCPKG_LINE_INFO, status_it != status_db.end()); dependency_abis.emplace_back( @@ -949,6 +970,7 @@ namespace vcpkg::Build static const std::string POST_BUILD_CHECKS_FAILED_STRING = "POST_BUILD_CHECKS_FAILED"; static const std::string CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING = "CASCADED_DUE_TO_MISSING_DEPENDENCIES"; static const std::string EXCLUDED_STRING = "EXCLUDED"; + static const std::string DOWNLOADED_STRING = "DOWNLOADED"; switch (build_result) { @@ -959,6 +981,7 @@ namespace vcpkg::Build case BuildResult::FILE_CONFLICTS: return FILE_CONFLICTS_STRING; case BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: return CASCADED_DUE_TO_MISSING_DEPENDENCIES_STRING; case BuildResult::EXCLUDED: return EXCLUDED_STRING; + case BuildResult::DOWNLOADED: return DOWNLOADED_STRING; default: Checks::unreachable(VCPKG_LINE_INFO); } } diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index f0f162f5c..6e0a71adf 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -212,6 +212,7 @@ namespace vcpkg::Commands::CI const Build::BuildPackageOptions build_options = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, + Build::OnlyDownloads::NO, Build::CleanBuildtrees::YES, Build::CleanPackages::YES, Build::CleanDownloads::NO, @@ -356,6 +357,7 @@ namespace vcpkg::Commands::CI const Build::BuildPackageOptions install_plan_options = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, + Build::OnlyDownloads::NO, Build::CleanBuildtrees::YES, Build::CleanPackages::YES, Build::CleanDownloads::NO, diff --git a/toolsrc/src/vcpkg/commands.upgrade.cpp b/toolsrc/src/vcpkg/commands.upgrade.cpp index 1e64b2eb6..b1dbf6194 100644 --- a/toolsrc/src/vcpkg/commands.upgrade.cpp +++ b/toolsrc/src/vcpkg/commands.upgrade.cpp @@ -154,6 +154,7 @@ namespace vcpkg::Commands::Upgrade const Build::BuildPackageOptions install_plan_options = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, + Build::OnlyDownloads::NO, Build::CleanBuildtrees::NO, Build::CleanPackages::NO, Build::CleanDownloads::NO, diff --git a/toolsrc/src/vcpkg/export.cpp b/toolsrc/src/vcpkg/export.cpp index 5ceb47adf..349d9aefd 100644 --- a/toolsrc/src/vcpkg/export.cpp +++ b/toolsrc/src/vcpkg/export.cpp @@ -73,6 +73,7 @@ namespace vcpkg::Export static constexpr Build::BuildPackageOptions BUILD_OPTIONS = { Build::UseHeadVersion::NO, Build::AllowDownloads::YES, + Build::OnlyDownloads::NO, Build::CleanBuildtrees::NO, Build::CleanPackages::NO, Build::CleanDownloads::NO, diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 1812f1624..009965887 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -342,6 +342,13 @@ namespace vcpkg::Install return Build::build_package(paths, build_config, status_db); }(); + if (BuildResult::DOWNLOADED == result.code) + { + System::print2( + System::Color::success, "Downloaded sources for package ", display_name_with_features, "\n"); + return result; + } + if (result.code != Build::BuildResult::SUCCEEDED) { System::print2(System::Color::error, Build::create_error_message(result.code, action.spec), "\n"); @@ -467,16 +474,18 @@ namespace vcpkg::Install static constexpr StringLiteral OPTION_DRY_RUN = "--dry-run"; static constexpr StringLiteral OPTION_USE_HEAD_VERSION = "--head"; static constexpr StringLiteral OPTION_NO_DOWNLOADS = "--no-downloads"; + static constexpr StringLiteral OPTION_ONLY_DOWNLOADS = "--only-downloads"; static constexpr StringLiteral OPTION_RECURSE = "--recurse"; static constexpr StringLiteral OPTION_KEEP_GOING = "--keep-going"; 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 std::array INSTALL_SWITCHES = {{ + static constexpr std::array INSTALL_SWITCHES = {{ {OPTION_DRY_RUN, "Do not actually build or install"}, {OPTION_USE_HEAD_VERSION, "Install the libraries on the command line using the latest upstream sources"}, {OPTION_NO_DOWNLOADS, "Do not download new sources"}, + {OPTION_ONLY_DOWNLOADS, "Download sources but don't build packages"}, {OPTION_RECURSE, "Allow removal of packages as part of installation"}, {OPTION_KEEP_GOING, "Continue installing packages on failure"}, {OPTION_USE_ARIA2, "Use aria2 to perform download tasks"}, @@ -631,10 +640,12 @@ namespace vcpkg::Install const bool dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN); const bool use_head_version = Util::Sets::contains(options.switches, (OPTION_USE_HEAD_VERSION)); const bool no_downloads = Util::Sets::contains(options.switches, (OPTION_NO_DOWNLOADS)); + const bool only_downloads = Util::Sets::contains(options.switches, (OPTION_ONLY_DOWNLOADS)); const bool is_recursive = Util::Sets::contains(options.switches, (OPTION_RECURSE)); const bool use_aria2 = Util::Sets::contains(options.switches, (OPTION_USE_ARIA2)); const bool clean_after_build = Util::Sets::contains(options.switches, (OPTION_CLEAN_AFTER_BUILD)); - const KeepGoing keep_going = to_keep_going(Util::Sets::contains(options.switches, OPTION_KEEP_GOING)); + const KeepGoing keep_going = + to_keep_going(Util::Sets::contains(options.switches, OPTION_KEEP_GOING) || only_downloads); auto& fs = paths.get_filesystem(); @@ -647,11 +658,12 @@ namespace vcpkg::Install const Build::BuildPackageOptions install_plan_options = { Util::Enum::to_enum(use_head_version), Util::Enum::to_enum(!no_downloads), + Util::Enum::to_enum(only_downloads), clean_after_build ? Build::CleanBuildtrees::YES : Build::CleanBuildtrees::NO, clean_after_build ? Build::CleanPackages::YES : Build::CleanPackages::NO, clean_after_build ? Build::CleanDownloads::YES : Build::CleanDownloads::NO, download_tool, - GlobalState::g_binary_caching ? Build::BinaryCaching::YES : Build::BinaryCaching::NO, + (GlobalState::g_binary_caching && !only_downloads) ? Build::BinaryCaching::YES : Build::BinaryCaching::NO, Build::FailOnTombstone::NO, }; -- cgit v1.2.3 From 84ba23ad3300a86e00841c5e26cbf753f6e89f3f Mon Sep 17 00:00:00 2001 From: Victor Romero Date: Fri, 6 Sep 2019 11:35:56 -0700 Subject: =?UTF-8?q?[x-history]=20Prints=20CONTROL=20version=20history=20of?= =?UTF-8?q?=20a=20port=20=F0=9F=91=BB=20(#7377)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [port-history] Print port CONTROL version history * Add commands.porthistory.cpp to VS project * Get most recent commit for each version * Apply clang-format * Fix output format * Rename command to x-history --- toolsrc/src/vcpkg/commands.cpp | 1 + toolsrc/src/vcpkg/commands.porthistory.cpp | 91 ++++++++++++++++++++++++++++++ toolsrc/src/vcpkg/help.cpp | 1 + 3 files changed, 93 insertions(+) create mode 100644 toolsrc/src/vcpkg/commands.porthistory.cpp (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/commands.cpp b/toolsrc/src/vcpkg/commands.cpp index 962dbd48b..1f424a559 100644 --- a/toolsrc/src/vcpkg/commands.cpp +++ b/toolsrc/src/vcpkg/commands.cpp @@ -47,6 +47,7 @@ namespace vcpkg::Commands {"autocomplete", &Autocomplete::perform_and_exit}, {"hash", &Hash::perform_and_exit}, {"fetch", &Fetch::perform_and_exit}, + {"x-history", &PortHistory::perform_and_exit}, {"x-vsinstances", &X_VSInstances::perform_and_exit}, }; return t; diff --git a/toolsrc/src/vcpkg/commands.porthistory.cpp b/toolsrc/src/vcpkg/commands.porthistory.cpp new file mode 100644 index 000000000..44fccbb7f --- /dev/null +++ b/toolsrc/src/vcpkg/commands.porthistory.cpp @@ -0,0 +1,91 @@ +#include "pch.h" + +#include +#include + +#include +#include +#include + +namespace vcpkg::Commands::PortHistory +{ + struct PortControlVersion + { + std::string commit_id; + std::string version; + std::string date; + }; + + static System::ExitCodeAndOutput run_git_command(const VcpkgPaths& paths, const std::string& cmd) + { + const fs::path& git_exe = paths.get_tool_exe(Tools::GIT); + const fs::path dot_git_dir = paths.root / ".git"; + + const std::string full_cmd = + Strings::format(R"("%s" --git-dir="%s" %s)", git_exe.u8string(), dot_git_dir.u8string(), cmd); + + auto output = System::cmd_execute_and_capture_output(full_cmd); + Checks::check_exit(VCPKG_LINE_INFO, output.exit_code == 0, "Failed to run command: %s", full_cmd); + return output; + } + + static std::string get_version_from_commit(const VcpkgPaths& paths, + const std::string& commit_id, + const std::string& port_name) + { + const std::string cmd = Strings::format(R"(show %s:ports/%s/CONTROL)", commit_id, port_name); + auto output = run_git_command(paths, cmd); + + const auto version = Strings::find_at_most_one_enclosed(output.output, "Version: ", "\n"); + Checks::check_exit(VCPKG_LINE_INFO, version.has_value(), "CONTROL file does not have a 'Version' field"); + return version.get()->to_string(); + } + + static std::vector read_versions_from_log(const VcpkgPaths& paths, const std::string& port_name) + { + const std::string cmd = + Strings::format(R"(log --format="%%H %%cd" --date=short --left-only -- ports/%s/.)", port_name); + auto output = run_git_command(paths, cmd); + + auto commits = Util::fmap( + Strings::split(output.output, "\n"), [](const std::string& line) -> auto { + auto parts = Strings::split(line, " "); + return std::make_pair(parts[0], parts[1]); + }); + + std::vector ret; + std::string last_version; + for (auto&& commit_date_pair : commits) + { + const std::string version = get_version_from_commit(paths, commit_date_pair.first, port_name); + if (last_version != version) + { + ret.emplace_back(PortControlVersion{commit_date_pair.first, version, commit_date_pair.second}); + last_version = version; + } + } + return ret; + } + + const CommandStructure COMMAND_STRUCTURE = { + Help::create_example_string("history "), + 1, + 1, + {}, + nullptr, + }; + + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) + { + Util::unused(args.parse_arguments(COMMAND_STRUCTURE)); + + std::string port_name = args.command_arguments.at(0); + std::vector versions = read_versions_from_log(paths, port_name); + System::print2(" version date vcpkg commit\n"); + for (auto&& version : versions) + { + System::printf("%20.20s %s %s\n", version.version, version.date, version.commit_id); + } + Checks::exit_success(VCPKG_LINE_INFO); + } +} diff --git a/toolsrc/src/vcpkg/help.cpp b/toolsrc/src/vcpkg/help.cpp index 9b2751739..1b8e8886e 100644 --- a/toolsrc/src/vcpkg/help.cpp +++ b/toolsrc/src/vcpkg/help.cpp @@ -91,6 +91,7 @@ namespace vcpkg::Help " vcpkg list List installed packages\n" " vcpkg update Display list of packages for updating\n" " vcpkg upgrade Rebuild all outdated packages\n" + " vcpkg history Shows the history of CONTROL versions of a package\n" " vcpkg hash [alg] Hash a file by specific algorithm, default SHA512\n" " vcpkg help topics Display the list of help topics\n" " vcpkg help Display help for a specific topic\n" -- cgit v1.2.3 From 90c3f80fffc376664e2a607c58e7f13ab06eb41e Mon Sep 17 00:00:00 2001 From: JackBoosY <47264268+JackBoosY@users.noreply.github.com> Date: Mon, 9 Sep 2019 23:53:24 +0800 Subject: fix x-history help desc. (#8101) --- toolsrc/src/vcpkg/help.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/help.cpp b/toolsrc/src/vcpkg/help.cpp index 1b8e8886e..48c836e63 100644 --- a/toolsrc/src/vcpkg/help.cpp +++ b/toolsrc/src/vcpkg/help.cpp @@ -91,7 +91,7 @@ namespace vcpkg::Help " vcpkg list List installed packages\n" " vcpkg update Display list of packages for updating\n" " vcpkg upgrade Rebuild all outdated packages\n" - " vcpkg history Shows the history of CONTROL versions of a package\n" + " vcpkg x-history Shows the history of CONTROL versions of a package\n" " vcpkg hash [alg] Hash a file by specific algorithm, default SHA512\n" " vcpkg help topics Display the list of help topics\n" " vcpkg help Display help for a specific topic\n" -- cgit v1.2.3 From cb0fc1a5f98f98aa8b86a32c9bce3074e775042e Mon Sep 17 00:00:00 2001 From: Victor Romero Date: Wed, 11 Sep 2019 11:10:31 -0700 Subject: [vcpkg] Fix depend-info command arguments (#8135) --- toolsrc/src/vcpkg/commands.dependinfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/commands.dependinfo.cpp b/toolsrc/src/vcpkg/commands.dependinfo.cpp index faf207980..79cbba590 100644 --- a/toolsrc/src/vcpkg/commands.dependinfo.cpp +++ b/toolsrc/src/vcpkg/commands.dependinfo.cpp @@ -228,8 +228,8 @@ namespace vcpkg::Commands::DependInfo const CommandStructure COMMAND_STRUCTURE = { Help::create_example_string("depend-info sqlite3"), - 0, - SIZE_MAX, + 1, + 1, {DEPEND_SWITCHES, DEPEND_SETTINGS}, nullptr, }; -- cgit v1.2.3 From 191c864927ea9e9e8788408adda4eff35d3edaf1 Mon Sep 17 00:00:00 2001 From: martin-s Date: Fri, 13 Sep 2019 06:52:52 +0000 Subject: Fix bug in `.vcpkg-root` detection that breaks `--overlay-triplets` (#7954) * - Added scripts variable to ports file. - Added check if triplet file is not available (NPE). * - Fixed line endings. * Provide location of .vcpkg-root to ports.cmake * vcpkg sets VCPKG_ROOT_PATH in ports.cmake * [vcpkg] Fail if VCPKG_ROOT_PATH is not passed from vcpkg.exe * [vcpkg] Fix vcpkg rooth path * [vcpkg] Make --x-scripts-root an experimental command --- toolsrc/src/vcpkg-test/arguments.cpp | 4 ++-- toolsrc/src/vcpkg/build.cpp | 1 + toolsrc/src/vcpkg/help.cpp | 2 +- toolsrc/src/vcpkg/vcpkgcmdarguments.cpp | 8 ++++---- toolsrc/src/vcpkg/vcpkgpaths.cpp | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg-test/arguments.cpp b/toolsrc/src/vcpkg-test/arguments.cpp index 326b07579..c63a31396 100644 --- a/toolsrc/src/vcpkg-test/arguments.cpp +++ b/toolsrc/src/vcpkg-test/arguments.cpp @@ -13,7 +13,7 @@ TEST_CASE ("VcpkgCmdArguments from lowercase argument sequence", "[arguments]") { std::vector t = {"--vcpkg-root", "C:\\vcpkg", - "--scripts-root=C:\\scripts", + "--x-scripts-root=C:\\scripts", "--debug", "--sendmetrics", "--printmetrics", @@ -45,7 +45,7 @@ TEST_CASE ("VcpkgCmdArguments from uppercase argument sequence", "[arguments]") { std::vector t = {"--VCPKG-ROOT", "C:\\vcpkg", - "--SCRIPTS-ROOT=C:\\scripts", + "--X-SCRIPTS-ROOT=C:\\scripts", "--DEBUG", "--SENDMETRICS", "--PRINTMETRICS", diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index e5c00b929..618e4126b 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -396,6 +396,7 @@ namespace vcpkg::Build {"CMD", "BUILD"}, {"PORT", config.scf.core_paragraph->name}, {"CURRENT_PORT_DIR", config.port_dir}, + {"VCPKG_ROOT_PATH", paths.root}, {"TARGET_TRIPLET", triplet.canonical_name()}, {"TARGET_TRIPLET_FILE", paths.get_triplet_file_path(triplet).u8string()}, {"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()}, diff --git a/toolsrc/src/vcpkg/help.cpp b/toolsrc/src/vcpkg/help.cpp index 48c836e63..0c53536fb 100644 --- a/toolsrc/src/vcpkg/help.cpp +++ b/toolsrc/src/vcpkg/help.cpp @@ -125,7 +125,7 @@ namespace vcpkg::Help " (default: " ENVVAR(VCPKG_ROOT) // ")\n" "\n" - " --scripts-root= Specify the scripts root directory\n" + " --x-scripts-root= (Experimental) Specify the scripts root directory\n" "\n" " @response_file Specify a " "response file to provide additional parameters\n" diff --git a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp index e48340df7..5f99b85e5 100644 --- a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp +++ b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp @@ -146,10 +146,10 @@ namespace vcpkg parse_value(arg_begin, arg_end, "--vcpkg-root", args.vcpkg_root_dir); continue; } - if (Strings::starts_with(arg, "--scripts-root=")) + if (Strings::starts_with(arg, "--x-scripts-root=")) { parse_cojoined_value( - arg.substr(sizeof("--scripts-root=") - 1), "--scripts-root", args.scripts_root_dir); + arg.substr(sizeof("--x-scripts-root=") - 1), "--x-scripts-root", args.scripts_root_dir); continue; } if (arg == "--triplet") @@ -430,7 +430,7 @@ namespace vcpkg "--vcpkg-root ", "Specify the vcpkg directory to use instead of current directory or tool directory"); System::printf(" %-40s %s\n", - "--scripts-root=", - "Specify the scripts directory to use instead of default vcpkg scripts directory"); + "--x-scripts-root=", + "(Experimental) Specify the scripts directory to use instead of default vcpkg scripts directory"); } } diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 4f01ed03b..078121fcc 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -76,7 +76,7 @@ namespace vcpkg Checks::exit_with_message( VCPKG_LINE_INFO, "Invalid scripts override directory: %s; " - "create that directory or unset --scripts-root to use the default scripts location.", + "create that directory or unset --x-scripts-root to use the default scripts location.", scripts_dir->u8string()); } -- cgit v1.2.3 From b4a0c8d57453cd77c5958800c345e6fd9938f0a4 Mon Sep 17 00:00:00 2001 From: Phoebe <925731795@qq.com> Date: Wed, 18 Sep 2019 00:35:50 +0800 Subject: [vcpkg] Continue on malformed paths in PATH (#8129) Previously vcpkg would exit on malformed paths. We now will continue and ignore the malformed path. --- toolsrc/src/vcpkg/base/files.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 5ebe8d834..3d7df1a68 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -185,6 +185,7 @@ namespace vcpkg::Files if (ec) Checks::exit_with_message(li, "error checking existence of file %s: %s", path.u8string(), ec.message()); return result; } + bool Filesystem::exists(const fs::path& path) const { std::error_code ec; @@ -667,13 +668,14 @@ namespace vcpkg::Files auto paths = Strings::split(System::get_environment_variable("PATH").value_or_exit(VCPKG_LINE_INFO), ";"); std::vector ret; + std::error_code ec; for (auto&& path : paths) { auto base = path + "/" + name; for (auto&& ext : EXTS) { auto p = fs::u8path(base + ext.c_str()); - if (Util::find(ret, p) == ret.end() && this->exists(VCPKG_LINE_INFO, p)) + if (Util::find(ret, p) == ret.end() && this->exists(p, ec)) { ret.push_back(p); Debug::print("Found path: ", p.u8string(), '\n'); -- cgit v1.2.3 From 54173e7fe250fc75604569708109bd6398b87694 Mon Sep 17 00:00:00 2001 From: Alexander Neumann <30894796+Neumann-A@users.noreply.github.com> Date: Tue, 17 Sep 2019 18:55:47 +0200 Subject: Fix #8193 (#8200) --- toolsrc/src/vcpkg/commands.create.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/commands.create.cpp b/toolsrc/src/vcpkg/commands.create.cpp index 31bf97f30..e04599dfe 100644 --- a/toolsrc/src/vcpkg/commands.create.cpp +++ b/toolsrc/src/vcpkg/commands.create.cpp @@ -24,7 +24,7 @@ namespace vcpkg::Commands::Create const fs::path& cmake_exe = paths.get_tool_exe(Tools::CMAKE); - std::vector cmake_args{{"CMD", "CREATE"}, {"PORT", port_name}, {"URL", url}}; + std::vector cmake_args{{"CMD", "CREATE"}, {"PORT", port_name}, {"URL", url}, {"VCPKG_ROOT_PATH", paths.root}}; if (args.command_arguments.size() >= 3) { -- cgit v1.2.3 From 2f4cb2d5be72ab6f40a2a5fc68f8c03a5fa1e8fd Mon Sep 17 00:00:00 2001 From: Phil Christensen Date: Thu, 26 Sep 2019 11:10:26 -0700 Subject: [CI system] Add features to test result xml (#8342) * Add features to test result xml --- toolsrc/src/vcpkg/commands.ci.cpp | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index 6e0a71adf..419d65f03 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -60,9 +60,10 @@ namespace vcpkg::Commands::CI void add_test_results(const std::string& spec, const Build::BuildResult& build_result, const Chrono::ElapsedTime& elapsed_time, - const std::string& abi_tag) + const std::string& abi_tag, + const std::vector& features) { - m_collections.back().tests.push_back({spec, build_result, elapsed_time, abi_tag}); + m_collections.back().tests.push_back({spec, build_result, elapsed_time, abi_tag, features}); } // Starting a new test collection @@ -98,6 +99,7 @@ namespace vcpkg::Commands::CI vcpkg::Build::BuildResult result; vcpkg::Chrono::ElapsedTime time; std::string abi_tag; + std::vector features; }; struct XunitCollection @@ -166,9 +168,29 @@ namespace vcpkg::Commands::CI } std::string traits_block; - if (test.abi_tag != "") // only adding if there is a known abi tag + if (test.abi_tag != "") { - traits_block = Strings::format(R"()", test.abi_tag); + traits_block += Strings::format(R"()", test.abi_tag); + } + + if (!test.features.empty()) + { + std::string feature_list; + for (const auto& feature : test.features) + { + if (!feature_list.empty()) + { + feature_list += ", "; + } + feature_list += feature; + } + + traits_block += Strings::format(R"()", feature_list); + } + + if (!traits_block.empty()) + { + traits_block = "" + traits_block + ""; } m_xml += Strings::format(R"( %s%s)" @@ -458,20 +480,24 @@ namespace vcpkg::Commands::CI // Adding results for ports that were built or pulled from an archive for (auto&& result : summary.results) { + auto& port_features = split_specs->features[result.spec]; split_specs->known.erase(result.spec); xunitTestResults.add_test_results(result.spec.to_string(), result.build_result.code, result.timing, - split_specs->abi_tag_map.at(result.spec)); + split_specs->abi_tag_map.at(result.spec), + port_features); } // Adding results for ports that were not built because they have known states for (auto&& port : split_specs->known) { + auto& port_features = split_specs->features[port.first]; xunitTestResults.add_test_results(port.first.to_string(), port.second, Chrono::ElapsedTime{}, - split_specs->abi_tag_map.at(port.first)); + split_specs->abi_tag_map.at(port.first), + port_features); } all_known_results.emplace_back(std::move(split_specs->known)); -- cgit v1.2.3 From 9f26ae8bf0888c8a5b6a92c792859dde044d005f Mon Sep 17 00:00:00 2001 From: Chris-SG Date: Tue, 8 Oct 2019 15:00:59 +1100 Subject: Find default for text/plain on Linux and Windows (#567) (#8435) * Find default for text/plain on machines with xdg (#567) * Add unicode aware detection of text/plain on windows --- toolsrc/src/vcpkg/commands.edit.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/commands.edit.cpp b/toolsrc/src/vcpkg/commands.edit.cpp index 6e98f5818..314af1167 100644 --- a/toolsrc/src/vcpkg/commands.edit.cpp +++ b/toolsrc/src/vcpkg/commands.edit.cpp @@ -167,6 +167,22 @@ namespace vcpkg::Commands::Edit const std::vector from_registry = find_from_registry(); candidate_paths.insert(candidate_paths.end(), from_registry.cbegin(), from_registry.cend()); + + const auto txt_default = System::get_registry_string(HKEY_CLASSES_ROOT, R"(.txt\ShellNew)", "ItemName"); + if(const auto entry = txt_default.get()) + { + #ifdef UNICODE + LPWSTR dst = new wchar_t[MAX_PATH]; + ExpandEnvironmentStrings(Strings::to_utf16(*entry).c_str(), dst, MAX_PATH); + auto full_path = Strings::to_utf8(dst); + #else + LPSTR dst = new char[MAX_PATH]; + ExpandEnvironmentStrings(entry->c_str(), dst, MAX_PATH); + auto full_path = std::string(dst); + #endif + auto begin = full_path.find_first_not_of('@'); + candidate_paths.push_back(fs::u8path(full_path.substr(begin, full_path.find_first_of(',')-begin))); + } #elif defined(__APPLE__) candidate_paths.push_back( fs::path{"/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code"}); @@ -174,6 +190,22 @@ namespace vcpkg::Commands::Edit #elif defined(__linux__) candidate_paths.push_back(fs::path{"/usr/share/code/bin/code"}); candidate_paths.push_back(fs::path{"/usr/bin/code"}); + + if(System::cmd_execute("command -v xdg-mime") == 0) + { + auto mime_qry = Strings::format(R"(xdg-mime query default text/plain)"); + auto execute_result = System::cmd_execute_and_capture_output(mime_qry); + if(execute_result.exit_code == 0 && !execute_result.output.empty()) + { + mime_qry = Strings::format(R"(command -v %s)", execute_result.output.substr(0, execute_result.output.find('.'))); + execute_result = System::cmd_execute_and_capture_output(mime_qry); + if(execute_result.exit_code == 0 && !execute_result.output.empty()) + { + execute_result.output.erase(std::remove(std::begin(execute_result.output), std::end(execute_result.output), '\n'), std::end(execute_result.output)); + candidate_paths.push_back(fs::path{execute_result.output}); + } + } + } #endif const auto it = Util::find_if(candidate_paths, [&](const fs::path& p) { return fs.exists(p); }); -- cgit v1.2.3 From 78c0fd26c4e75b595583c7ca671c32653518f3b4 Mon Sep 17 00:00:00 2001 From: Sergey Zolotarev Date: Thu, 17 Oct 2019 15:23:15 +0600 Subject: Fix compile error in Visual Studio 2017 15.1 --- toolsrc/src/vcpkg/install.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'toolsrc/src') diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 009965887..21be2d7b0 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -204,7 +204,7 @@ namespace vcpkg::Install { // The VS2015 standard library requires comparison operators of T and U // to also support comparison of T and T, and of U and U, due to debug checks. -#if _MSC_VER < 1910 +#if _MSC_VER <= 1910 bool operator()(const std::string& lhs, const std::string& rhs) { return lhs < rhs; } bool operator()(const file_pack& lhs, const file_pack& rhs) { return lhs.first < rhs.first; } #endif -- cgit v1.2.3