From ffac1482e83100571f14ff90e0ec74f264e1531f Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 9 Nov 2022 15:53:52 +0100 Subject: [PATCH 01/69] WIP: Test features in ci --- include/vcpkg/binarycaching.h | 3 + include/vcpkg/commands.setinstalled.h | 8 ++ include/vcpkg/packagespec.h | 3 + src/vcpkg/binarycaching.cpp | 10 +++ src/vcpkg/commands.ci.cpp | 119 +++++++++++++++++++++++++- src/vcpkg/commands.setinstalled.cpp | 61 +++++++------ src/vcpkg/install.cpp | 6 +- src/vcpkg/packagespec.cpp | 17 ++++ 8 files changed, 198 insertions(+), 29 deletions(-) diff --git a/include/vcpkg/binarycaching.h b/include/vcpkg/binarycaching.h index 378a8001b4..276d49c3fe 100644 --- a/include/vcpkg/binarycaching.h +++ b/include/vcpkg/binarycaching.h @@ -30,6 +30,7 @@ namespace vcpkg void mark_unavailable(const IBinaryProvider* sender); void mark_available(const IBinaryProvider* sender) noexcept; void mark_restored() noexcept; + void mark_unrestored() noexcept; private: CacheStatusState m_status = CacheStatusState::unknown; @@ -142,6 +143,8 @@ namespace vcpkg /// Returns a vector where each index corresponds to the matching index in `actions`. std::vector precheck(View actions); + void clear_cache(); + private: std::unordered_map m_status; std::vector> m_providers; diff --git a/include/vcpkg/commands.setinstalled.h b/include/vcpkg/commands.setinstalled.h index 083efa79d3..d5b40b7b70 100644 --- a/include/vcpkg/commands.setinstalled.h +++ b/include/vcpkg/commands.setinstalled.h @@ -8,6 +8,14 @@ namespace vcpkg::Commands::SetInstalled { extern const CommandStructure COMMAND_STRUCTURE; + + /** + * @brief adjust_action_plan_to_status_db creates an action plan that installs only the requested ports + * @param action_plan An action plan that was created with an empty status db + * @param status_db The status db of the installed folder + */ + void adjust_action_plan_to_status_db(ActionPlan& action_plan, const StatusParagraphs& status_db); + void perform_and_exit_ex(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const PathsPortFileProvider& provider, diff --git a/include/vcpkg/packagespec.h b/include/vcpkg/packagespec.h index b743864f47..a848420795 100644 --- a/include/vcpkg/packagespec.h +++ b/include/vcpkg/packagespec.h @@ -114,6 +114,9 @@ namespace vcpkg { } + std::string to_string() const; + void to_string(std::string& s) const; + /// Splats into individual FeatureSpec's void expand_fspecs_to(std::vector& oFut) const; diff --git a/src/vcpkg/binarycaching.cpp b/src/vcpkg/binarycaching.cpp index 162fde70fc..ae6c960c09 100644 --- a/src/vcpkg/binarycaching.cpp +++ b/src/vcpkg/binarycaching.cpp @@ -1458,6 +1458,14 @@ namespace vcpkg return results; } + void BinaryCache::clear_cache() + { + for (auto& entry : m_status) + { + entry.second.mark_unrestored(); + } + } + bool CacheStatus::should_attempt_precheck(const IBinaryProvider* sender) const noexcept { switch (m_status) @@ -1534,6 +1542,8 @@ namespace vcpkg } } + void CacheStatus::mark_unrestored() noexcept { m_status = CacheStatusState::available; } + const IBinaryProvider* CacheStatus::get_available_provider() const noexcept { switch (m_status) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index f6c42024c2..2088910d38 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -270,6 +271,28 @@ namespace vcpkg::Commands::CI }); } + static auto get_changed_ports_with_features(ActionPlan& action_plan, + std::unordered_map parent_versions) + { + std::vector ports_to_test; + for (const auto& action : action_plan.install_actions) + { + const auto& source_control_file = + action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_control_file; + if (source_control_file->feature_paragraphs.empty()) + { + continue; + } + auto iter = parent_versions.find(source_control_file->core_paragraph->name); + if (iter == parent_versions.end() || iter->second != source_control_file->to_version()) + { + ports_to_test.push_back( + action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_control_file.get()); + } + } + return ports_to_test; + } + static void parse_exclusions(const std::map>& settings, StringLiteral opt, Triplet triplet, @@ -451,6 +474,10 @@ namespace vcpkg::Commands::CI obj.insert("triplet", Json::Value::string(action.spec.triplet().canonical_name())); obj.insert("state", Json::Value::string(split_specs->action_state_string[i])); obj.insert("abi", Json::Value::string(action.abi_info.value_or_exit(VCPKG_LINE_INFO).package_abi)); + const auto& core_paragraph = action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO) + .source_control_file->core_paragraph; + obj.insert("version", Json::Value::string(core_paragraph->raw_version)); + obj.insert("port-version", Json::Value::integer(core_paragraph->port_version)); arr.push_back(std::move(obj)); } filesystem.write_contents(output_hash_json, Json::stringify(arr), VCPKG_LINE_INFO); @@ -458,6 +485,7 @@ namespace vcpkg::Commands::CI } std::vector parent_hashes; + std::unordered_map parent_versions; auto it_parent_hashes = settings.find(OPTION_PARENT_HASHES); if (it_parent_hashes != settings.end()) @@ -472,8 +500,20 @@ namespace vcpkg::Commands::CI #endif return abi->string(VCPKG_LINE_INFO).to_string(); }); + for (const auto& entry : parsed_json.first.array(VCPKG_LINE_INFO)) + { + const auto& object = entry.object(VCPKG_LINE_INFO); + auto name = object.get("name"); + Checks::check_exit(VCPKG_LINE_INFO, name); + auto version = object.get("version"); + Checks::check_exit(VCPKG_LINE_INFO, version); + auto port_version = object.get("port-version"); + Checks::check_exit(VCPKG_LINE_INFO, port_version); + parent_versions.emplace(name->string(VCPKG_LINE_INFO), + Version(version->string(VCPKG_LINE_INFO).to_string(), + static_cast(port_version->integer(VCPKG_LINE_INFO)))); + } } - reduce_action_plan(action_plan, split_specs->known, parent_hashes); msg::println(msgElapsedTimeForChecks, msg::elapsed = timer.elapsed()); @@ -494,6 +534,83 @@ namespace vcpkg::Commands::CI else { StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); + + // test port features + for (const auto port : get_changed_ports_with_features(action_plan, parent_versions)) + { + PackageSpec package_spec(port->core_paragraph->name, target_triplet); + var_provider.load_dep_info_vars(Span(&package_spec, 1), host_triplet); + const auto dep_info_vars = var_provider.get_dep_info_vars(package_spec).value_or_exit(VCPKG_LINE_INFO); + std::vector specs_to_test; + specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); + InternalFeatureSet all_features{{"core"}}; + for (const auto& feature : port->feature_paragraphs) + { + if (feature->supports_expression.evaluate(dep_info_vars)) + { + all_features.push_back(feature->name); + specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); + } + } + if (all_features.size() > 2) + { + specs_to_test.emplace_back(package_spec, all_features); + } + + for (auto& spec : specs_to_test) + { + auto install_plan = create_feature_install_plan(provider, + var_provider, + Span(&spec, 1), + {}, + {host_triplet, UnsupportedPortAction::Warn}); + if (!install_plan.warnings.empty()) + { + Debug::println("Skipping testing of ", + install_plan.install_actions.back().displayname(), + " because of the following warnings: \n", + Strings::join("\n", install_plan.warnings)); + continue; + } + print2("Test feature ", spec, '\n'); + compute_all_abis(paths, install_plan, var_provider, status_db); + // only install the absolute minimum + SetInstalled::adjust_action_plan_to_status_db(install_plan, status_db); + for (auto&& action : install_plan.install_actions) + { + action.build_options = default_build_package_options; + } + if (install_plan.install_actions.empty()) + { + print2("Test feature already installed \n"); + continue; + } + + compute_all_abis(paths, install_plan, var_provider, status_db); + if (binary_cache.precheck({&install_plan.install_actions.back(), 1}).front() == + CacheAvailability::available) + continue; + binary_cache.clear_cache(); + const auto summary = Install::perform(args, + install_plan, + KeepGoing::YES, + paths, + status_db, + binary_cache, + null_build_logs_recorder(), + var_provider); + if (summary.failed()) + { + print2("Feature ", spec, " failed with:\n"); + summary.print_failed(); + } + else + { + print2("Feature ", spec, " works \n"); + } + } + } + auto summary = Install::perform( args, action_plan, KeepGoing::YES, paths, status_db, binary_cache, build_logs_recorder, var_provider); diff --git a/src/vcpkg/commands.setinstalled.cpp b/src/vcpkg/commands.setinstalled.cpp index 802ef5e594..69f8545c32 100644 --- a/src/vcpkg/commands.setinstalled.cpp +++ b/src/vcpkg/commands.setinstalled.cpp @@ -38,39 +38,14 @@ namespace vcpkg::Commands::SetInstalled nullptr, }; - void perform_and_exit_ex(const VcpkgCmdArguments& args, - const VcpkgPaths& paths, - const PathsPortFileProvider& provider, - BinaryCache& binary_cache, - const CMakeVars::CMakeVarProvider& cmake_vars, - ActionPlan action_plan, - DryRun dry_run, - const Optional& maybe_pkgsconfig, - Triplet host_triplet, - const KeepGoing keep_going, - const bool only_downloads, - const PrintUsage print_cmake_usage) + void adjust_action_plan_to_status_db(ActionPlan& action_plan, const StatusParagraphs& status_db) { - auto& fs = paths.get_filesystem(); - - cmake_vars.load_tag_vars(action_plan, provider, host_triplet); - compute_all_abis(paths, action_plan, cmake_vars, {}); - std::set all_abis; - - std::vector user_requested_specs; for (const auto& action : action_plan.install_actions) { all_abis.insert(action.abi_info.value_or_exit(VCPKG_LINE_INFO).package_abi); - if (action.request_type == RequestType::USER_REQUESTED) - { - // save for reporting usage later - user_requested_specs.push_back(action.spec); - } } - // currently (or once) installed specifications - auto status_db = database_load_check(fs, paths.installed()); std::vector specs_to_remove; std::set specs_installed; for (auto&& status_pgh : status_db) @@ -101,6 +76,39 @@ namespace vcpkg::Commands::SetInstalled Util::erase_remove_if(action_plan.install_actions, [&](const InstallPlanAction& ipa) { return Util::Sets::contains(specs_installed, ipa.spec); }); + } + + void perform_and_exit_ex(const VcpkgCmdArguments& args, + const VcpkgPaths& paths, + const PathsPortFileProvider& provider, + BinaryCache& binary_cache, + const CMakeVars::CMakeVarProvider& cmake_vars, + ActionPlan action_plan, + DryRun dry_run, + const Optional& maybe_pkgsconfig, + Triplet host_triplet, + const KeepGoing keep_going, + const bool only_downloads, + const PrintUsage print_cmake_usage) + { + auto& fs = paths.get_filesystem(); + + cmake_vars.load_tag_vars(action_plan, provider, host_triplet); + compute_all_abis(paths, action_plan, cmake_vars, {}); + + std::vector user_requested_specs; + for (const auto& action : action_plan.install_actions) + { + if (action.request_type == RequestType::USER_REQUESTED) + { + // save for reporting usage later + user_requested_specs.push_back(action.spec); + } + } + + // currently (or once) installed specifications + auto status_db = database_load_check(fs, paths.installed()); + adjust_action_plan_to_status_db(action_plan, status_db); print_plan(action_plan, true, paths.builtin_ports_directory()); @@ -215,4 +223,5 @@ namespace vcpkg::Commands::SetInstalled { SetInstalled::perform_and_exit(args, paths, default_triplet, host_triplet); } + } diff --git a/src/vcpkg/install.cpp b/src/vcpkg/install.cpp index f91b069ae8..8222bbe813 100644 --- a/src/vcpkg/install.cpp +++ b/src/vcpkg/install.cpp @@ -454,9 +454,11 @@ namespace vcpkg { for (const auto& result : this->results) { - if (result.build_result.value_or_exit(VCPKG_LINE_INFO).code != BuildResult::SUCCEEDED) + switch (result.build_result.value_or_exit(VCPKG_LINE_INFO).code) { - return true; + case BuildResult::SUCCEEDED: + case BuildResult::REMOVED: continue; + default: return true; } } return false; diff --git a/src/vcpkg/packagespec.cpp b/src/vcpkg/packagespec.cpp index 1a7a498b68..2984b2d009 100644 --- a/src/vcpkg/packagespec.cpp +++ b/src/vcpkg/packagespec.cpp @@ -20,6 +20,23 @@ namespace vcpkg Strings::append(out, port(), '[', feature(), "]:", triplet()); } + std::string FullPackageSpec::to_string() const + { + std::string ret; + this->to_string(ret); + return ret; + } + + void FullPackageSpec::to_string(std::string& out) const + { + out += package_spec.name(); + if (!features.empty()) + { + Strings::append(out, '[', Strings::join(",", features), ']'); + } + Strings::append(out, ':', package_spec.triplet()); + } + void FullPackageSpec::expand_fspecs_to(std::vector& out) const { for (auto&& feature : features) From adc9011a9351ab010fc3277a535065ae669ed0bb Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 9 Nov 2022 16:55:15 +0100 Subject: [PATCH 02/69] Add command line to specify which ports to test and how features are tested instead of testing all "changed" ports --- include/vcpkg/base/lineinfo.h | 5 +- src/vcpkg/commands.ci.cpp | 112 +++++++++++++++++++--------------- 2 files changed, 68 insertions(+), 49 deletions(-) diff --git a/include/vcpkg/base/lineinfo.h b/include/vcpkg/base/lineinfo.h index 68fca2e0e8..29b8ede563 100644 --- a/include/vcpkg/base/lineinfo.h +++ b/include/vcpkg/base/lineinfo.h @@ -10,4 +10,7 @@ namespace vcpkg } #define VCPKG_LINE_INFO \ - vcpkg::LineInfo { __LINE__, __FILE__ } + vcpkg::LineInfo \ + { \ + __LINE__, __FILE__ \ + } diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 2088910d38..1d2ce3f072 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -102,26 +102,38 @@ namespace vcpkg::Commands::CI static constexpr StringLiteral OPTION_OUTPUT_HASHES = "output-hashes"; static constexpr StringLiteral OPTION_PARENT_HASHES = "parent-hashes"; static constexpr StringLiteral OPTION_SKIPPED_CASCADE_COUNT = "x-skipped-cascade-count"; + static constexpr StringLiteral OPTION_TEST_CORE_FEATURE = "test-core-feature"; + static constexpr StringLiteral OPTION_TEST_COMBINED_FEATURES = "test-combined-features"; + static constexpr StringLiteral OPTION_TEST_FEATURES_SEPERATLY = "test-features-seperatly"; + static constexpr StringLiteral OPTION_TEST_FEATURES_PORTS = "test-features-of-ports"; + static constexpr StringLiteral OPTION_TEST_FEATURES_ALL_PORTS = "test-features-of-all-ports"; + + static constexpr std::array CI_SETTINGS = {{ + {OPTION_EXCLUDE, "Comma separated list of ports to skip"}, + {OPTION_HOST_EXCLUDE, "Comma separated list of ports to skip for the host triplet"}, + {OPTION_XUNIT, "File to output results in XUnit format (internal)"}, + {OPTION_CI_BASELINE, "Path to the ci.baseline.txt file. Used to skip ports and detect regressions."}, + {OPTION_FAILURE_LOGS, "Directory to which failure logs will be copied"}, + {OPTION_OUTPUT_HASHES, "File to output all determined package hashes"}, + {OPTION_PARENT_HASHES, + "File to read package hashes for a parent CI state, to reduce the set of changed packages"}, + {OPTION_SKIPPED_CASCADE_COUNT, + "Asserts that the number of --exclude and supports skips exactly equal this number"}, + {OPTION_TEST_FEATURES_PORTS, + "A comma seperated list of ports for which the specified feature tests should be run"}, + }}; - static constexpr std::array CI_SETTINGS = { - {{OPTION_EXCLUDE, "Comma separated list of ports to skip"}, - {OPTION_HOST_EXCLUDE, "Comma separated list of ports to skip for the host triplet"}, - {OPTION_XUNIT, "File to output results in XUnit format (internal)"}, - {OPTION_CI_BASELINE, "Path to the ci.baseline.txt file. Used to skip ports and detect regressions."}, - {OPTION_FAILURE_LOGS, "Directory to which failure logs will be copied"}, - {OPTION_OUTPUT_HASHES, "File to output all determined package hashes"}, - {OPTION_PARENT_HASHES, - "File to read package hashes for a parent CI state, to reduce the set of changed packages"}, - {OPTION_SKIPPED_CASCADE_COUNT, - "Asserts that the number of --exclude and supports skips exactly equal this number"}}}; - - static constexpr std::array CI_SWITCHES = {{ + static constexpr std::array CI_SWITCHES = {{ {OPTION_DRY_RUN, "Print out plan without execution"}, {OPTION_RANDOMIZE, "Randomize the install order"}, {OPTION_ALLOW_UNEXPECTED_PASSING, "Indicates that 'Passing, remove from fail list' results should not be emitted."}, {OPTION_SKIP_FAILURES, "Indicates that ports marked `=fail` in ci.baseline.txt should be skipped."}, {OPTION_XUNIT_ALL, "Report also unchanged ports to the XUnit output (internal)"}, + {OPTION_TEST_FEATURES_ALL_PORTS, "Runs the specified tests for all ports"}, + {OPTION_TEST_CORE_FEATURE, "Tests the 'core' feature for every specified port"}, + {OPTION_TEST_FEATURES_SEPERATLY, "Tests every feature of a port seperatly for every specified port"}, + {OPTION_TEST_COMBINED_FEATURES, "Tests the combination of every feature of a port for every specified port"}, }}; const CommandStructure COMMAND_STRUCTURE = { @@ -271,23 +283,28 @@ namespace vcpkg::Commands::CI }); } - static auto get_changed_ports_with_features(ActionPlan& action_plan, - std::unordered_map parent_versions) + static auto get_ports_to_test_with_features(const ParsedArguments& args, ActionPlan& action_plan) { + const auto all_ports = Util::Sets::contains(args.switches, OPTION_TEST_FEATURES_ALL_PORTS); + std::vector ports; + auto iter = args.settings.find(OPTION_TEST_FEATURES_PORTS); + if (iter != args.settings.end()) + { + ports = Strings::split(iter->second, ','); + } std::vector ports_to_test; - for (const auto& action : action_plan.install_actions) + if (all_ports || !ports.empty()) { - const auto& source_control_file = - action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_control_file; - if (source_control_file->feature_paragraphs.empty()) + for (const auto& action : action_plan.install_actions) { - continue; - } - auto iter = parent_versions.find(source_control_file->core_paragraph->name); - if (iter == parent_versions.end() || iter->second != source_control_file->to_version()) - { - ports_to_test.push_back( - action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_control_file.get()); + const auto& source_control_file = + action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_control_file; + + if (all_ports || Util::Vectors::contains(ports, source_control_file->core_paragraph->name)) + { + ports_to_test.push_back(action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO) + .source_control_file.get()); + } } } return ports_to_test; @@ -474,10 +491,6 @@ namespace vcpkg::Commands::CI obj.insert("triplet", Json::Value::string(action.spec.triplet().canonical_name())); obj.insert("state", Json::Value::string(split_specs->action_state_string[i])); obj.insert("abi", Json::Value::string(action.abi_info.value_or_exit(VCPKG_LINE_INFO).package_abi)); - const auto& core_paragraph = action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO) - .source_control_file->core_paragraph; - obj.insert("version", Json::Value::string(core_paragraph->raw_version)); - obj.insert("port-version", Json::Value::integer(core_paragraph->port_version)); arr.push_back(std::move(obj)); } filesystem.write_contents(output_hash_json, Json::stringify(arr), VCPKG_LINE_INFO); @@ -485,7 +498,6 @@ namespace vcpkg::Commands::CI } std::vector parent_hashes; - std::unordered_map parent_versions; auto it_parent_hashes = settings.find(OPTION_PARENT_HASHES); if (it_parent_hashes != settings.end()) @@ -500,19 +512,6 @@ namespace vcpkg::Commands::CI #endif return abi->string(VCPKG_LINE_INFO).to_string(); }); - for (const auto& entry : parsed_json.first.array(VCPKG_LINE_INFO)) - { - const auto& object = entry.object(VCPKG_LINE_INFO); - auto name = object.get("name"); - Checks::check_exit(VCPKG_LINE_INFO, name); - auto version = object.get("version"); - Checks::check_exit(VCPKG_LINE_INFO, version); - auto port_version = object.get("port-version"); - Checks::check_exit(VCPKG_LINE_INFO, port_version); - parent_versions.emplace(name->string(VCPKG_LINE_INFO), - Version(version->string(VCPKG_LINE_INFO).to_string(), - static_cast(port_version->integer(VCPKG_LINE_INFO)))); - } } reduce_action_plan(action_plan, split_specs->known, parent_hashes); @@ -536,23 +535,40 @@ namespace vcpkg::Commands::CI StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); // test port features - for (const auto port : get_changed_ports_with_features(action_plan, parent_versions)) + const auto test_core = Util::Sets::contains(options.switches, OPTION_TEST_CORE_FEATURE); + const auto test_combined = Util::Sets::contains(options.switches, OPTION_TEST_COMBINED_FEATURES); + const auto test_seperatly = Util::Sets::contains(options.switches, OPTION_TEST_FEATURES_SEPERATLY); + + auto ports_to_test = get_ports_to_test_with_features(options, action_plan); + Checks::check_exit(VCPKG_LINE_INFO, + !((test_core || test_combined || test_seperatly) && ports_to_test.empty()), + "You specify a flag to test features, but not which port should be checked"); + Checks::check_exit(VCPKG_LINE_INFO, + !(!(test_core || test_combined || test_seperatly) && !ports_to_test.empty()), + "You specify which port should be checked for features, but not which checks"); + for (const auto port : ports_to_test) { PackageSpec package_spec(port->core_paragraph->name, target_triplet); var_provider.load_dep_info_vars(Span(&package_spec, 1), host_triplet); const auto dep_info_vars = var_provider.get_dep_info_vars(package_spec).value_or_exit(VCPKG_LINE_INFO); std::vector specs_to_test; - specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); + if (test_core) + { + specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); + } InternalFeatureSet all_features{{"core"}}; for (const auto& feature : port->feature_paragraphs) { if (feature->supports_expression.evaluate(dep_info_vars)) { all_features.push_back(feature->name); - specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); + if (test_seperatly) + { + specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); + } } } - if (all_features.size() > 2) + if (test_combined && all_features.size() > 2) { specs_to_test.emplace_back(package_spec, all_features); } From 5f994187730fdad8e90ba8c5af33af8f74e7237c Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 9 Nov 2022 17:58:19 +0100 Subject: [PATCH 03/69] Use old clang-format --- include/vcpkg/base/lineinfo.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/vcpkg/base/lineinfo.h b/include/vcpkg/base/lineinfo.h index 29b8ede563..68fca2e0e8 100644 --- a/include/vcpkg/base/lineinfo.h +++ b/include/vcpkg/base/lineinfo.h @@ -10,7 +10,4 @@ namespace vcpkg } #define VCPKG_LINE_INFO \ - vcpkg::LineInfo \ - { \ - __LINE__, __FILE__ \ - } + vcpkg::LineInfo { __LINE__, __FILE__ } From 80a53a3a3a57802b710060efd9d5359dc5ca6f3e Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 9 Nov 2022 18:52:59 +0100 Subject: [PATCH 04/69] optimize --- src/vcpkg/commands.ci.cpp | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 1d2ce3f072..18e7fa5b97 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -582,31 +582,31 @@ namespace vcpkg::Commands::CI {host_triplet, UnsupportedPortAction::Warn}); if (!install_plan.warnings.empty()) { - Debug::println("Skipping testing of ", - install_plan.install_actions.back().displayname(), - " because of the following warnings: \n", - Strings::join("\n", install_plan.warnings)); + print2("Skipping testing of ", + install_plan.install_actions.back().displayname(), + " because of the following warnings: \n", + Strings::join("\n", install_plan.warnings), + '\n'); continue; } - print2("Test feature ", spec, '\n'); + compute_all_abis(paths, install_plan, var_provider, status_db); // only install the absolute minimum SetInstalled::adjust_action_plan_to_status_db(install_plan, status_db); - for (auto&& action : install_plan.install_actions) + if (install_plan.install_actions.empty()) // already installed { - action.build_options = default_build_package_options; - } - if (install_plan.install_actions.empty()) - { - print2("Test feature already installed \n"); continue; } - compute_all_abis(paths, install_plan, var_provider, status_db); if (binary_cache.precheck({&install_plan.install_actions.back(), 1}).front() == CacheAvailability::available) continue; + print2("Test feature ", spec, '\n'); binary_cache.clear_cache(); + for (auto&& action : install_plan.install_actions) + { + action.build_options = backcompat_prohibiting_package_options; + } const auto summary = Install::perform(args, install_plan, KeepGoing::YES, @@ -615,14 +615,13 @@ namespace vcpkg::Commands::CI binary_cache, null_build_logs_recorder(), var_provider); - if (summary.failed()) - { - print2("Feature ", spec, " failed with:\n"); - summary.print_failed(); - } - else + switch (summary.results.back().build_result.value_or_exit(VCPKG_LINE_INFO).code) { - print2("Feature ", spec, " works \n"); + case vcpkg::BuildResult::SUCCEEDED: + case vcpkg::BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: + print2("Feature ", spec, " works \n"); + break; + default: print2("Feature ", spec, " failed with \n"); } } } From 6946d6a5fe9e398962ea9b682a427a494477fab6 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Thu, 10 Nov 2022 16:53:39 +0100 Subject: [PATCH 05/69] Don't delete packages folders --- src/vcpkg/commands.ci.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 18e7fa5b97..34f1546caf 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -602,10 +602,10 @@ namespace vcpkg::Commands::CI CacheAvailability::available) continue; print2("Test feature ", spec, '\n'); - binary_cache.clear_cache(); for (auto&& action : install_plan.install_actions) { action.build_options = backcompat_prohibiting_package_options; + action.build_options.clean_packages = CleanPackages::NO; // The binary cache assumes this } const auto summary = Install::perform(args, install_plan, @@ -625,6 +625,7 @@ namespace vcpkg::Commands::CI } } } + SetInstalled::adjust_action_plan_to_status_db(action_plan, status_db); auto summary = Install::perform( args, action_plan, KeepGoing::YES, paths, status_db, binary_cache, build_logs_recorder, var_provider); From a93c7072b35c2097517839e38b1393b64cd77b5c Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Thu, 10 Nov 2022 17:19:03 +0100 Subject: [PATCH 06/69] Don't purge packages folder to make the binary cache happy --- include/vcpkg/install.h | 4 +++- src/vcpkg/commands.ci.cpp | 3 ++- src/vcpkg/install.cpp | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/vcpkg/install.h b/include/vcpkg/install.h index 93103c85ac..579b088ef0 100644 --- a/include/vcpkg/install.h +++ b/include/vcpkg/install.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -115,7 +116,8 @@ namespace vcpkg StatusParagraphs& status_db, BinaryCache& binary_cache, const IBuildLogsRecorder& build_logs_recorder, - const CMakeVars::CMakeVarProvider& var_provider); + const CMakeVars::CMakeVarProvider& var_provider, + Remove::Purge purge = Remove::Purge::YES); void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 34f1546caf..6567be0349 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -614,7 +614,8 @@ namespace vcpkg::Commands::CI status_db, binary_cache, null_build_logs_recorder(), - var_provider); + var_provider, + Remove::Purge::NO); // The binary cache assumes this switch (summary.results.back().build_result.value_or_exit(VCPKG_LINE_INFO).code) { case vcpkg::BuildResult::SUCCEEDED: diff --git a/src/vcpkg/install.cpp b/src/vcpkg/install.cpp index 8222bbe813..eaf361ee90 100644 --- a/src/vcpkg/install.cpp +++ b/src/vcpkg/install.cpp @@ -511,7 +511,8 @@ namespace vcpkg StatusParagraphs& status_db, BinaryCache& binary_cache, const IBuildLogsRecorder& build_logs_recorder, - const CMakeVars::CMakeVarProvider& var_provider) + const CMakeVars::CMakeVarProvider& var_provider, + Remove::Purge purge) { const ElapsedTimer timer; std::vector results; @@ -521,7 +522,7 @@ namespace vcpkg for (auto&& action : action_plan.remove_actions) { TrackedPackageInstallGuard this_install(action_index++, action_count, results, action); - Remove::perform_remove_plan_action(paths, action, Remove::Purge::YES, &status_db); + Remove::perform_remove_plan_action(paths, action, purge, &status_db); results.back().build_result.emplace(BuildResult::REMOVED); } From bbdf7e76ad607aaa275341672878180024e8d409 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Fri, 11 Nov 2022 00:01:51 +0100 Subject: [PATCH 07/69] Clear internal binary cache state instead of keep packages folder because the packages folder is deleted when a package fails --- src/vcpkg/commands.ci.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 6567be0349..2711720692 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -605,7 +605,6 @@ namespace vcpkg::Commands::CI for (auto&& action : install_plan.install_actions) { action.build_options = backcompat_prohibiting_package_options; - action.build_options.clean_packages = CleanPackages::NO; // The binary cache assumes this } const auto summary = Install::perform(args, install_plan, @@ -614,8 +613,8 @@ namespace vcpkg::Commands::CI status_db, binary_cache, null_build_logs_recorder(), - var_provider, - Remove::Purge::NO); // The binary cache assumes this + var_provider); + binary_cache.clear_cache(); switch (summary.results.back().build_result.value_or_exit(VCPKG_LINE_INFO).code) { case vcpkg::BuildResult::SUCCEEDED: From c6ed7b3e4e620ce28507436aef8a1c912732b03a Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Fri, 11 Nov 2022 00:03:05 +0100 Subject: [PATCH 08/69] Don't try to build known failures. --- include/vcpkg/install.h | 4 ++++ src/vcpkg/commands.ci.cpp | 49 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/include/vcpkg/install.h b/include/vcpkg/install.h index 579b088ef0..59d169539c 100644 --- a/include/vcpkg/install.h +++ b/include/vcpkg/install.h @@ -33,6 +33,10 @@ namespace vcpkg const BinaryParagraph* get_binary_paragraph() const; const PackageSpec& get_spec() const { return m_spec; } + Optional get_abi() const + { + return m_install_action ? m_install_action->package_abi() : nullopt; + } bool is_user_requested_install() const; Optional build_result; vcpkg::ElapsedTime timing; diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 2711720692..e544707b82 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -546,6 +546,7 @@ namespace vcpkg::Commands::CI Checks::check_exit(VCPKG_LINE_INFO, !(!(test_core || test_combined || test_seperatly) && !ports_to_test.empty()), "You specify which port should be checked for features, but not which checks"); + std::unordered_set known_failures; for (const auto port : ports_to_test) { PackageSpec package_spec(port->core_paragraph->name, target_triplet); @@ -591,6 +592,15 @@ namespace vcpkg::Commands::CI } compute_all_abis(paths, install_plan, var_provider, status_db); + if (Util::any_of(install_plan.install_actions, [&known_failures](const auto& install_action) { + return Util::Sets::contains(known_failures, + install_action.package_abi().value_or_exit(VCPKG_LINE_INFO)); + })) + { + print2(spec, " will fail tested\n"); + continue; + } + // only install the absolute minimum SetInstalled::adjust_action_plan_to_status_db(install_plan, status_db); if (install_plan.install_actions.empty()) // already installed @@ -615,6 +625,18 @@ namespace vcpkg::Commands::CI null_build_logs_recorder(), var_provider); binary_cache.clear_cache(); + for (const auto& result : summary.results) + { + switch (result.build_result.value_or_exit(VCPKG_LINE_INFO).code) + { + case BuildResult::BUILD_FAILED: + case BuildResult::POST_BUILD_CHECKS_FAILED: + case BuildResult::FILE_CONFLICTS: + known_failures.insert(result.get_abi().value_or_exit(VCPKG_LINE_INFO)); + break; + default: break; + } + } switch (summary.results.back().build_result.value_or_exit(VCPKG_LINE_INFO).code) { case vcpkg::BuildResult::SUCCEEDED: @@ -625,6 +647,33 @@ namespace vcpkg::Commands::CI } } } + + if (!known_failures.empty()) + { + // remove known failures from the action_plan.install_actions + std::set known_failure_specs; + for (const auto& install_action : action_plan.install_actions) + { + if (Util::Sets::contains(known_failures, + install_action.package_abi().value_or_exit(VCPKG_LINE_INFO))) + { + split_specs->known.emplace(install_action.spec, BuildResult::BUILD_FAILED); + known_failure_specs.emplace(install_action.spec); + } + else if (Util::any_of(install_action.package_dependencies, [&](const PackageSpec& spec) { + return Util::Sets::contains(known_failure_specs, spec); + })) + { + split_specs->known.emplace(install_action.spec, + BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES); + known_failure_specs.emplace(install_action.spec); + } + } + Util::erase_remove_if(action_plan.install_actions, + [&known_failure_specs](const InstallPlanAction& action) { + return Util::Sets::contains(known_failure_specs, action.spec); + }); + } SetInstalled::adjust_action_plan_to_status_db(action_plan, status_db); auto summary = Install::perform( From a1a01888de22dd9a2acf2882c721a4531b8dcb91 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 12 Nov 2022 14:08:45 +0100 Subject: [PATCH 09/69] Rename command line arguments --- src/vcpkg/commands.ci.cpp | 53 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index e544707b82..b72001ddb6 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -102,11 +102,11 @@ namespace vcpkg::Commands::CI static constexpr StringLiteral OPTION_OUTPUT_HASHES = "output-hashes"; static constexpr StringLiteral OPTION_PARENT_HASHES = "parent-hashes"; static constexpr StringLiteral OPTION_SKIPPED_CASCADE_COUNT = "x-skipped-cascade-count"; - static constexpr StringLiteral OPTION_TEST_CORE_FEATURE = "test-core-feature"; - static constexpr StringLiteral OPTION_TEST_COMBINED_FEATURES = "test-combined-features"; + static constexpr StringLiteral OPTION_TEST_FEATURE_CORE = "test-feature-core"; + static constexpr StringLiteral OPTION_TEST_FEATURES_COMBINED = "test-features-combined"; static constexpr StringLiteral OPTION_TEST_FEATURES_SEPERATLY = "test-features-seperatly"; - static constexpr StringLiteral OPTION_TEST_FEATURES_PORTS = "test-features-of-ports"; - static constexpr StringLiteral OPTION_TEST_FEATURES_ALL_PORTS = "test-features-of-all-ports"; + static constexpr StringLiteral OPTION_RUN_FEATURE_TESTS_PORTS = "run-feature-tests-for-ports"; + static constexpr StringLiteral OPTION_RUN_FEATURE_TESTS_ALL_PORTS = "run-feature-tests-for-all-ports"; static constexpr std::array CI_SETTINGS = {{ {OPTION_EXCLUDE, "Comma separated list of ports to skip"}, @@ -119,7 +119,7 @@ namespace vcpkg::Commands::CI "File to read package hashes for a parent CI state, to reduce the set of changed packages"}, {OPTION_SKIPPED_CASCADE_COUNT, "Asserts that the number of --exclude and supports skips exactly equal this number"}, - {OPTION_TEST_FEATURES_PORTS, + {OPTION_RUN_FEATURE_TESTS_PORTS, "A comma seperated list of ports for which the specified feature tests should be run"}, }}; @@ -130,10 +130,10 @@ namespace vcpkg::Commands::CI "Indicates that 'Passing, remove from fail list' results should not be emitted."}, {OPTION_SKIP_FAILURES, "Indicates that ports marked `=fail` in ci.baseline.txt should be skipped."}, {OPTION_XUNIT_ALL, "Report also unchanged ports to the XUnit output (internal)"}, - {OPTION_TEST_FEATURES_ALL_PORTS, "Runs the specified tests for all ports"}, - {OPTION_TEST_CORE_FEATURE, "Tests the 'core' feature for every specified port"}, + {OPTION_RUN_FEATURE_TESTS_ALL_PORTS, "Runs the specified tests for all ports"}, + {OPTION_TEST_FEATURE_CORE, "Tests the 'core' feature for every specified port"}, {OPTION_TEST_FEATURES_SEPERATLY, "Tests every feature of a port seperatly for every specified port"}, - {OPTION_TEST_COMBINED_FEATURES, "Tests the combination of every feature of a port for every specified port"}, + {OPTION_TEST_FEATURES_COMBINED, "Tests the combination of every feature of a port for every specified port"}, }}; const CommandStructure COMMAND_STRUCTURE = { @@ -285,9 +285,9 @@ namespace vcpkg::Commands::CI static auto get_ports_to_test_with_features(const ParsedArguments& args, ActionPlan& action_plan) { - const auto all_ports = Util::Sets::contains(args.switches, OPTION_TEST_FEATURES_ALL_PORTS); + const auto all_ports = Util::Sets::contains(args.switches, OPTION_RUN_FEATURE_TESTS_ALL_PORTS); std::vector ports; - auto iter = args.settings.find(OPTION_TEST_FEATURES_PORTS); + auto iter = args.settings.find(OPTION_RUN_FEATURE_TESTS_PORTS); if (iter != args.settings.end()) { ports = Strings::split(iter->second, ','); @@ -376,6 +376,20 @@ namespace vcpkg::Commands::CI const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); const auto& settings = options.settings; + const auto test_feature_core = Util::Sets::contains(options.switches, OPTION_TEST_FEATURE_CORE); + const auto test_features_combined = Util::Sets::contains(options.switches, OPTION_TEST_FEATURES_COMBINED); + const auto test_features_seperatly = Util::Sets::contains(options.switches, OPTION_TEST_FEATURES_SEPERATLY); + + const auto run_tests_all_ports = Util::Sets::contains(options.switches, OPTION_RUN_FEATURE_TESTS_ALL_PORTS); + const auto run_tests_ports_list = Util::Sets::contains(options.settings, OPTION_RUN_FEATURE_TESTS_PORTS); + { + const auto tests_selected = test_feature_core || test_features_combined || test_features_seperatly; + const auto ports_selected = run_tests_all_ports || run_tests_ports_list; + Checks::check_exit(VCPKG_LINE_INFO, + (tests_selected && ports_selected) || (!tests_selected && !ports_selected), + "You specify a flag to test features, but not which port should be checked"); + } + BinaryCache binary_cache{args, paths}; ExclusionsMap exclusions_map; @@ -535,25 +549,14 @@ namespace vcpkg::Commands::CI StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); // test port features - const auto test_core = Util::Sets::contains(options.switches, OPTION_TEST_CORE_FEATURE); - const auto test_combined = Util::Sets::contains(options.switches, OPTION_TEST_COMBINED_FEATURES); - const auto test_seperatly = Util::Sets::contains(options.switches, OPTION_TEST_FEATURES_SEPERATLY); - - auto ports_to_test = get_ports_to_test_with_features(options, action_plan); - Checks::check_exit(VCPKG_LINE_INFO, - !((test_core || test_combined || test_seperatly) && ports_to_test.empty()), - "You specify a flag to test features, but not which port should be checked"); - Checks::check_exit(VCPKG_LINE_INFO, - !(!(test_core || test_combined || test_seperatly) && !ports_to_test.empty()), - "You specify which port should be checked for features, but not which checks"); std::unordered_set known_failures; - for (const auto port : ports_to_test) + for (const auto port : get_ports_to_test_with_features(options, action_plan)) { PackageSpec package_spec(port->core_paragraph->name, target_triplet); var_provider.load_dep_info_vars(Span(&package_spec, 1), host_triplet); const auto dep_info_vars = var_provider.get_dep_info_vars(package_spec).value_or_exit(VCPKG_LINE_INFO); std::vector specs_to_test; - if (test_core) + if (test_feature_core) { specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); } @@ -563,13 +566,13 @@ namespace vcpkg::Commands::CI if (feature->supports_expression.evaluate(dep_info_vars)) { all_features.push_back(feature->name); - if (test_seperatly) + if (test_features_seperatly) { specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); } } } - if (test_combined && all_features.size() > 2) + if (test_features_combined && all_features.size() > (test_features_seperatly ? 2 : 1)) { specs_to_test.emplace_back(package_spec, all_features); } From 1f9ebad13b0f0065da86bd7d963d8c3f0a8aca37 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 12 Nov 2022 14:40:53 +0100 Subject: [PATCH 10/69] Make pipeline happy --- src/vcpkg/commands.ci.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index b72001ddb6..060eca9724 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -572,7 +572,7 @@ namespace vcpkg::Commands::CI } } } - if (test_features_combined && all_features.size() > (test_features_seperatly ? 2 : 1)) + if (test_features_combined && all_features.size() > test_features_seperatly ? size_t{2} : size_t{1}) { specs_to_test.emplace_back(package_spec, all_features); } From fcefd69a7ae52b2bba92e24f98663b96fbc974d4 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 12 Nov 2022 15:51:13 +0100 Subject: [PATCH 11/69] Fix windows --- src/vcpkg/commands.ci.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 060eca9724..6a30cc5dd6 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -572,7 +572,7 @@ namespace vcpkg::Commands::CI } } } - if (test_features_combined && all_features.size() > test_features_seperatly ? size_t{2} : size_t{1}) + if (test_features_combined && all_features.size() > (test_features_seperatly ? size_t{2} : size_t{1})) { specs_to_test.emplace_back(package_spec, all_features); } From 4aeaf491df8c733317d0c76a9eba1e698c71ac3a Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 19 Nov 2022 16:45:00 +0100 Subject: [PATCH 12/69] Fix spelling --- src/vcpkg/commands.ci.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 913eea62be..25b8515877 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -98,7 +98,7 @@ namespace vcpkg::Commands::CI static constexpr StringLiteral OPTION_SKIPPED_CASCADE_COUNT = "x-skipped-cascade-count"; static constexpr StringLiteral OPTION_TEST_FEATURE_CORE = "test-feature-core"; static constexpr StringLiteral OPTION_TEST_FEATURES_COMBINED = "test-features-combined"; - static constexpr StringLiteral OPTION_TEST_FEATURES_SEPERATLY = "test-features-seperatly"; + static constexpr StringLiteral OPTION_TEST_FEATURES_SEPARATELY = "test-features-separately"; static constexpr StringLiteral OPTION_RUN_FEATURE_TESTS_PORTS = "run-feature-tests-for-ports"; static constexpr StringLiteral OPTION_RUN_FEATURE_TESTS_ALL_PORTS = "run-feature-tests-for-all-ports"; @@ -126,7 +126,7 @@ namespace vcpkg::Commands::CI {OPTION_XUNIT_ALL, "Report also unchanged ports to the XUnit output (internal)"}, {OPTION_RUN_FEATURE_TESTS_ALL_PORTS, "Runs the specified tests for all ports"}, {OPTION_TEST_FEATURE_CORE, "Tests the 'core' feature for every specified port"}, - {OPTION_TEST_FEATURES_SEPERATLY, "Tests every feature of a port seperatly for every specified port"}, + {OPTION_TEST_FEATURES_SEPARATELY, "Tests every feature of a port seperatly for every specified port"}, {OPTION_TEST_FEATURES_COMBINED, "Tests the combination of every feature of a port for every specified port"}, }}; @@ -383,7 +383,7 @@ namespace vcpkg::Commands::CI const auto test_feature_core = Util::Sets::contains(options.switches, OPTION_TEST_FEATURE_CORE); const auto test_features_combined = Util::Sets::contains(options.switches, OPTION_TEST_FEATURES_COMBINED); - const auto test_features_seperatly = Util::Sets::contains(options.switches, OPTION_TEST_FEATURES_SEPERATLY); + const auto test_features_seperatly = Util::Sets::contains(options.switches, OPTION_TEST_FEATURES_SEPARATELY); const auto run_tests_all_ports = Util::Sets::contains(options.switches, OPTION_RUN_FEATURE_TESTS_ALL_PORTS); const auto run_tests_ports_list = Util::Sets::contains(options.settings, OPTION_RUN_FEATURE_TESTS_PORTS); From 517e61431534eee511aca120051015c0ad2f0277 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Thu, 8 Dec 2022 18:23:00 +0100 Subject: [PATCH 13/69] Add support for a baseline file --- include/vcpkg/base/util.h | 6 ++ include/vcpkg/ci-baseline.h | 27 +++++ include/vcpkg/fwd/ci-baseline.h | 8 ++ src/vcpkg/ci-baseline.cpp | 180 ++++++++++++++++++++++++++++++++ src/vcpkg/commands.ci.cpp | 155 +++++++++++++++++++++++---- 5 files changed, 353 insertions(+), 23 deletions(-) diff --git a/include/vcpkg/base/util.h b/include/vcpkg/base/util.h index bfcf91f302..401ad55256 100644 --- a/include/vcpkg/base/util.h +++ b/include/vcpkg/base/util.h @@ -316,6 +316,12 @@ namespace vcpkg::Util return std::any_of(rng.begin(), rng.end(), std::move(pred)); } + template + bool all_of(Range&& rng, Pred pred) + { + return std::all_of(rng.begin(), rng.end(), std::move(pred)); + } + template> Range&& sort_unique_erase(Range&& cont, Comp comp = Comp()) { diff --git a/include/vcpkg/ci-baseline.h b/include/vcpkg/ci-baseline.h index 39fd0b01c1..687b5835d2 100644 --- a/include/vcpkg/ci-baseline.h +++ b/include/vcpkg/ci-baseline.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include @@ -29,6 +30,25 @@ namespace vcpkg friend bool operator!=(const CiBaselineLine& lhs, const CiBaselineLine& rhs) { return !(lhs == rhs); } }; + struct CiFeatureBaselineEntry + { + CiFeatureBaselineState state = CiFeatureBaselineState::Pass; + std::set skip_features; + std::set no_separate_feature_test; + std::set cascade_features; + std::vector> fail_configurations; + bool will_fail(const InternalFeatureSet& internal_feature_set) const; + }; + + struct CiFeatureBaseline + { + std::unordered_map ports; + const CiFeatureBaselineEntry& get_port(const std::string& port_name) const; + }; + + void to_string(std::string& out, CiFeatureBaselineState state); + std::string to_string(CiFeatureBaselineState state); + struct TripletExclusions { Triplet triplet; @@ -55,6 +75,13 @@ namespace vcpkg std::vector parse_ci_baseline(StringView text, StringView origin, ParseMessages& messages); + CiFeatureBaseline parse_ci_feature_baseline(StringView text, + StringView origin, + ParseMessages& messages, + Triplet triplet, + Triplet host_triplet, + CMakeVars::CMakeVarProvider& var_provider); + struct CiBaselineData { SortedVector expected_failures; diff --git a/include/vcpkg/fwd/ci-baseline.h b/include/vcpkg/fwd/ci-baseline.h index 79b80cad3f..89e0033fdb 100644 --- a/include/vcpkg/fwd/ci-baseline.h +++ b/include/vcpkg/fwd/ci-baseline.h @@ -4,6 +4,7 @@ namespace vcpkg { struct CiBaseline; struct CiBaselineLine; + struct CiFeatureBaseline; struct TripletExclusions; struct ExclusionsMap; struct ExclusionPredicate; @@ -14,6 +15,13 @@ namespace vcpkg Fail, Pass, }; + enum class CiFeatureBaselineState + { + Skip, + Fail, + Cascade, + Pass, + }; enum class SkipFailures : bool { No, diff --git a/src/vcpkg/ci-baseline.cpp b/src/vcpkg/ci-baseline.cpp index 324e91d2d1..6b273f0403 100644 --- a/src/vcpkg/ci-baseline.cpp +++ b/src/vcpkg/ci-baseline.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -234,4 +235,183 @@ namespace vcpkg } return {}; } + + namespace + { + bool respect_entry(const ParsedQualifiedSpecifier& entry, + Triplet triplet, + Triplet host_triplet, + CMakeVars::CMakeVarProvider& var_provider) + { + if (auto maybe_triplet = entry.triplet.get()) + { + return *maybe_triplet == triplet; + } + else if (auto maybe_platform = entry.platform.get()) + { + return maybe_platform->evaluate( + var_provider.get_or_load_dep_info_vars(PackageSpec{entry.name, triplet}, host_triplet)); + } + return true; + } + } + + CiFeatureBaseline parse_ci_feature_baseline(StringView text, + StringView origin, + ParseMessages& messages, + Triplet triplet, + Triplet host_triplet, + CMakeVars::CMakeVarProvider& var_provider) + { + CiFeatureBaseline result; + ParserBase parser(text, origin); + for (;;) + { + parser.skip_whitespace(); + if (parser.at_eof()) + { + // success + return result; + } + + if (parser.cur() == '#') + { + parser.skip_line(); + continue; + } + + // port-name = (fail|skip)\b + auto maybe_spec = parse_qualified_specifier(parser); + if (!maybe_spec) break; + auto& spec = maybe_spec.value_or_exit(VCPKG_LINE_INFO); + if (spec.platform.has_value() && spec.triplet.has_value()) + { + parser.add_error("You can not specify a platform expression and a triplet"); + break; + } + + parser.skip_tabs_spaces(); + if (parser.require_character('=')) + { + break; + } + + parser.skip_tabs_spaces(); + + static constexpr StringLiteral FAIL = "fail"; + static constexpr StringLiteral SKIP = "skip"; + static constexpr StringLiteral CASCADE = "cascade"; + static constexpr StringLiteral NO_TEST = "no-separate-feature-test"; + static constexpr CiFeatureBaselineState NO_TEST_STATE = static_cast(100); + CiFeatureBaselineState state; + if (parser.try_match_keyword(FAIL)) + { + state = CiFeatureBaselineState::Fail; + } + else if (parser.try_match_keyword(SKIP)) + { + state = CiFeatureBaselineState::Skip; + } + else if (parser.try_match_keyword(CASCADE)) + { + state = CiFeatureBaselineState::Cascade; + } + else if (parser.try_match_keyword(NO_TEST)) + { + state = NO_TEST_STATE; + } + else + { + parser.add_error(msg::format(msgExpectedFailOrSkip)); + break; + } + + parser.skip_tabs_spaces(); + auto trailing = parser.cur(); + if (trailing == '#') + { + parser.skip_line(); + } + else if (trailing == '\r' || trailing == '\n') + { + parser.skip_newline(); + } + else if (trailing != Unicode::end_of_file) + { + parser.add_error(msg::format(msgUnknownBaselineFileContent)); + break; + } + + if (respect_entry(spec, triplet, host_triplet, var_provider)) + { + if (spec.features.has_value()) + { + auto& features = *spec.features.get(); + if (state == CiFeatureBaselineState::Skip) + { + result.ports[spec.name].skip_features.insert(features.begin(), features.end()); + } + else if (state == CiFeatureBaselineState::Cascade) + { + result.ports[spec.name].cascade_features.insert(features.begin(), features.end()); + } + else if (state == CiFeatureBaselineState::Fail) + { + features.emplace_back("core"); + result.ports[spec.name].fail_configurations.push_back( + Util::sort_unique_erase(std::move(features))); + } + else if (state == NO_TEST_STATE) + { + result.ports[spec.name].no_separate_feature_test.insert(features.begin(), features.end()); + } + } + else + { + result.ports[spec.name].state = state; + } + } + } + + // failure + messages = std::move(parser).extract_messages(); + result.ports.clear(); + return result; + } + + const CiFeatureBaselineEntry& CiFeatureBaseline::get_port(const std::string& port_name) const + { + auto iter = ports.find(port_name); + if (iter != ports.end()) + { + return iter->second; + } + static CiFeatureBaselineEntry empty_entry; + return empty_entry; + } + + bool CiFeatureBaselineEntry::will_fail(const InternalFeatureSet& internal_feature_set) const + { + return Util::Vectors::contains(fail_configurations, internal_feature_set); + } + + std::string to_string(CiFeatureBaselineState state) + { + std::string s; + to_string(s, state); + return s; + } + + void to_string(std::string& out, CiFeatureBaselineState state) + { + switch (state) + { + case CiFeatureBaselineState::Fail: out += "fail"; return; + case CiFeatureBaselineState::Pass: out += "pass"; return; + case CiFeatureBaselineState::Cascade: out += "cascade"; return; + case CiFeatureBaselineState::Skip: out += "skip"; return; + } + Checks::unreachable(VCPKG_LINE_INFO); + } + } diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 25b8515877..2fce7821b0 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -42,9 +42,7 @@ namespace { CiBuildLogsRecorder(const Path& base_path_) : base_path(base_path_) { } - virtual void record_build_result(const VcpkgPaths& paths, - const PackageSpec& spec, - BuildResult result) const override + void record_build_result(const VcpkgPaths& paths, const PackageSpec& spec, BuildResult result) const override { if (result == BuildResult::SUCCEEDED) { @@ -56,7 +54,7 @@ namespace auto children = filesystem.get_regular_files_non_recursive(source_path, IgnoreErrors{}); Util::erase_remove_if(children, NotExtensionCaseInsensitive{".log"}); const auto target_path = base_path / spec.name(); - (void)filesystem.create_directory(target_path, VCPKG_LINE_INFO); + (void)filesystem.create_directories(target_path, VCPKG_LINE_INFO); if (children.empty()) { std::string message = @@ -76,7 +74,15 @@ namespace } } - private: + CiBuildLogsRecorder create_for_feature_test(const FullPackageSpec& spec, Filesystem& filesystem) const + { + static int counter = 0; + auto new_base_path = base_path / Strings::concat("feature_test_", ++counter); + filesystem.create_directory(new_base_path, VCPKG_LINE_INFO); + filesystem.write_contents(new_base_path / "tested_spec.txt", spec.to_string(), VCPKG_LINE_INFO); + return {new_base_path}; + } + Path base_path; }; } @@ -90,6 +96,7 @@ namespace vcpkg::Commands::CI static constexpr StringLiteral OPTION_XUNIT = "x-xunit"; static constexpr StringLiteral OPTION_XUNIT_ALL = "x-xunit-all"; static constexpr StringLiteral OPTION_CI_BASELINE = "ci-baseline"; + static constexpr StringLiteral OPTION_CI_FEATURE_BASELINE = "ci-feature-baseline"; static constexpr StringLiteral OPTION_ALLOW_UNEXPECTED_PASSING = "allow-unexpected-passing"; static constexpr StringLiteral OPTION_SKIP_FAILURES = "skip-failures"; static constexpr StringLiteral OPTION_RANDOMIZE = "x-randomize"; @@ -102,11 +109,13 @@ namespace vcpkg::Commands::CI static constexpr StringLiteral OPTION_RUN_FEATURE_TESTS_PORTS = "run-feature-tests-for-ports"; static constexpr StringLiteral OPTION_RUN_FEATURE_TESTS_ALL_PORTS = "run-feature-tests-for-all-ports"; - static constexpr std::array CI_SETTINGS = {{ + static constexpr std::array CI_SETTINGS = {{ {OPTION_EXCLUDE, "Comma separated list of ports to skip"}, {OPTION_HOST_EXCLUDE, "Comma separated list of ports to skip for the host triplet"}, {OPTION_XUNIT, "File to output results in XUnit format (internal)"}, {OPTION_CI_BASELINE, "Path to the ci.baseline.txt file. Used to skip ports and detect regressions."}, + {OPTION_CI_FEATURE_BASELINE, + "Path to the ci.feature.baseline.txt file. Used to skip ports and detect regressions."}, {OPTION_FAILURE_LOGS, "Directory to which failure logs will be copied"}, {OPTION_OUTPUT_HASHES, "File to output all determined package hashes"}, {OPTION_PARENT_HASHES, @@ -277,7 +286,9 @@ namespace vcpkg::Commands::CI }); } - static auto get_ports_to_test_with_features(const ParsedArguments& args, ActionPlan& action_plan) + static auto get_ports_to_test_with_features(const ParsedArguments& args, + const std::map& known_states, + ActionPlan& action_plan) { const auto all_ports = Util::Sets::contains(args.switches, OPTION_RUN_FEATURE_TESTS_ALL_PORTS); std::vector ports; @@ -291,6 +302,8 @@ namespace vcpkg::Commands::CI { for (const auto& action : action_plan.install_actions) { + auto iter = known_states.find(action.spec); + if (iter != known_states.end() && iter->second == BuildResult::EXCLUDED) continue; const auto& source_control_file = action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_control_file; @@ -482,7 +495,7 @@ namespace vcpkg::Commands::CI const auto precheck_results = binary_cache.precheck(action_plan.install_actions); auto split_specs = compute_action_statuses(ExclusionPredicate{&exclusions_map}, var_provider, precheck_results, action_plan); - + const auto feature_test_ports = get_ports_to_test_with_features(options, split_specs->known, action_plan); { std::string msg; for (size_t i = 0; i < action_plan.install_actions.size(); ++i) @@ -549,44 +562,101 @@ namespace vcpkg::Commands::CI } else { + auto feature_baseline_iter = settings.find(OPTION_CI_FEATURE_BASELINE); + CiFeatureBaseline feature_baseline; + if (feature_baseline_iter != settings.end()) + { + const auto ci_feature_baseline_file_name = feature_baseline_iter->second; + const auto ci_feature_baseline_file_contents = + paths.get_filesystem().read_contents(ci_feature_baseline_file_name, VCPKG_LINE_INFO); + ParseMessages ci_parse_messages; + feature_baseline = parse_ci_feature_baseline(ci_feature_baseline_file_contents, + ci_feature_baseline_file_name, + ci_parse_messages, + target_triplet, + host_triplet, + var_provider); + ci_parse_messages.exit_if_errors_or_warnings(ci_feature_baseline_file_name); + } + StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); // test port features std::unordered_set known_failures; - for (const auto port : get_ports_to_test_with_features(options, action_plan)) + struct UnexpectedResult + { + FullPackageSpec spec; + CiFeatureBaselineState actual_state; + Optional logs_dir; + }; + + std::vector unexpected_states; + + const auto handle_result = [&](FullPackageSpec&& spec, + CiFeatureBaselineState result, + CiFeatureBaselineEntry baseline, + Optional logs_dir = nullopt) { + bool expected_cascade = + (baseline.state == CiFeatureBaselineState::Cascade || + (spec.features.size() > 1 && Util::all_of(spec.features, [&](const auto& feature) { + return feature == "core" || Util::Sets::contains(baseline.cascade_features, feature); + }))); + bool actual_cascade = (result == CiFeatureBaselineState::Cascade); + if (actual_cascade != expected_cascade) + { + unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir}); + } + bool expected_fail = + (baseline.state == CiFeatureBaselineState::Fail || baseline.will_fail(spec.features)); + bool actual_fail = (result == CiFeatureBaselineState::Fail); + if (expected_fail != actual_fail) + { + unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir}); + } + }; + + int i = 0; + for (const auto port : feature_test_ports) { + ++i; + print2("\nTest ", i, "/", feature_test_ports.size(), " ", port->core_paragraph->name, "\n"); + const auto& baseline = feature_baseline.get_port(port->core_paragraph->name); + if (baseline.state == CiFeatureBaselineState::Skip) continue; PackageSpec package_spec(port->core_paragraph->name, target_triplet); - var_provider.load_dep_info_vars(Span(&package_spec, 1), host_triplet); - const auto dep_info_vars = var_provider.get_dep_info_vars(package_spec).value_or_exit(VCPKG_LINE_INFO); std::vector specs_to_test; - if (test_feature_core) + if (test_feature_core && !Util::Sets::contains(baseline.skip_features, "core")) { specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); } + const auto dep_info_vars = var_provider.get_or_load_dep_info_vars(package_spec, host_triplet); InternalFeatureSet all_features{{"core"}}; for (const auto& feature : port->feature_paragraphs) { - if (feature->supports_expression.evaluate(dep_info_vars)) + if (feature->supports_expression.evaluate(dep_info_vars) && + !Util::Sets::contains(baseline.skip_features, feature->name)) { all_features.push_back(feature->name); - if (test_features_seperatly) + if (test_features_seperatly && + !Util::Sets::contains(baseline.no_separate_feature_test, feature->name)) { specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); } } } + // if test_features_seperatly == true and there is only one feature test_features_combined is not needed if (test_features_combined && all_features.size() > (test_features_seperatly ? size_t{2} : size_t{1})) { specs_to_test.emplace_back(package_spec, all_features); } - for (auto& spec : specs_to_test) + for (auto&& spec : std::move(specs_to_test)) { auto install_plan = create_feature_install_plan(provider, var_provider, Span(&spec, 1), {}, {host_triplet, UnsupportedPortAction::Warn}); + if (!install_plan.warnings.empty()) { print2("Skipping testing of ", @@ -594,16 +664,22 @@ namespace vcpkg::Commands::CI " because of the following warnings: \n", Strings::join("\n", install_plan.warnings), '\n'); + handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); continue; } compute_all_abis(paths, install_plan, var_provider, status_db); - if (Util::any_of(install_plan.install_actions, [&known_failures](const auto& install_action) { - return Util::Sets::contains(known_failures, - install_action.package_abi().value_or_exit(VCPKG_LINE_INFO)); - })) + + if (auto iter = Util::find_if(install_plan.install_actions, + [&known_failures](const auto& install_action) { + return Util::Sets::contains( + known_failures, + install_action.package_abi().value_or_exit(VCPKG_LINE_INFO)); + }); + iter != install_plan.install_actions.end()) { - print2(spec, " will fail tested\n"); + print2(spec, " dependency ", iter->displayname(), " will fail => cascade\n"); + handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); continue; } @@ -611,24 +687,37 @@ namespace vcpkg::Commands::CI SetInstalled::adjust_action_plan_to_status_db(install_plan, status_db); if (install_plan.install_actions.empty()) // already installed { + handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); continue; } if (binary_cache.precheck({&install_plan.install_actions.back(), 1}).front() == CacheAvailability::available) + { + handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); continue; + } print2("Test feature ", spec, '\n'); for (auto&& action : install_plan.install_actions) { action.build_options = backcompat_prohibiting_package_options; } + Optional feature_build_logs_recorder_storage = + build_logs_recorder_storage.map([&](const CiBuildLogsRecorder& recorder) { + return recorder.create_for_feature_test(spec, filesystem); + }); + Optional logs_dir = feature_build_logs_recorder_storage.map( + [](const CiBuildLogsRecorder& recorder) { return recorder.base_path; }); + const IBuildLogsRecorder& build_logs_recorder = feature_build_logs_recorder_storage + ? *(feature_build_logs_recorder_storage.get()) + : null_build_logs_recorder(); const auto summary = Install::perform(args, install_plan, KeepGoing::YES, paths, status_db, binary_cache, - null_build_logs_recorder(), + build_logs_recorder, var_provider); binary_cache.clear_cache(); for (const auto& result : summary.results) @@ -645,15 +734,35 @@ namespace vcpkg::Commands::CI } switch (summary.results.back().build_result.value_or_exit(VCPKG_LINE_INFO).code) { + case BuildResult::DOWNLOADED: case vcpkg::BuildResult::SUCCEEDED: + handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline, logs_dir); + break; case vcpkg::BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: - print2("Feature ", spec, " works \n"); + handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline, logs_dir); + break; + case BuildResult::BUILD_FAILED: + case BuildResult::POST_BUILD_CHECKS_FAILED: + case BuildResult::FILE_CONFLICTS: + case BuildResult::CACHE_MISSING: + case BuildResult::REMOVED: + case BuildResult::EXCLUDED: + handle_result(std::move(spec), CiFeatureBaselineState::Fail, baseline, logs_dir); break; - default: print2("Feature ", spec, " failed with \n"); } } } + for (const auto& result : unexpected_states) + { + print2(result.spec, + " resulted in the unexpected state ", + result.actual_state, + " ", + result.logs_dir.value_or(""), + '\n'); + } + if (!known_failures.empty()) { // remove known failures from the action_plan.install_actions From a610bb4c3e1e15ccf5337349d368af7c241d0629 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Thu, 8 Dec 2022 18:34:17 +0100 Subject: [PATCH 14/69] Make msvc happy --- src/vcpkg/commands.ci.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 2fce7821b0..203f7ee996 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -292,8 +292,7 @@ namespace vcpkg::Commands::CI { const auto all_ports = Util::Sets::contains(args.switches, OPTION_RUN_FEATURE_TESTS_ALL_PORTS); std::vector ports; - auto iter = args.settings.find(OPTION_RUN_FEATURE_TESTS_PORTS); - if (iter != args.settings.end()) + if (auto iter = args.settings.find(OPTION_RUN_FEATURE_TESTS_PORTS); iter != args.settings.end()) { ports = Strings::split(iter->second, ','); } @@ -453,9 +452,6 @@ namespace vcpkg::Commands::CI } } - const IBuildLogsRecorder& build_logs_recorder = - build_logs_recorder_storage ? *(build_logs_recorder_storage.get()) : null_build_logs_recorder(); - PathsPortFileProvider provider(paths, make_overlay_provider(paths, paths.overlay_ports)); auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths); auto& var_provider = *var_provider_storage; @@ -791,6 +787,9 @@ namespace vcpkg::Commands::CI } SetInstalled::adjust_action_plan_to_status_db(action_plan, status_db); + const IBuildLogsRecorder& build_logs_recorder = + build_logs_recorder_storage ? *(build_logs_recorder_storage.get()) : null_build_logs_recorder(); + auto summary = Install::perform( args, action_plan, KeepGoing::YES, paths, status_db, binary_cache, build_logs_recorder, var_provider); From 781c7b1ac3a25bf96d52c132db36a9bc144f6f76 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Fri, 9 Dec 2022 20:57:37 +0100 Subject: [PATCH 15/69] Create issue template for failing ports --- include/vcpkg/install.h | 4 ++++ src/vcpkg/commands.ci.cpp | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/include/vcpkg/install.h b/include/vcpkg/install.h index 59d169539c..a920240793 100644 --- a/include/vcpkg/install.h +++ b/include/vcpkg/install.h @@ -41,6 +41,10 @@ namespace vcpkg Optional build_result; vcpkg::ElapsedTime timing; std::chrono::system_clock::time_point start_time; + Optional get_install_plan_action() const + { + return m_install_action ? Optional(*m_install_action) : nullopt; + } private: const InstallPlanAction* m_install_action; diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index c082298393..ed8e92818d 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -735,6 +735,18 @@ namespace vcpkg::Commands::CI switch (result.build_result.value_or_exit(VCPKG_LINE_INFO).code) { case BuildResult::BUILD_FAILED: + if (Path* dir = logs_dir.get()) + { + auto issue_body_path = *dir / "issue_body.md"; + paths.get_filesystem().write_contents( + issue_body_path, + create_github_issue( + args, + result.build_result.value_or_exit(VCPKG_LINE_INFO), + paths, + result.get_install_plan_action().value_or_exit(VCPKG_LINE_INFO)), + VCPKG_LINE_INFO); + } case BuildResult::POST_BUILD_CHECKS_FAILED: case BuildResult::FILE_CONFLICTS: known_failures.insert(result.get_abi().value_or_exit(VCPKG_LINE_INFO)); @@ -772,6 +784,7 @@ namespace vcpkg::Commands::CI result.logs_dir.value_or(""), '\n'); } + Checks::exit_success(VCPKG_LINE_INFO); if (!known_failures.empty()) { From 1d60a7d93ad77de5debfe781dc989f33727d0ebc Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 10 Dec 2022 11:48:15 +0100 Subject: [PATCH 16/69] Give the logs folder a better name --- src/vcpkg/commands.ci.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index ed8e92818d..26f21e5012 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -77,7 +77,20 @@ namespace CiBuildLogsRecorder create_for_feature_test(const FullPackageSpec& spec, Filesystem& filesystem) const { static int counter = 0; - auto new_base_path = base_path / Strings::concat("feature_test_", ++counter); + std::string feature; + if (spec.features.size() == 1) + { + feature = "core"; + } + else if (spec.features.size() == 2) + { + feature = spec.features.back(); + } + else + { + feature = Strings::concat("all_", ++counter); + } + auto new_base_path = base_path / Strings::concat(spec.package_spec.name(), '_', feature); filesystem.create_directory(new_base_path, VCPKG_LINE_INFO); filesystem.write_contents(new_base_path / "tested_spec.txt", spec.to_string(), VCPKG_LINE_INFO); return {new_base_path}; From 9a0c844ff900060962615e05103374729cd4f302 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Mon, 26 Dec 2022 19:15:12 +0100 Subject: [PATCH 17/69] Collect time needed to build a port --- src/vcpkg/commands.ci.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 26f21e5012..93845f1766 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -611,6 +611,7 @@ namespace vcpkg::Commands::CI FullPackageSpec spec; CiFeatureBaselineState actual_state; Optional logs_dir; + ElapsedTime build_time; }; std::vector unexpected_states; @@ -618,7 +619,8 @@ namespace vcpkg::Commands::CI const auto handle_result = [&](FullPackageSpec&& spec, CiFeatureBaselineState result, CiFeatureBaselineEntry baseline, - Optional logs_dir = nullopt) { + Optional logs_dir = nullopt, + ElapsedTime build_time = {}) { bool expected_cascade = (baseline.state == CiFeatureBaselineState::Cascade || (spec.features.size() > 1 && Util::all_of(spec.features, [&](const auto& feature) { @@ -627,14 +629,14 @@ namespace vcpkg::Commands::CI bool actual_cascade = (result == CiFeatureBaselineState::Cascade); if (actual_cascade != expected_cascade) { - unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir}); + unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir, build_time}); } bool expected_fail = (baseline.state == CiFeatureBaselineState::Fail || baseline.will_fail(spec.features)); bool actual_fail = (result == CiFeatureBaselineState::Fail); if (expected_fail != actual_fail) { - unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir}); + unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir, build_time}); } }; @@ -734,6 +736,7 @@ namespace vcpkg::Commands::CI const IBuildLogsRecorder& build_logs_recorder = feature_build_logs_recorder_storage ? *(feature_build_logs_recorder_storage.get()) : null_build_logs_recorder(); + ElapsedTimer timer; const auto summary = Install::perform(args, install_plan, KeepGoing::YES, @@ -743,6 +746,7 @@ namespace vcpkg::Commands::CI build_logs_recorder, var_provider); binary_cache.clear_cache(); + for (const auto& result : summary.results) { switch (result.build_result.value_or_exit(VCPKG_LINE_INFO).code) @@ -771,10 +775,12 @@ namespace vcpkg::Commands::CI { case BuildResult::DOWNLOADED: case vcpkg::BuildResult::SUCCEEDED: - handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline, logs_dir); + handle_result( + std::move(spec), CiFeatureBaselineState::Pass, baseline, logs_dir, timer.elapsed()); break; case vcpkg::BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: - handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline, logs_dir); + handle_result( + std::move(spec), CiFeatureBaselineState::Cascade, baseline, logs_dir, timer.elapsed()); break; case BuildResult::BUILD_FAILED: case BuildResult::POST_BUILD_CHECKS_FAILED: @@ -782,7 +788,8 @@ namespace vcpkg::Commands::CI case BuildResult::CACHE_MISSING: case BuildResult::REMOVED: case BuildResult::EXCLUDED: - handle_result(std::move(spec), CiFeatureBaselineState::Fail, baseline, logs_dir); + handle_result( + std::move(spec), CiFeatureBaselineState::Fail, baseline, logs_dir, timer.elapsed()); break; } } @@ -795,6 +802,8 @@ namespace vcpkg::Commands::CI result.actual_state, " ", result.logs_dir.value_or(""), + " after ", + result.build_time.to_string(), '\n'); } Checks::exit_success(VCPKG_LINE_INFO); From 03eb18c050254cef0cfc05c235dc3b2c16fde8d7 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sun, 15 Jan 2023 18:43:45 +0100 Subject: [PATCH 18/69] Don't include cascaded features in the "all" feature test --- src/vcpkg/commands.ci.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 93845f1766..e15d42b613 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -660,7 +660,12 @@ namespace vcpkg::Commands::CI if (feature->supports_expression.evaluate(dep_info_vars) && !Util::Sets::contains(baseline.skip_features, feature->name)) { - all_features.push_back(feature->name); + // if we expect a feature to cascade don't add it the the all features test because this test + // will them simply cascade too + if (!Util::Sets::contains(baseline.cascade_features, feature->name)) + { + all_features.push_back(feature->name); + } if (test_features_seperatly && !Util::Sets::contains(baseline.no_separate_feature_test, feature->name)) { From e801de158050d63a2e9e3e4e394655b593e187c4 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sun, 15 Jan 2023 18:46:18 +0100 Subject: [PATCH 19/69] Fix warning --- src/vcpkg/commands.ci.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index e15d42b613..e812663d16 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -769,6 +769,7 @@ namespace vcpkg::Commands::CI result.get_install_plan_action().value_or_exit(VCPKG_LINE_INFO)), VCPKG_LINE_INFO); } + [[fallthrough]]; case BuildResult::POST_BUILD_CHECKS_FAILED: case BuildResult::FILE_CONFLICTS: known_failures.insert(result.get_abi().value_or_exit(VCPKG_LINE_INFO)); From f83b66146cedf836e355f4426e30f668fd1a7317 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sun, 15 Jan 2023 20:24:38 +0100 Subject: [PATCH 20/69] Fix msvc warnings --- src/vcpkg/commands.ci.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index e812663d16..d42b065e5e 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -741,7 +741,7 @@ namespace vcpkg::Commands::CI const IBuildLogsRecorder& build_logs_recorder = feature_build_logs_recorder_storage ? *(feature_build_logs_recorder_storage.get()) : null_build_logs_recorder(); - ElapsedTimer timer; + ElapsedTimer install_timer; const auto summary = Install::perform(args, install_plan, KeepGoing::YES, @@ -777,16 +777,17 @@ namespace vcpkg::Commands::CI default: break; } } + const auto time_to_install = install_timer.elapsed(); switch (summary.results.back().build_result.value_or_exit(VCPKG_LINE_INFO).code) { case BuildResult::DOWNLOADED: case vcpkg::BuildResult::SUCCEEDED: handle_result( - std::move(spec), CiFeatureBaselineState::Pass, baseline, logs_dir, timer.elapsed()); + std::move(spec), CiFeatureBaselineState::Pass, baseline, logs_dir, time_to_install); break; case vcpkg::BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: handle_result( - std::move(spec), CiFeatureBaselineState::Cascade, baseline, logs_dir, timer.elapsed()); + std::move(spec), CiFeatureBaselineState::Cascade, baseline, logs_dir, time_to_install); break; case BuildResult::BUILD_FAILED: case BuildResult::POST_BUILD_CHECKS_FAILED: @@ -795,7 +796,7 @@ namespace vcpkg::Commands::CI case BuildResult::REMOVED: case BuildResult::EXCLUDED: handle_result( - std::move(spec), CiFeatureBaselineState::Fail, baseline, logs_dir, timer.elapsed()); + std::move(spec), CiFeatureBaselineState::Fail, baseline, logs_dir, time_to_install); break; } } From 498b36ba1dc631264096f2124fd187681a3f0031 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Fri, 27 Jan 2023 16:53:16 +0100 Subject: [PATCH 21/69] Add option to only run feature tests --- src/vcpkg/commands.ci.cpp | 50 ++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 935856c54d..c97ec4f4c2 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -121,6 +121,7 @@ namespace vcpkg::Commands::CI static constexpr StringLiteral OPTION_TEST_FEATURES_SEPARATELY = "test-features-separately"; static constexpr StringLiteral OPTION_RUN_FEATURE_TESTS_PORTS = "run-feature-tests-for-ports"; static constexpr StringLiteral OPTION_RUN_FEATURE_TESTS_ALL_PORTS = "run-feature-tests-for-all-ports"; + static constexpr StringLiteral OPTION_ONLY_RUN_FEATURE_TESTS = "only-run-feature-tests"; static constexpr std::array CI_SETTINGS = { {{OPTION_EXCLUDE, []() { return msg::format(msgCISettingsOptExclude); }}, @@ -142,27 +143,28 @@ namespace vcpkg::Commands::CI "A comma seperated list of ports for which the specified feature tests should be run"); }}}}; - static constexpr std::array CI_SWITCHES = {{ - {OPTION_DRY_RUN, []() { return msg::format(msgCISwitchOptDryRun); }}, - {OPTION_RANDOMIZE, []() { return msg::format(msgCISwitchOptRandomize); }}, - {OPTION_ALLOW_UNEXPECTED_PASSING, []() { return msg::format(msgCISwitchOptAllowUnexpectedPassing); }}, - {OPTION_SKIP_FAILURES, []() { return msg::format(msgCISwitchOptSkipFailures); }}, - {OPTION_XUNIT_ALL, []() { return msg::format(msgCISwitchOptXUnitAll); }}, - {OPTION_RUN_FEATURE_TESTS_ALL_PORTS, - []() { return LocalizedString::from_raw("Runs the specified tests for all ports"); }}, - {OPTION_TEST_FEATURE_CORE, - []() { return LocalizedString::from_raw("Tests the 'core' feature for every specified port"); }}, - {OPTION_TEST_FEATURES_SEPARATELY, - []() { - return LocalizedString::from_raw("Tests every feature of a port seperatly for every specified port"); - }}, - {OPTION_TEST_FEATURES_COMBINED, - []() { - return LocalizedString::from_raw( - "Tests the combination of every feature of a port for every specified port"); - }}, - - }}; + static constexpr std::array CI_SWITCHES = { + {{OPTION_DRY_RUN, []() { return msg::format(msgCISwitchOptDryRun); }}, + {OPTION_RANDOMIZE, []() { return msg::format(msgCISwitchOptRandomize); }}, + {OPTION_ALLOW_UNEXPECTED_PASSING, []() { return msg::format(msgCISwitchOptAllowUnexpectedPassing); }}, + {OPTION_SKIP_FAILURES, []() { return msg::format(msgCISwitchOptSkipFailures); }}, + {OPTION_XUNIT_ALL, []() { return msg::format(msgCISwitchOptXUnitAll); }}, + {OPTION_RUN_FEATURE_TESTS_ALL_PORTS, + []() { return LocalizedString::from_raw("Runs the specified tests for all ports"); }}, + {OPTION_TEST_FEATURE_CORE, + []() { return LocalizedString::from_raw("Tests the 'core' feature for every specified port"); }}, + {OPTION_TEST_FEATURES_SEPARATELY, + []() { + return LocalizedString::from_raw("Tests every feature of a port seperatly for every specified port"); + }}, + {OPTION_TEST_FEATURES_COMBINED, + []() { + return LocalizedString::from_raw( + "Tests the combination of every feature of a port for every specified port"); + }}, + {OPTION_ONLY_RUN_FEATURE_TESTS, []() { + return LocalizedString::from_raw("Only run the feature tests and not the normal ci test of all ports"); + }}}}; const CommandStructure COMMAND_STRUCTURE = { create_example_string("ci --triplet=x64-windows"), @@ -421,6 +423,7 @@ namespace vcpkg::Commands::CI const auto test_feature_core = Util::Sets::contains(options.switches, OPTION_TEST_FEATURE_CORE); const auto test_features_combined = Util::Sets::contains(options.switches, OPTION_TEST_FEATURES_COMBINED); const auto test_features_seperatly = Util::Sets::contains(options.switches, OPTION_TEST_FEATURES_SEPARATELY); + const auto only_run_feature_tests = Util::Sets::contains(options.switches, OPTION_ONLY_RUN_FEATURE_TESTS); const auto run_tests_all_ports = Util::Sets::contains(options.switches, OPTION_RUN_FEATURE_TESTS_ALL_PORTS); const auto run_tests_ports_list = Util::Sets::contains(options.settings, OPTION_RUN_FEATURE_TESTS_PORTS); @@ -813,7 +816,10 @@ namespace vcpkg::Commands::CI result.build_time.to_string(), '\n'); } - Checks::exit_success(VCPKG_LINE_INFO); + if (only_run_feature_tests) + { + Checks::exit_success(VCPKG_LINE_INFO); + } if (!known_failures.empty()) { From a3beb6e0a4e25135bdea344389a50d0f722d6269 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 14 Feb 2023 17:23:44 +0100 Subject: [PATCH 22/69] Add command test-features --- include/vcpkg/commands.test-features.h | 20 ++ src/vcpkg/commands.cpp | 3 + src/vcpkg/commands.test-features.cpp | 455 +++++++++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 include/vcpkg/commands.test-features.h create mode 100644 src/vcpkg/commands.test-features.cpp diff --git a/include/vcpkg/commands.test-features.h b/include/vcpkg/commands.test-features.h new file mode 100644 index 0000000000..3cd675815b --- /dev/null +++ b/include/vcpkg/commands.test-features.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace vcpkg::Commands::TestFeatures +{ + extern const CommandStructure COMMAND_STRUCTURE; + void perform_and_exit(const VcpkgCmdArguments& args, + const VcpkgPaths& paths, + Triplet default_triplet, + Triplet host_triplet); + + struct TestFeaturesCommand : TripletCommand + { + virtual void perform_and_exit(const VcpkgCmdArguments& args, + const VcpkgPaths& paths, + Triplet default_triplet, + Triplet host_triplet) const override; + }; +} diff --git a/src/vcpkg/commands.cpp b/src/vcpkg/commands.cpp index 9bd5f31e8e..9ae6263dea 100644 --- a/src/vcpkg/commands.cpp +++ b/src/vcpkg/commands.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -162,6 +163,7 @@ namespace vcpkg::Commands static const InstallCommand install{}; static const SetInstalled::SetInstalledCommand set_installed{}; static const CI::CICommand ci{}; + static const TestFeatures::TestFeaturesCommand test_features{}; static const Remove::RemoveCommand remove{}; static const Upgrade::UpgradeCommand upgrade{}; static const BuildCommand build{}; @@ -176,6 +178,7 @@ namespace vcpkg::Commands {"install", &install}, {"x-set-installed", &set_installed}, {"ci", &ci}, + {"test-features", &test_features}, {"remove", &remove}, {"upgrade", &upgrade}, {"build", &build}, diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp new file mode 100644 index 0000000000..b47e397aac --- /dev/null +++ b/src/vcpkg/commands.test-features.cpp @@ -0,0 +1,455 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace vcpkg; + +namespace +{ + const Path readme_dot_log = "readme.log"; + + struct CiBuildLogsRecorder final : IBuildLogsRecorder + { + CiBuildLogsRecorder(const Path& base_path_) : base_path(base_path_) { } + + void record_build_result(const VcpkgPaths& paths, const PackageSpec& spec, BuildResult result) const override + { + if (result == BuildResult::SUCCEEDED) + { + return; + } + + auto& filesystem = paths.get_filesystem(); + const auto source_path = paths.build_dir(spec); + auto children = filesystem.get_regular_files_non_recursive(source_path, IgnoreErrors{}); + Util::erase_remove_if(children, NotExtensionCaseInsensitive{".log"}); + const auto target_path = base_path / spec.name(); + (void)filesystem.create_directories(target_path, VCPKG_LINE_INFO); + if (children.empty()) + { + std::string message = + "There are no build logs for " + spec.to_string() + + " build.\n" + "This is usually because the build failed early and outside of a task that is logged.\n" + "See the console output logs from vcpkg for more information on the failure.\n"; + filesystem.write_contents(target_path / readme_dot_log, message, VCPKG_LINE_INFO); + } + else + { + for (const Path& p : children) + { + filesystem.copy_file( + p, target_path / p.filename(), CopyOptions::overwrite_existing, VCPKG_LINE_INFO); + } + } + } + + CiBuildLogsRecorder create_for_feature_test(const FullPackageSpec& spec, Filesystem& filesystem) const + { + static int counter = 0; + std::string feature; + if (spec.features.size() == 1) + { + feature = "core"; + } + else if (spec.features.size() == 2) + { + feature = spec.features.back(); + } + else + { + feature = Strings::concat("all_", ++counter); + } + auto new_base_path = base_path / Strings::concat(spec.package_spec.name(), '_', feature); + filesystem.create_directory(new_base_path, VCPKG_LINE_INFO); + filesystem.write_contents(new_base_path / "tested_spec.txt", spec.to_string(), VCPKG_LINE_INFO); + return {new_base_path}; + } + + Path base_path; + }; +} + +namespace vcpkg::Commands::TestFeatures +{ + static constexpr StringLiteral OPTION_FAILURE_LOGS = "failure-logs"; + static constexpr StringLiteral OPTION_CI_FEATURE_BASELINE = "ci-feature-baseline"; + static constexpr StringLiteral OPTION_DONT_TEST_FEATURE_CORE = "dont-test-feature-core"; + static constexpr StringLiteral OPTION_DONT_TEST_FEATURES_COMBINED = "dont-test-features-combined"; + static constexpr StringLiteral OPTION_DONT_TEST_FEATURES_SEPARATELY = "dont-test-features-separately"; + static constexpr StringLiteral OPTION_OUTPUT_FAILURE_ABIS = "write-failure-abis-to"; + static constexpr StringLiteral OPTION_ALL_PORTS = "all"; + + static constexpr std::array CI_SETTINGS = {{ + {OPTION_CI_FEATURE_BASELINE, + []() { + return LocalizedString::from_raw( + "Path to the ci.feature.baseline.txt file. Used to skip ports and detect regressions."); + }}, + {OPTION_OUTPUT_FAILURE_ABIS, + []() { + return LocalizedString::from_raw( + "Path to a file to which abis from ports that failed to build are written."); + }}, + {OPTION_FAILURE_LOGS, []() { return msg::format(msgCISettingsOptFailureLogs); }}, + }}; + + static constexpr std::array CI_SWITCHES = {{ + + {OPTION_ALL_PORTS, []() { return LocalizedString::from_raw("Runs the specified tests for all ports"); }}, + {OPTION_DONT_TEST_FEATURE_CORE, + []() { return LocalizedString::from_raw("Tests the 'core' feature for every specified port"); }}, + {OPTION_DONT_TEST_FEATURES_SEPARATELY, + []() { + return LocalizedString::from_raw("Tests every feature of a port seperatly for every specified port"); + }}, + {OPTION_DONT_TEST_FEATURES_COMBINED, + []() { + return LocalizedString::from_raw( + "Tests the combination of every feature of a port for every specified port"); + }}, + }}; + + const CommandStructure COMMAND_STRUCTURE = { + create_example_string("test-features llvm"), + 0, + SIZE_MAX, + {CI_SWITCHES, CI_SETTINGS}, + nullptr, + }; + + void perform_and_exit(const VcpkgCmdArguments& args, + const VcpkgPaths& paths, + Triplet target_triplet, + Triplet host_triplet) + { + const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); + const auto& settings = options.settings; + + const auto all_ports = Util::Sets::contains(options.switches, OPTION_ALL_PORTS); + + const auto test_feature_core = !Util::Sets::contains(options.switches, OPTION_DONT_TEST_FEATURE_CORE); + const auto test_features_combined = !Util::Sets::contains(options.switches, OPTION_DONT_TEST_FEATURES_COMBINED); + const auto test_features_seperatly = + !Util::Sets::contains(options.switches, OPTION_DONT_TEST_FEATURES_SEPARATELY); + + BinaryCache binary_cache{args, paths}; + + auto& filesystem = paths.get_filesystem(); + Optional build_logs_recorder_storage; + { + auto it_failure_logs = settings.find(OPTION_FAILURE_LOGS); + if (it_failure_logs != settings.end()) + { + msg::println(msgCreateFailureLogsDir, msg::path = it_failure_logs->second); + Path raw_path = it_failure_logs->second; + filesystem.create_directories(raw_path, VCPKG_LINE_INFO); + build_logs_recorder_storage = filesystem.almost_canonical(raw_path, VCPKG_LINE_INFO); + } + } + + auto registry_set = paths.make_registry_set(); + PathsPortFileProvider provider( + filesystem, *registry_set, make_overlay_provider(filesystem, paths.original_cwd, paths.overlay_ports)); + auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths); + auto& var_provider = *var_provider_storage; + + // const auto precheck_results = binary_cache.precheck(action_plan.install_actions); + + std::vector feature_test_ports; + if (all_ports) + { + feature_test_ports = Util::fmap(provider.load_all_control_files(), + [](auto& scfl) { return scfl->source_control_file.get(); }); + } + else + { + feature_test_ports = Util::fmap(args.command_arguments, [&](auto&& arg) { + return provider.get_control_file(arg).value_or_exit(VCPKG_LINE_INFO).source_control_file.get(); + }); + } + + auto feature_baseline_iter = settings.find(OPTION_CI_FEATURE_BASELINE); + CiFeatureBaseline feature_baseline; + if (feature_baseline_iter != settings.end()) + { + const auto ci_feature_baseline_file_name = feature_baseline_iter->second; + const auto ci_feature_baseline_file_contents = + paths.get_filesystem().read_contents(ci_feature_baseline_file_name, VCPKG_LINE_INFO); + ParseMessages ci_parse_messages; + feature_baseline = parse_ci_feature_baseline(ci_feature_baseline_file_contents, + ci_feature_baseline_file_name, + ci_parse_messages, + target_triplet, + host_triplet, + var_provider); + ci_parse_messages.exit_if_errors_or_warnings(ci_feature_baseline_file_name); + } + + StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); + + // test port features + std::unordered_set known_failures; + struct UnexpectedResult + { + FullPackageSpec spec; + CiFeatureBaselineState actual_state; + Optional logs_dir; + ElapsedTime build_time; + }; + + std::vector unexpected_states; + + const auto handle_result = [&](FullPackageSpec&& spec, + CiFeatureBaselineState result, + CiFeatureBaselineEntry baseline, + Optional logs_dir = nullopt, + ElapsedTime build_time = {}) { + bool expected_cascade = + (baseline.state == CiFeatureBaselineState::Cascade || + (spec.features.size() > 1 && Util::all_of(spec.features, [&](const auto& feature) { + return feature == "core" || Util::Sets::contains(baseline.cascade_features, feature); + }))); + bool actual_cascade = (result == CiFeatureBaselineState::Cascade); + if (actual_cascade != expected_cascade) + { + unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir, build_time}); + } + bool expected_fail = (baseline.state == CiFeatureBaselineState::Fail || baseline.will_fail(spec.features)); + bool actual_fail = (result == CiFeatureBaselineState::Fail); + if (expected_fail != actual_fail) + { + unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir, build_time}); + } + }; + + int i = 0; + for (const auto port : feature_test_ports) + { + ++i; + print2("\nTest ", i, "/", feature_test_ports.size(), " ", port->core_paragraph->name, "\n"); + const auto& baseline = feature_baseline.get_port(port->core_paragraph->name); + if (baseline.state == CiFeatureBaselineState::Skip) continue; + PackageSpec package_spec(port->core_paragraph->name, target_triplet); + std::vector specs_to_test; + if (test_feature_core && !Util::Sets::contains(baseline.skip_features, "core")) + { + specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); + } + const auto dep_info_vars = var_provider.get_or_load_dep_info_vars(package_spec, host_triplet); + if (!port->core_paragraph->supports_expression.evaluate(dep_info_vars)) + { + print2("Port is not supported on this triplet\n"); + continue; + } + InternalFeatureSet all_features{{"core"}}; + for (const auto& feature : port->feature_paragraphs) + { + if (feature->supports_expression.evaluate(dep_info_vars) && + !Util::Sets::contains(baseline.skip_features, feature->name)) + { + // if we expect a feature to cascade don't add it the the all features test because this test + // will them simply cascade too + if (!Util::Sets::contains(baseline.cascade_features, feature->name)) + { + all_features.push_back(feature->name); + } + if (test_features_seperatly && + !Util::Sets::contains(baseline.no_separate_feature_test, feature->name)) + { + specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); + } + } + } + // if test_features_seperatly == true and there is only one feature test_features_combined is not needed + if (test_features_combined && all_features.size() > (test_features_seperatly ? size_t{2} : size_t{1})) + { + specs_to_test.emplace_back(package_spec, all_features); + } + + for (auto&& spec : std::move(specs_to_test)) + { + auto install_plan = create_feature_install_plan(provider, + var_provider, + Span(&spec, 1), + {}, + {host_triplet, UnsupportedPortAction::Warn}); + + if (!install_plan.warnings.empty()) + { + print2("Skipping testing of ", + install_plan.install_actions.back().displayname(), + " because of the following warnings: \n", + Strings::join("\n", install_plan.warnings), + '\n'); + handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); + continue; + } + var_provider.load_tag_vars(install_plan, provider, host_triplet); + compute_all_abis(paths, install_plan, var_provider, status_db); + + if (auto iter = Util::find_if(install_plan.install_actions, + [&known_failures](const auto& install_action) { + return Util::Sets::contains( + known_failures, + install_action.package_abi().value_or_exit(VCPKG_LINE_INFO)); + }); + iter != install_plan.install_actions.end()) + { + print2(spec, " dependency ", iter->displayname(), " will fail => cascade\n"); + handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); + continue; + } + + // only install the absolute minimum + SetInstalled::adjust_action_plan_to_status_db(install_plan, status_db); + if (install_plan.install_actions.empty()) // already installed + { + handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); + continue; + } + + if (binary_cache.precheck({&install_plan.install_actions.back(), 1}).front() == + CacheAvailability::available) + { + handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); + continue; + } + print2("Test feature ", spec, '\n'); + for (auto&& action : install_plan.install_actions) + { + action.build_options = backcompat_prohibiting_package_options; + } + Optional feature_build_logs_recorder_storage = + build_logs_recorder_storage.map([&](const CiBuildLogsRecorder& recorder) { + return recorder.create_for_feature_test(spec, filesystem); + }); + Optional logs_dir = feature_build_logs_recorder_storage.map( + [](const CiBuildLogsRecorder& recorder) { return recorder.base_path; }); + const IBuildLogsRecorder& build_logs_recorder = feature_build_logs_recorder_storage + ? *(feature_build_logs_recorder_storage.get()) + : null_build_logs_recorder(); + ElapsedTimer install_timer; + const auto summary = Install::perform(args, + install_plan, + KeepGoing::YES, + paths, + status_db, + binary_cache, + build_logs_recorder, + var_provider); + binary_cache.clear_cache(); + + for (const auto& result : summary.results) + { + switch (result.build_result.value_or_exit(VCPKG_LINE_INFO).code) + { + case BuildResult::BUILD_FAILED: + if (Path* dir = logs_dir.get()) + { + auto issue_body_path = *dir / "issue_body.md"; + paths.get_filesystem().write_contents( + issue_body_path, + create_github_issue( + args, + result.build_result.value_or_exit(VCPKG_LINE_INFO), + paths, + result.get_install_plan_action().value_or_exit(VCPKG_LINE_INFO)), + VCPKG_LINE_INFO); + } + [[fallthrough]]; + case BuildResult::POST_BUILD_CHECKS_FAILED: + case BuildResult::FILE_CONFLICTS: + known_failures.insert(result.get_abi().value_or_exit(VCPKG_LINE_INFO)); + break; + default: break; + } + } + const auto time_to_install = install_timer.elapsed(); + switch (summary.results.back().build_result.value_or_exit(VCPKG_LINE_INFO).code) + { + case BuildResult::DOWNLOADED: + case vcpkg::BuildResult::SUCCEEDED: + handle_result( + std::move(spec), CiFeatureBaselineState::Pass, baseline, logs_dir, time_to_install); + break; + case vcpkg::BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: + handle_result( + std::move(spec), CiFeatureBaselineState::Cascade, baseline, logs_dir, time_to_install); + break; + case BuildResult::BUILD_FAILED: + case BuildResult::POST_BUILD_CHECKS_FAILED: + case BuildResult::FILE_CONFLICTS: + case BuildResult::CACHE_MISSING: + case BuildResult::REMOVED: + case BuildResult::EXCLUDED: + handle_result( + std::move(spec), CiFeatureBaselineState::Fail, baseline, logs_dir, time_to_install); + break; + } + } + } + + for (const auto& result : unexpected_states) + { + print2(Color::error, + result.spec, + " resulted in the unexpected state ", + result.actual_state, + " ", + result.logs_dir.value_or(""), + " after ", + result.build_time.to_string(), + '\n'); + } + + auto it_output_file = settings.find(OPTION_OUTPUT_FAILURE_ABIS); + if (it_output_file != settings.end()) + { + Path raw_path = it_output_file->second; + auto content = Strings::join("\n", known_failures); + content += '\n'; + filesystem.write_contents_and_dirs(raw_path, content, VCPKG_LINE_INFO); + } + + Checks::exit_success(VCPKG_LINE_INFO); + } + + void TestFeaturesCommand::perform_and_exit(const VcpkgCmdArguments& args, + const VcpkgPaths& paths, + Triplet default_triplet, + Triplet host_triplet) const + { + TestFeatures::perform_and_exit(args, paths, default_triplet, host_triplet); + } +} From ebfc50460ca61737451c4c280463626aa4bd08ab Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 14 Feb 2023 18:10:04 +0100 Subject: [PATCH 23/69] Remove feature test code from ci command. Add option to exclude known failures --- src/vcpkg/commands.ci.cpp | 423 +++++--------------------------------- 1 file changed, 46 insertions(+), 377 deletions(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index c97ec4f4c2..710322a4f7 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -74,28 +74,6 @@ namespace } } - CiBuildLogsRecorder create_for_feature_test(const FullPackageSpec& spec, Filesystem& filesystem) const - { - static int counter = 0; - std::string feature; - if (spec.features.size() == 1) - { - feature = "core"; - } - else if (spec.features.size() == 2) - { - feature = spec.features.back(); - } - else - { - feature = Strings::concat("all_", ++counter); - } - auto new_base_path = base_path / Strings::concat(spec.package_spec.name(), '_', feature); - filesystem.create_directory(new_base_path, VCPKG_LINE_INFO); - filesystem.write_contents(new_base_path / "tested_spec.txt", spec.to_string(), VCPKG_LINE_INFO); - return {new_base_path}; - } - Path base_path; }; } @@ -115,56 +93,34 @@ namespace vcpkg::Commands::CI static constexpr StringLiteral OPTION_RANDOMIZE = "x-randomize"; static constexpr StringLiteral OPTION_OUTPUT_HASHES = "output-hashes"; static constexpr StringLiteral OPTION_PARENT_HASHES = "parent-hashes"; + static constexpr StringLiteral OPTION_KNOWN_FAILURES = "known-failures-from"; static constexpr StringLiteral OPTION_SKIPPED_CASCADE_COUNT = "x-skipped-cascade-count"; - static constexpr StringLiteral OPTION_TEST_FEATURE_CORE = "test-feature-core"; - static constexpr StringLiteral OPTION_TEST_FEATURES_COMBINED = "test-features-combined"; - static constexpr StringLiteral OPTION_TEST_FEATURES_SEPARATELY = "test-features-separately"; - static constexpr StringLiteral OPTION_RUN_FEATURE_TESTS_PORTS = "run-feature-tests-for-ports"; - static constexpr StringLiteral OPTION_RUN_FEATURE_TESTS_ALL_PORTS = "run-feature-tests-for-all-ports"; - static constexpr StringLiteral OPTION_ONLY_RUN_FEATURE_TESTS = "only-run-feature-tests"; - - static constexpr std::array CI_SETTINGS = { - {{OPTION_EXCLUDE, []() { return msg::format(msgCISettingsOptExclude); }}, - {OPTION_HOST_EXCLUDE, []() { return msg::format(msgCISettingsOptHostExclude); }}, - {OPTION_XUNIT, []() { return msg::format(msgCISettingsOptXUnit); }}, - {OPTION_CI_BASELINE, []() { return msg::format(msgCISettingsOptCIBase); }}, - {OPTION_CI_FEATURE_BASELINE, - []() { - return LocalizedString::from_raw( - "Path to the ci.feature.baseline.txt file. Used to skip ports and detect regressions."); - }}, - {OPTION_FAILURE_LOGS, []() { return msg::format(msgCISettingsOptFailureLogs); }}, - {OPTION_OUTPUT_HASHES, []() { return msg::format(msgCISettingsOptOutputHashes); }}, - {OPTION_PARENT_HASHES, []() { return msg::format(msgCISettingsOptParentHashes); }}, - {OPTION_SKIPPED_CASCADE_COUNT, []() { return msg::format(msgCISettingsOptSkippedCascadeCount); }}, - - {OPTION_RUN_FEATURE_TESTS_PORTS, []() { - return LocalizedString::from_raw( - "A comma seperated list of ports for which the specified feature tests should be run"); - }}}}; - - static constexpr std::array CI_SWITCHES = { - {{OPTION_DRY_RUN, []() { return msg::format(msgCISwitchOptDryRun); }}, - {OPTION_RANDOMIZE, []() { return msg::format(msgCISwitchOptRandomize); }}, - {OPTION_ALLOW_UNEXPECTED_PASSING, []() { return msg::format(msgCISwitchOptAllowUnexpectedPassing); }}, - {OPTION_SKIP_FAILURES, []() { return msg::format(msgCISwitchOptSkipFailures); }}, - {OPTION_XUNIT_ALL, []() { return msg::format(msgCISwitchOptXUnitAll); }}, - {OPTION_RUN_FEATURE_TESTS_ALL_PORTS, - []() { return LocalizedString::from_raw("Runs the specified tests for all ports"); }}, - {OPTION_TEST_FEATURE_CORE, - []() { return LocalizedString::from_raw("Tests the 'core' feature for every specified port"); }}, - {OPTION_TEST_FEATURES_SEPARATELY, - []() { - return LocalizedString::from_raw("Tests every feature of a port seperatly for every specified port"); - }}, - {OPTION_TEST_FEATURES_COMBINED, - []() { - return LocalizedString::from_raw( - "Tests the combination of every feature of a port for every specified port"); - }}, - {OPTION_ONLY_RUN_FEATURE_TESTS, []() { - return LocalizedString::from_raw("Only run the feature tests and not the normal ci test of all ports"); - }}}}; + + static constexpr std::array CI_SETTINGS = {{ + {OPTION_EXCLUDE, []() { return msg::format(msgCISettingsOptExclude); }}, + {OPTION_HOST_EXCLUDE, []() { return msg::format(msgCISettingsOptHostExclude); }}, + {OPTION_XUNIT, []() { return msg::format(msgCISettingsOptXUnit); }}, + {OPTION_CI_BASELINE, []() { return msg::format(msgCISettingsOptCIBase); }}, + {OPTION_CI_FEATURE_BASELINE, + []() { + return LocalizedString::from_raw( + "Path to the ci.feature.baseline.txt file. Used to skip ports and detect regressions."); + }}, + {OPTION_FAILURE_LOGS, []() { return msg::format(msgCISettingsOptFailureLogs); }}, + {OPTION_OUTPUT_HASHES, []() { return msg::format(msgCISettingsOptOutputHashes); }}, + {OPTION_PARENT_HASHES, []() { return msg::format(msgCISettingsOptParentHashes); }}, + {OPTION_SKIPPED_CASCADE_COUNT, []() { return msg::format(msgCISettingsOptSkippedCascadeCount); }}, + {OPTION_KNOWN_FAILURES, + []() { return LocalizedString::from_raw("Path to the file of known package build failures"); }}, + }}; + + static constexpr std::array CI_SWITCHES = {{ + {OPTION_DRY_RUN, []() { return msg::format(msgCISwitchOptDryRun); }}, + {OPTION_RANDOMIZE, []() { return msg::format(msgCISwitchOptRandomize); }}, + {OPTION_ALLOW_UNEXPECTED_PASSING, []() { return msg::format(msgCISwitchOptAllowUnexpectedPassing); }}, + {OPTION_SKIP_FAILURES, []() { return msg::format(msgCISwitchOptSkipFailures); }}, + {OPTION_XUNIT_ALL, []() { return msg::format(msgCISwitchOptXUnitAll); }}, + }}; const CommandStructure COMMAND_STRUCTURE = { create_example_string("ci --triplet=x64-windows"), @@ -227,6 +183,7 @@ namespace vcpkg::Commands::CI ExclusionPredicate is_excluded, const CMakeVars::CMakeVarProvider& var_provider, const std::vector& precheck_results, + const std::unordered_set& known_failures, const ActionPlan& action_plan) { auto ret = std::make_unique(); @@ -257,6 +214,12 @@ namespace vcpkg::Commands::CI ret->known.emplace(p->spec, BuildResult::EXCLUDED); will_fail.emplace(p->spec); } + else if (Util::Sets::contains(known_failures, p->public_abi())) + { + ret->action_state_string.emplace_back("will fail"); + ret->known.emplace(p->spec, BuildResult::BUILD_FAILED); + will_fail.emplace(p->spec); + } else if (Util::any_of(p->package_dependencies, [&](const PackageSpec& spec) { return Util::Sets::contains(will_fail, spec); })) { @@ -313,36 +276,6 @@ namespace vcpkg::Commands::CI }); } - static auto get_ports_to_test_with_features(const ParsedArguments& args, - const std::map& known_states, - ActionPlan& action_plan) - { - const auto all_ports = Util::Sets::contains(args.switches, OPTION_RUN_FEATURE_TESTS_ALL_PORTS); - std::vector ports; - if (auto iter = args.settings.find(OPTION_RUN_FEATURE_TESTS_PORTS); iter != args.settings.end()) - { - ports = Strings::split(iter->second, ','); - } - std::vector ports_to_test; - if (all_ports || !ports.empty()) - { - for (const auto& action : action_plan.install_actions) - { - auto iter = known_states.find(action.spec); - if (iter != known_states.end() && iter->second == BuildResult::EXCLUDED) continue; - const auto& source_control_file = - action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_control_file; - - if (all_ports || Util::Vectors::contains(ports, source_control_file->core_paragraph->name)) - { - ports_to_test.push_back(action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO) - .source_control_file.get()); - } - } - } - return ports_to_test; - } - static void parse_exclusions(const std::map>& settings, StringLiteral opt, Triplet triplet, @@ -420,21 +353,6 @@ namespace vcpkg::Commands::CI const ParsedArguments options = args.parse_arguments(COMMAND_STRUCTURE); const auto& settings = options.settings; - const auto test_feature_core = Util::Sets::contains(options.switches, OPTION_TEST_FEATURE_CORE); - const auto test_features_combined = Util::Sets::contains(options.switches, OPTION_TEST_FEATURES_COMBINED); - const auto test_features_seperatly = Util::Sets::contains(options.switches, OPTION_TEST_FEATURES_SEPARATELY); - const auto only_run_feature_tests = Util::Sets::contains(options.switches, OPTION_ONLY_RUN_FEATURE_TESTS); - - const auto run_tests_all_ports = Util::Sets::contains(options.switches, OPTION_RUN_FEATURE_TESTS_ALL_PORTS); - const auto run_tests_ports_list = Util::Sets::contains(options.settings, OPTION_RUN_FEATURE_TESTS_PORTS); - { - const auto tests_selected = test_feature_core || test_features_combined || test_features_seperatly; - const auto ports_selected = run_tests_all_ports || run_tests_ports_list; - Checks::check_exit(VCPKG_LINE_INFO, - (tests_selected && ports_selected) || (!tests_selected && !ports_selected), - "You specify a flag to test features, but not which port should be checked"); - } - BinaryCache binary_cache{args, paths}; ExclusionsMap exclusions_map; @@ -463,6 +381,15 @@ namespace vcpkg::Commands::CI cidata = parse_and_apply_ci_baseline(lines, exclusions_map, skip_failures); } + std::unordered_set known_failures; + auto it_known_failures = settings.find(OPTION_KNOWN_FAILURES); + if (it_known_failures != settings.end()) + { + Path raw_path = it_known_failures->second; + auto lines = paths.get_filesystem().read_lines(raw_path).value_or_exit(VCPKG_LINE_INFO); + known_failures.insert(lines.begin(), lines.end()); + } + auto skipped_cascade_count = parse_skipped_cascade_count(settings); const auto is_dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN); @@ -519,9 +446,9 @@ namespace vcpkg::Commands::CI auto action_plan = compute_full_plan(paths, provider, var_provider, all_default_full_specs, serialize_options); const auto precheck_results = binary_cache.precheck(action_plan.install_actions); - auto split_specs = - compute_action_statuses(ExclusionPredicate{&exclusions_map}, var_provider, precheck_results, action_plan); - const auto feature_test_ports = get_ports_to_test_with_features(options, split_specs->known, action_plan); + auto split_specs = compute_action_statuses( + ExclusionPredicate{&exclusions_map}, var_provider, precheck_results, known_failures, action_plan); + { std::string msg; for (size_t i = 0; i < action_plan.install_actions.size(); ++i) @@ -588,265 +515,7 @@ namespace vcpkg::Commands::CI } else { - auto feature_baseline_iter = settings.find(OPTION_CI_FEATURE_BASELINE); - CiFeatureBaseline feature_baseline; - if (feature_baseline_iter != settings.end()) - { - const auto ci_feature_baseline_file_name = feature_baseline_iter->second; - const auto ci_feature_baseline_file_contents = - paths.get_filesystem().read_contents(ci_feature_baseline_file_name, VCPKG_LINE_INFO); - ParseMessages ci_parse_messages; - feature_baseline = parse_ci_feature_baseline(ci_feature_baseline_file_contents, - ci_feature_baseline_file_name, - ci_parse_messages, - target_triplet, - host_triplet, - var_provider); - ci_parse_messages.exit_if_errors_or_warnings(ci_feature_baseline_file_name); - } - StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); - - // test port features - std::unordered_set known_failures; - struct UnexpectedResult - { - FullPackageSpec spec; - CiFeatureBaselineState actual_state; - Optional logs_dir; - ElapsedTime build_time; - }; - - std::vector unexpected_states; - - const auto handle_result = [&](FullPackageSpec&& spec, - CiFeatureBaselineState result, - CiFeatureBaselineEntry baseline, - Optional logs_dir = nullopt, - ElapsedTime build_time = {}) { - bool expected_cascade = - (baseline.state == CiFeatureBaselineState::Cascade || - (spec.features.size() > 1 && Util::all_of(spec.features, [&](const auto& feature) { - return feature == "core" || Util::Sets::contains(baseline.cascade_features, feature); - }))); - bool actual_cascade = (result == CiFeatureBaselineState::Cascade); - if (actual_cascade != expected_cascade) - { - unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir, build_time}); - } - bool expected_fail = - (baseline.state == CiFeatureBaselineState::Fail || baseline.will_fail(spec.features)); - bool actual_fail = (result == CiFeatureBaselineState::Fail); - if (expected_fail != actual_fail) - { - unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir, build_time}); - } - }; - - int i = 0; - for (const auto port : feature_test_ports) - { - ++i; - print2("\nTest ", i, "/", feature_test_ports.size(), " ", port->core_paragraph->name, "\n"); - const auto& baseline = feature_baseline.get_port(port->core_paragraph->name); - if (baseline.state == CiFeatureBaselineState::Skip) continue; - PackageSpec package_spec(port->core_paragraph->name, target_triplet); - std::vector specs_to_test; - if (test_feature_core && !Util::Sets::contains(baseline.skip_features, "core")) - { - specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); - } - const auto dep_info_vars = var_provider.get_or_load_dep_info_vars(package_spec, host_triplet); - InternalFeatureSet all_features{{"core"}}; - for (const auto& feature : port->feature_paragraphs) - { - if (feature->supports_expression.evaluate(dep_info_vars) && - !Util::Sets::contains(baseline.skip_features, feature->name)) - { - // if we expect a feature to cascade don't add it the the all features test because this test - // will them simply cascade too - if (!Util::Sets::contains(baseline.cascade_features, feature->name)) - { - all_features.push_back(feature->name); - } - if (test_features_seperatly && - !Util::Sets::contains(baseline.no_separate_feature_test, feature->name)) - { - specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); - } - } - } - // if test_features_seperatly == true and there is only one feature test_features_combined is not needed - if (test_features_combined && all_features.size() > (test_features_seperatly ? size_t{2} : size_t{1})) - { - specs_to_test.emplace_back(package_spec, all_features); - } - - for (auto&& spec : std::move(specs_to_test)) - { - auto install_plan = create_feature_install_plan(provider, - var_provider, - Span(&spec, 1), - {}, - {host_triplet, UnsupportedPortAction::Warn}); - - if (!install_plan.warnings.empty()) - { - print2("Skipping testing of ", - install_plan.install_actions.back().displayname(), - " because of the following warnings: \n", - Strings::join("\n", install_plan.warnings), - '\n'); - handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); - continue; - } - - compute_all_abis(paths, install_plan, var_provider, status_db); - - if (auto iter = Util::find_if(install_plan.install_actions, - [&known_failures](const auto& install_action) { - return Util::Sets::contains( - known_failures, - install_action.package_abi().value_or_exit(VCPKG_LINE_INFO)); - }); - iter != install_plan.install_actions.end()) - { - print2(spec, " dependency ", iter->displayname(), " will fail => cascade\n"); - handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); - continue; - } - - // only install the absolute minimum - SetInstalled::adjust_action_plan_to_status_db(install_plan, status_db); - if (install_plan.install_actions.empty()) // already installed - { - handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); - continue; - } - - if (binary_cache.precheck({&install_plan.install_actions.back(), 1}).front() == - CacheAvailability::available) - { - handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); - continue; - } - print2("Test feature ", spec, '\n'); - for (auto&& action : install_plan.install_actions) - { - action.build_options = backcompat_prohibiting_package_options; - } - Optional feature_build_logs_recorder_storage = - build_logs_recorder_storage.map([&](const CiBuildLogsRecorder& recorder) { - return recorder.create_for_feature_test(spec, filesystem); - }); - Optional logs_dir = feature_build_logs_recorder_storage.map( - [](const CiBuildLogsRecorder& recorder) { return recorder.base_path; }); - const IBuildLogsRecorder& build_logs_recorder = feature_build_logs_recorder_storage - ? *(feature_build_logs_recorder_storage.get()) - : null_build_logs_recorder(); - ElapsedTimer install_timer; - const auto summary = Install::perform(args, - install_plan, - KeepGoing::YES, - paths, - status_db, - binary_cache, - build_logs_recorder, - var_provider); - binary_cache.clear_cache(); - - for (const auto& result : summary.results) - { - switch (result.build_result.value_or_exit(VCPKG_LINE_INFO).code) - { - case BuildResult::BUILD_FAILED: - if (Path* dir = logs_dir.get()) - { - auto issue_body_path = *dir / "issue_body.md"; - paths.get_filesystem().write_contents( - issue_body_path, - create_github_issue( - args, - result.build_result.value_or_exit(VCPKG_LINE_INFO), - paths, - result.get_install_plan_action().value_or_exit(VCPKG_LINE_INFO)), - VCPKG_LINE_INFO); - } - [[fallthrough]]; - case BuildResult::POST_BUILD_CHECKS_FAILED: - case BuildResult::FILE_CONFLICTS: - known_failures.insert(result.get_abi().value_or_exit(VCPKG_LINE_INFO)); - break; - default: break; - } - } - const auto time_to_install = install_timer.elapsed(); - switch (summary.results.back().build_result.value_or_exit(VCPKG_LINE_INFO).code) - { - case BuildResult::DOWNLOADED: - case vcpkg::BuildResult::SUCCEEDED: - handle_result( - std::move(spec), CiFeatureBaselineState::Pass, baseline, logs_dir, time_to_install); - break; - case vcpkg::BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: - handle_result( - std::move(spec), CiFeatureBaselineState::Cascade, baseline, logs_dir, time_to_install); - break; - case BuildResult::BUILD_FAILED: - case BuildResult::POST_BUILD_CHECKS_FAILED: - case BuildResult::FILE_CONFLICTS: - case BuildResult::CACHE_MISSING: - case BuildResult::REMOVED: - case BuildResult::EXCLUDED: - handle_result( - std::move(spec), CiFeatureBaselineState::Fail, baseline, logs_dir, time_to_install); - break; - } - } - } - - for (const auto& result : unexpected_states) - { - print2(result.spec, - " resulted in the unexpected state ", - result.actual_state, - " ", - result.logs_dir.value_or(""), - " after ", - result.build_time.to_string(), - '\n'); - } - if (only_run_feature_tests) - { - Checks::exit_success(VCPKG_LINE_INFO); - } - - if (!known_failures.empty()) - { - // remove known failures from the action_plan.install_actions - std::set known_failure_specs; - for (const auto& install_action : action_plan.install_actions) - { - if (Util::Sets::contains(known_failures, - install_action.package_abi().value_or_exit(VCPKG_LINE_INFO))) - { - split_specs->known.emplace(install_action.spec, BuildResult::BUILD_FAILED); - known_failure_specs.emplace(install_action.spec); - } - else if (Util::any_of(install_action.package_dependencies, [&](const PackageSpec& spec) { - return Util::Sets::contains(known_failure_specs, spec); - })) - { - split_specs->known.emplace(install_action.spec, - BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES); - known_failure_specs.emplace(install_action.spec); - } - } - Util::erase_remove_if(action_plan.install_actions, - [&known_failure_specs](const InstallPlanAction& action) { - return Util::Sets::contains(known_failure_specs, action.spec); - }); - } SetInstalled::adjust_action_plan_to_status_db(action_plan, status_db); const IBuildLogsRecorder& build_logs_recorder = From dcdef4a96e30ef1cdd7e576fa6f9c6ed93471e61 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 14 Feb 2023 18:12:11 +0100 Subject: [PATCH 24/69] Remove leftover setting --- src/vcpkg/commands.ci.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 710322a4f7..7e008e3629 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -87,7 +87,6 @@ namespace vcpkg::Commands::CI static constexpr StringLiteral OPTION_XUNIT = "x-xunit"; static constexpr StringLiteral OPTION_XUNIT_ALL = "x-xunit-all"; static constexpr StringLiteral OPTION_CI_BASELINE = "ci-baseline"; - static constexpr StringLiteral OPTION_CI_FEATURE_BASELINE = "ci-feature-baseline"; static constexpr StringLiteral OPTION_ALLOW_UNEXPECTED_PASSING = "allow-unexpected-passing"; static constexpr StringLiteral OPTION_SKIP_FAILURES = "skip-failures"; static constexpr StringLiteral OPTION_RANDOMIZE = "x-randomize"; @@ -96,16 +95,11 @@ namespace vcpkg::Commands::CI static constexpr StringLiteral OPTION_KNOWN_FAILURES = "known-failures-from"; static constexpr StringLiteral OPTION_SKIPPED_CASCADE_COUNT = "x-skipped-cascade-count"; - static constexpr std::array CI_SETTINGS = {{ + static constexpr std::array CI_SETTINGS = {{ {OPTION_EXCLUDE, []() { return msg::format(msgCISettingsOptExclude); }}, {OPTION_HOST_EXCLUDE, []() { return msg::format(msgCISettingsOptHostExclude); }}, {OPTION_XUNIT, []() { return msg::format(msgCISettingsOptXUnit); }}, {OPTION_CI_BASELINE, []() { return msg::format(msgCISettingsOptCIBase); }}, - {OPTION_CI_FEATURE_BASELINE, - []() { - return LocalizedString::from_raw( - "Path to the ci.feature.baseline.txt file. Used to skip ports and detect regressions."); - }}, {OPTION_FAILURE_LOGS, []() { return msg::format(msgCISettingsOptFailureLogs); }}, {OPTION_OUTPUT_HASHES, []() { return msg::format(msgCISettingsOptOutputHashes); }}, {OPTION_PARENT_HASHES, []() { return msg::format(msgCISettingsOptParentHashes); }}, From d2edb008308e32166173b8fb697c745d0751d0f1 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 14 Feb 2023 18:20:01 +0100 Subject: [PATCH 25/69] No print2 anymore --- src/vcpkg/commands.test-features.cpp | 50 +++++++++++++++++----------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index b47e397aac..e849406fcb 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -257,7 +256,9 @@ namespace vcpkg::Commands::TestFeatures for (const auto port : feature_test_ports) { ++i; - print2("\nTest ", i, "/", feature_test_ports.size(), " ", port->core_paragraph->name, "\n"); + msg::write_unlocalized_text_to_stdout( + Color::none, + Strings::concat("\nTest ", i, "/", feature_test_ports.size(), " ", port->core_paragraph->name, "\n")); const auto& baseline = feature_baseline.get_port(port->core_paragraph->name); if (baseline.state == CiFeatureBaselineState::Skip) continue; PackageSpec package_spec(port->core_paragraph->name, target_triplet); @@ -269,7 +270,7 @@ namespace vcpkg::Commands::TestFeatures const auto dep_info_vars = var_provider.get_or_load_dep_info_vars(package_spec, host_triplet); if (!port->core_paragraph->supports_expression.evaluate(dep_info_vars)) { - print2("Port is not supported on this triplet\n"); + msg::write_unlocalized_text_to_stdout(Color::none, "Port is not supported on this triplet\n"); continue; } InternalFeatureSet all_features{{"core"}}; @@ -305,13 +306,20 @@ namespace vcpkg::Commands::TestFeatures {}, {host_triplet, UnsupportedPortAction::Warn}); - if (!install_plan.warnings.empty()) + if (!install_plan.unsupported_features.empty()) { - print2("Skipping testing of ", - install_plan.install_actions.back().displayname(), - " because of the following warnings: \n", - Strings::join("\n", install_plan.warnings), - '\n'); + std::string out; + for (const auto& entry : install_plan.unsupported_features) + { + Strings::append(out, entry.first, " only supported on ", to_string(entry.second), '\n'); + } + msg::write_unlocalized_text_to_stdout( + Color::none, + Strings::concat("Skipping testing of ", + install_plan.install_actions.back().displayname(), + " because of the following warnings: \n", + out, + '\n')); handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); continue; } @@ -326,7 +334,9 @@ namespace vcpkg::Commands::TestFeatures }); iter != install_plan.install_actions.end()) { - print2(spec, " dependency ", iter->displayname(), " will fail => cascade\n"); + msg::write_unlocalized_text_to_stdout( + Color::none, + Strings::concat(spec, " dependency ", iter->displayname(), " will fail => cascade\n")); handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); continue; } @@ -345,7 +355,7 @@ namespace vcpkg::Commands::TestFeatures handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); continue; } - print2("Test feature ", spec, '\n'); + msg::write_unlocalized_text_to_stdout(Color::none, Strings::concat("Test feature ", spec, '\n')); for (auto&& action : install_plan.install_actions) { action.build_options = backcompat_prohibiting_package_options; @@ -422,15 +432,15 @@ namespace vcpkg::Commands::TestFeatures for (const auto& result : unexpected_states) { - print2(Color::error, - result.spec, - " resulted in the unexpected state ", - result.actual_state, - " ", - result.logs_dir.value_or(""), - " after ", - result.build_time.to_string(), - '\n'); + msg::write_unlocalized_text_to_stderr(Color::error, + Strings::concat(result.spec, + " resulted in the unexpected state ", + result.actual_state, + " ", + result.logs_dir.value_or(""), + " after ", + result.build_time.to_string(), + '\n')); } auto it_output_file = settings.find(OPTION_OUTPUT_FAILURE_ABIS); From e399b2d765988c04c4773df40df351961eb5eeef Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 28 Feb 2023 11:29:06 +0100 Subject: [PATCH 26/69] Fix build --- include/vcpkg/base/messages.h | 4 ++++ locales/messages.json | 1 + src/vcpkg/base/messages.cpp | 1 + src/vcpkg/ci-baseline.cpp | 2 +- src/vcpkg/commands.test-features.cpp | 4 +--- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/vcpkg/base/messages.h b/include/vcpkg/base/messages.h index 933b7996b7..821f9ffc3f 100644 --- a/include/vcpkg/base/messages.h +++ b/include/vcpkg/base/messages.h @@ -698,6 +698,10 @@ namespace vcpkg "", "The baseline.json from commit `\"{commit_sha}\"` in the repo {url} was invalid (did not " "contain a \"default\" field)."); + DECLARE_MESSAGE(BaselineOnlyPlatformExpressionOrTriplet, + (), + "", + "You can not specify a platform expression and a triplet"); DECLARE_MESSAGE(BinarySourcesArg, (), "", "Add sources for binary caching. See 'vcpkg help binarycaching'."); DECLARE_MESSAGE(BinaryWithInvalidArchitecture, (msg::path, msg::expected, msg::actual), diff --git a/locales/messages.json b/locales/messages.json index 7d89d9ca91..76acbf030b 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -164,6 +164,7 @@ "_BaselineMissing.comment": "An example of {package_name} is zlib. An example of {version} is 1.3.8.", "BaselineMissingDefault": "The baseline.json from commit `\"{commit_sha}\"` in the repo {url} was invalid (did not contain a \"default\" field).", "_BaselineMissingDefault.comment": "An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949. An example of {url} is https://github.com/microsoft/vcpkg.", + "BaselineOnlyPlatformExpressionOrTriplet": "You can not specify a platform expression and a triplet", "BinarySourcesArg": "Add sources for binary caching. See 'vcpkg help binarycaching'.", "BinaryWithInvalidArchitecture": "{path}\n Expected: {expected}, but was {actual}", "_BinaryWithInvalidArchitecture.comment": "{expected} and {actual} are architectures An example of {path} is /foo/bar.", diff --git a/src/vcpkg/base/messages.cpp b/src/vcpkg/base/messages.cpp index c0d07350b8..3fb45caa9e 100644 --- a/src/vcpkg/base/messages.cpp +++ b/src/vcpkg/base/messages.cpp @@ -611,6 +611,7 @@ namespace vcpkg REGISTER_MESSAGE(BaselineGitShowFailed); REGISTER_MESSAGE(BaselineMissing); REGISTER_MESSAGE(BaselineMissingDefault); + REGISTER_MESSAGE(BaselineOnlyPlatformExpressionOrTriplet); REGISTER_MESSAGE(AvailableArchitectureTriplets); REGISTER_MESSAGE(AvailableHelpTopics); REGISTER_MESSAGE(AVcpkgRepositoryCommit); diff --git a/src/vcpkg/ci-baseline.cpp b/src/vcpkg/ci-baseline.cpp index 6b273f0403..1c2a92aa67 100644 --- a/src/vcpkg/ci-baseline.cpp +++ b/src/vcpkg/ci-baseline.cpp @@ -286,7 +286,7 @@ namespace vcpkg auto& spec = maybe_spec.value_or_exit(VCPKG_LINE_INFO); if (spec.platform.has_value() && spec.triplet.has_value()) { - parser.add_error("You can not specify a platform expression and a triplet"); + parser.add_error(msg::format(msgBaselineOnlyPlatformExpressionOrTriplet)); break; } diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index e849406fcb..60f812f2f8 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -29,8 +29,6 @@ #include #include -#include - using namespace vcpkg; namespace @@ -140,7 +138,7 @@ namespace vcpkg::Commands::TestFeatures }}; const CommandStructure COMMAND_STRUCTURE = { - create_example_string("test-features llvm"), + []() { return create_example_string("test-features llvm"); }, 0, SIZE_MAX, {CI_SWITCHES, CI_SETTINGS}, From 1b2519a791d4aff807efadd97cf4712c6acbcda4 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Thu, 16 Mar 2023 11:56:51 +0100 Subject: [PATCH 27/69] Fix build --- src/vcpkg/commands.test-features.cpp | 6 ++---- src/vcpkg/packagespec.cpp | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 60f812f2f8..f9c6ad3dd3 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -191,7 +191,7 @@ namespace vcpkg::Commands::TestFeatures } else { - feature_test_ports = Util::fmap(args.command_arguments, [&](auto&& arg) { + feature_test_ports = Util::fmap(args.forwardable_arguments, [&](auto&& arg) { return provider.get_control_file(arg).value_or_exit(VCPKG_LINE_INFO).source_control_file.get(); }); } @@ -254,9 +254,7 @@ namespace vcpkg::Commands::TestFeatures for (const auto port : feature_test_ports) { ++i; - msg::write_unlocalized_text_to_stdout( - Color::none, - Strings::concat("\nTest ", i, "/", feature_test_ports.size(), " ", port->core_paragraph->name, "\n")); + fmt::print("\n{}/{} {}\n", i, feature_test_ports.size(), port->core_paragraph->name); const auto& baseline = feature_baseline.get_port(port->core_paragraph->name); if (baseline.state == CiFeatureBaselineState::Skip) continue; PackageSpec package_spec(port->core_paragraph->name, target_triplet); diff --git a/src/vcpkg/packagespec.cpp b/src/vcpkg/packagespec.cpp index 91a5398ced..cb66442639 100644 --- a/src/vcpkg/packagespec.cpp +++ b/src/vcpkg/packagespec.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include From 4cdc14c8fdc7b451120b230515dc65af7afa3cf3 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Mon, 20 Mar 2023 14:42:46 +0100 Subject: [PATCH 28/69] Make sure all dependencies are tested before a FullPackageSpec is tested --- src/vcpkg/commands.test-features.cpp | 314 ++++++++++++++------------- 1 file changed, 158 insertions(+), 156 deletions(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index f9c6ad3dd3..f016445780 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -181,8 +181,6 @@ namespace vcpkg::Commands::TestFeatures auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths); auto& var_provider = *var_provider_storage; - // const auto precheck_results = binary_cache.precheck(action_plan.install_actions); - std::vector feature_test_ports; if (all_ports) { @@ -213,6 +211,67 @@ namespace vcpkg::Commands::TestFeatures ci_parse_messages.exit_if_errors_or_warnings(ci_feature_baseline_file_name); } + // to reduce number of cmake invocations + auto all_specs = Util::fmap(feature_test_ports, + [&](auto scf) { return PackageSpec(scf->core_paragraph->name, target_triplet); }); + var_provider.load_dep_info_vars(all_specs, host_triplet); + + // check what should be tested + std::vector specs_to_test; + for (const auto port : feature_test_ports) + { + const auto& baseline = feature_baseline.get_port(port->core_paragraph->name); + if (baseline.state == CiFeatureBaselineState::Skip) continue; + PackageSpec package_spec(port->core_paragraph->name, target_triplet); + if (test_feature_core && !Util::Sets::contains(baseline.skip_features, "core")) + { + specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); + } + const auto dep_info_vars = var_provider.get_or_load_dep_info_vars(package_spec, host_triplet); + if (!port->core_paragraph->supports_expression.evaluate(dep_info_vars)) + { + fmt::print("Port {} is not supported on {}\n", port->core_paragraph->name, target_triplet); + continue; + } + InternalFeatureSet all_features{{"core"}}; + for (const auto& feature : port->feature_paragraphs) + { + if (feature->supports_expression.evaluate(dep_info_vars) && + !Util::Sets::contains(baseline.skip_features, feature->name)) + { + // if we expect a feature to cascade don't add it the the all features test because this test + // will them simply cascade too + if (!Util::Sets::contains(baseline.cascade_features, feature->name)) + { + all_features.push_back(feature->name); + } + if (test_features_seperatly && + !Util::Sets::contains(baseline.no_separate_feature_test, feature->name)) + { + specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); + } + } + } + // if test_features_seperatly == true and there is only one feature test_features_combined is not needed + if (test_features_combined && all_features.size() > (test_features_seperatly ? size_t{2} : size_t{1})) + { + specs_to_test.emplace_back(package_spec, all_features); + } + } + fmt::print("compute {} install plans\n", specs_to_test.size()); + auto install_plans = Util::fmap(specs_to_test, [&](auto& spec) { + return std::make_pair(spec, + create_feature_install_plan(provider, + var_provider, + Span(&spec, 1), + {}, + {host_triplet, UnsupportedPortAction::Warn})); + }); + + Util::sort(install_plans, [](const auto& left, const auto& right) { + return left.second.install_actions.size() < right.second.install_actions.size(); + }); + StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); // test port features @@ -251,179 +310,122 @@ namespace vcpkg::Commands::TestFeatures }; int i = 0; - for (const auto port : feature_test_ports) + for (auto&& [spec, install_plan] : std::move(install_plans)) { ++i; - fmt::print("\n{}/{} {}\n", i, feature_test_ports.size(), port->core_paragraph->name); - const auto& baseline = feature_baseline.get_port(port->core_paragraph->name); - if (baseline.state == CiFeatureBaselineState::Skip) continue; - PackageSpec package_spec(port->core_paragraph->name, target_triplet); - std::vector specs_to_test; - if (test_feature_core && !Util::Sets::contains(baseline.skip_features, "core")) + fmt::print("\n{}/{} {}\n", i, install_plans.size(), spec.to_string()); + const auto& baseline = feature_baseline.get_port(spec.package_spec.name()); + + if (!install_plan.unsupported_features.empty()) { - specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); + std::string out; + for (const auto& entry : install_plan.unsupported_features) + { + Strings::append(out, entry.first, " only supported on ", to_string(entry.second), '\n'); + } + msg::write_unlocalized_text_to_stdout(Color::none, + Strings::concat("Skipping testing of ", + install_plan.install_actions.back().displayname(), + " because of the following warnings: \n", + out, + '\n')); + handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); + continue; } - const auto dep_info_vars = var_provider.get_or_load_dep_info_vars(package_spec, host_triplet); - if (!port->core_paragraph->supports_expression.evaluate(dep_info_vars)) + var_provider.load_tag_vars(install_plan, provider, host_triplet); + compute_all_abis(paths, install_plan, var_provider, status_db); + + if (auto iter = Util::find_if(install_plan.install_actions, + [&known_failures](const auto& install_action) { + return Util::Sets::contains( + known_failures, + install_action.package_abi().value_or_exit(VCPKG_LINE_INFO)); + }); + iter != install_plan.install_actions.end()) { - msg::write_unlocalized_text_to_stdout(Color::none, "Port is not supported on this triplet\n"); + msg::write_unlocalized_text_to_stdout( + Color::none, Strings::concat(spec, " dependency ", iter->displayname(), " will fail => cascade\n")); + handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); continue; } - InternalFeatureSet all_features{{"core"}}; - for (const auto& feature : port->feature_paragraphs) + + // only install the absolute minimum + SetInstalled::adjust_action_plan_to_status_db(install_plan, status_db); + if (install_plan.install_actions.empty()) // already installed { - if (feature->supports_expression.evaluate(dep_info_vars) && - !Util::Sets::contains(baseline.skip_features, feature->name)) - { - // if we expect a feature to cascade don't add it the the all features test because this test - // will them simply cascade too - if (!Util::Sets::contains(baseline.cascade_features, feature->name)) - { - all_features.push_back(feature->name); - } - if (test_features_seperatly && - !Util::Sets::contains(baseline.no_separate_feature_test, feature->name)) - { - specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); - } - } + handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); + continue; } - // if test_features_seperatly == true and there is only one feature test_features_combined is not needed - if (test_features_combined && all_features.size() > (test_features_seperatly ? size_t{2} : size_t{1})) + + if (binary_cache.precheck({&install_plan.install_actions.back(), 1}).front() == + CacheAvailability::available) { - specs_to_test.emplace_back(package_spec, all_features); + handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); + continue; } - - for (auto&& spec : std::move(specs_to_test)) + msg::write_unlocalized_text_to_stdout(Color::none, Strings::concat("Test feature ", spec, '\n')); + for (auto&& action : install_plan.install_actions) { - auto install_plan = create_feature_install_plan(provider, - var_provider, - Span(&spec, 1), - {}, - {host_triplet, UnsupportedPortAction::Warn}); - - if (!install_plan.unsupported_features.empty()) - { - std::string out; - for (const auto& entry : install_plan.unsupported_features) - { - Strings::append(out, entry.first, " only supported on ", to_string(entry.second), '\n'); - } - msg::write_unlocalized_text_to_stdout( - Color::none, - Strings::concat("Skipping testing of ", - install_plan.install_actions.back().displayname(), - " because of the following warnings: \n", - out, - '\n')); - handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); - continue; - } - var_provider.load_tag_vars(install_plan, provider, host_triplet); - compute_all_abis(paths, install_plan, var_provider, status_db); - - if (auto iter = Util::find_if(install_plan.install_actions, - [&known_failures](const auto& install_action) { - return Util::Sets::contains( - known_failures, - install_action.package_abi().value_or_exit(VCPKG_LINE_INFO)); - }); - iter != install_plan.install_actions.end()) - { - msg::write_unlocalized_text_to_stdout( - Color::none, - Strings::concat(spec, " dependency ", iter->displayname(), " will fail => cascade\n")); - handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); - continue; - } - - // only install the absolute minimum - SetInstalled::adjust_action_plan_to_status_db(install_plan, status_db); - if (install_plan.install_actions.empty()) // already installed - { - handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); - continue; - } - - if (binary_cache.precheck({&install_plan.install_actions.back(), 1}).front() == - CacheAvailability::available) - { - handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); - continue; - } - msg::write_unlocalized_text_to_stdout(Color::none, Strings::concat("Test feature ", spec, '\n')); - for (auto&& action : install_plan.install_actions) - { - action.build_options = backcompat_prohibiting_package_options; - } - Optional feature_build_logs_recorder_storage = - build_logs_recorder_storage.map([&](const CiBuildLogsRecorder& recorder) { - return recorder.create_for_feature_test(spec, filesystem); - }); - Optional logs_dir = feature_build_logs_recorder_storage.map( - [](const CiBuildLogsRecorder& recorder) { return recorder.base_path; }); - const IBuildLogsRecorder& build_logs_recorder = feature_build_logs_recorder_storage - ? *(feature_build_logs_recorder_storage.get()) - : null_build_logs_recorder(); - ElapsedTimer install_timer; - const auto summary = Install::perform(args, - install_plan, - KeepGoing::YES, - paths, - status_db, - binary_cache, - build_logs_recorder, - var_provider); - binary_cache.clear_cache(); - - for (const auto& result : summary.results) - { - switch (result.build_result.value_or_exit(VCPKG_LINE_INFO).code) - { - case BuildResult::BUILD_FAILED: - if (Path* dir = logs_dir.get()) - { - auto issue_body_path = *dir / "issue_body.md"; - paths.get_filesystem().write_contents( - issue_body_path, - create_github_issue( - args, - result.build_result.value_or_exit(VCPKG_LINE_INFO), - paths, - result.get_install_plan_action().value_or_exit(VCPKG_LINE_INFO)), - VCPKG_LINE_INFO); - } - [[fallthrough]]; - case BuildResult::POST_BUILD_CHECKS_FAILED: - case BuildResult::FILE_CONFLICTS: - known_failures.insert(result.get_abi().value_or_exit(VCPKG_LINE_INFO)); - break; - default: break; - } - } - const auto time_to_install = install_timer.elapsed(); - switch (summary.results.back().build_result.value_or_exit(VCPKG_LINE_INFO).code) + action.build_options = backcompat_prohibiting_package_options; + } + Optional feature_build_logs_recorder_storage = + build_logs_recorder_storage.map([&, &spec = spec](const CiBuildLogsRecorder& recorder) { + return recorder.create_for_feature_test(spec, filesystem); + }); + Optional logs_dir = feature_build_logs_recorder_storage.map( + [](const CiBuildLogsRecorder& recorder) { return recorder.base_path; }); + const IBuildLogsRecorder& build_logs_recorder = feature_build_logs_recorder_storage + ? *(feature_build_logs_recorder_storage.get()) + : null_build_logs_recorder(); + ElapsedTimer install_timer; + const auto summary = Install::perform( + args, install_plan, KeepGoing::YES, paths, status_db, binary_cache, build_logs_recorder, var_provider); + binary_cache.clear_cache(); + + for (const auto& result : summary.results) + { + switch (result.build_result.value_or_exit(VCPKG_LINE_INFO).code) { - case BuildResult::DOWNLOADED: - case vcpkg::BuildResult::SUCCEEDED: - handle_result( - std::move(spec), CiFeatureBaselineState::Pass, baseline, logs_dir, time_to_install); - break; - case vcpkg::BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: - handle_result( - std::move(spec), CiFeatureBaselineState::Cascade, baseline, logs_dir, time_to_install); - break; case BuildResult::BUILD_FAILED: + if (Path* dir = logs_dir.get()) + { + auto issue_body_path = *dir / "issue_body.md"; + paths.get_filesystem().write_contents( + issue_body_path, + create_github_issue(args, + result.build_result.value_or_exit(VCPKG_LINE_INFO), + paths, + result.get_install_plan_action().value_or_exit(VCPKG_LINE_INFO)), + VCPKG_LINE_INFO); + } + [[fallthrough]]; case BuildResult::POST_BUILD_CHECKS_FAILED: case BuildResult::FILE_CONFLICTS: - case BuildResult::CACHE_MISSING: - case BuildResult::REMOVED: - case BuildResult::EXCLUDED: - handle_result( - std::move(spec), CiFeatureBaselineState::Fail, baseline, logs_dir, time_to_install); + known_failures.insert(result.get_abi().value_or_exit(VCPKG_LINE_INFO)); break; + default: break; } } + const auto time_to_install = install_timer.elapsed(); + switch (summary.results.back().build_result.value_or_exit(VCPKG_LINE_INFO).code) + { + case BuildResult::DOWNLOADED: + case vcpkg::BuildResult::SUCCEEDED: + handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline, logs_dir, time_to_install); + break; + case vcpkg::BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: + handle_result( + std::move(spec), CiFeatureBaselineState::Cascade, baseline, logs_dir, time_to_install); + break; + case BuildResult::BUILD_FAILED: + case BuildResult::POST_BUILD_CHECKS_FAILED: + case BuildResult::FILE_CONFLICTS: + case BuildResult::CACHE_MISSING: + case BuildResult::REMOVED: + case BuildResult::EXCLUDED: + handle_result(std::move(spec), CiFeatureBaselineState::Fail, baseline, logs_dir, time_to_install); + break; + } } for (const auto& result : unexpected_states) From c7f55987bdb3759fa5f8685f3ff34c41e28ba362 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Mon, 20 Mar 2023 21:47:35 +0100 Subject: [PATCH 29/69] Use stable sort to keep features of ports together --- include/vcpkg/base/util.h | 8 ++++++++ src/vcpkg/commands.test-features.cpp | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/vcpkg/base/util.h b/include/vcpkg/base/util.h index d653fef2c9..d9ebb414e0 100644 --- a/include/vcpkg/base/util.h +++ b/include/vcpkg/base/util.h @@ -328,6 +328,14 @@ namespace vcpkg::Util std::sort(begin(cont), end(cont), comp); } + template> + void stable_sort(Range& cont, Comp comp = Comp()) + { + using std::begin; + using std::end; + std::stable_sort(begin(cont), end(cont), comp); + } + template bool any_of(Range&& rng, Pred pred) { diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index f016445780..3b6e4dbe18 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -268,7 +268,7 @@ namespace vcpkg::Commands::TestFeatures {host_triplet, UnsupportedPortAction::Warn})); }); - Util::sort(install_plans, [](const auto& left, const auto& right) { + Util::stable_sort(install_plans, [](const auto& left, const auto& right) { return left.second.install_actions.size() < right.second.install_actions.size(); }); From db0364ca7a830a890cac99c48a60342d1d6183d4 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Thu, 23 Mar 2023 11:43:09 +0100 Subject: [PATCH 30/69] Don't test unsupported ports --- src/vcpkg/commands.test-features.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 3b6e4dbe18..3db0d9504d 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -223,16 +223,16 @@ namespace vcpkg::Commands::TestFeatures const auto& baseline = feature_baseline.get_port(port->core_paragraph->name); if (baseline.state == CiFeatureBaselineState::Skip) continue; PackageSpec package_spec(port->core_paragraph->name, target_triplet); - if (test_feature_core && !Util::Sets::contains(baseline.skip_features, "core")) - { - specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); - } const auto dep_info_vars = var_provider.get_or_load_dep_info_vars(package_spec, host_triplet); if (!port->core_paragraph->supports_expression.evaluate(dep_info_vars)) { fmt::print("Port {} is not supported on {}\n", port->core_paragraph->name, target_triplet); continue; } + if (test_feature_core && !Util::Sets::contains(baseline.skip_features, "core")) + { + specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); + } InternalFeatureSet all_features{{"core"}}; for (const auto& feature : port->feature_paragraphs) { From 61a453fd438f8c330cf6821fad28df433156882f Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Fri, 24 Mar 2023 17:28:38 +0100 Subject: [PATCH 31/69] Fix usage of wrong variable --- src/vcpkg/commands.test-features.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 3db0d9504d..318e1432d5 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -189,7 +189,7 @@ namespace vcpkg::Commands::TestFeatures } else { - feature_test_ports = Util::fmap(args.forwardable_arguments, [&](auto&& arg) { + feature_test_ports = Util::fmap(options.command_arguments, [&](auto&& arg) { return provider.get_control_file(arg).value_or_exit(VCPKG_LINE_INFO).source_control_file.get(); }); } From 2772c232ec9d18354cd8ac8a1689575b2be79868 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Fri, 24 Mar 2023 17:49:22 +0100 Subject: [PATCH 32/69] Do a full comparison if the vectors are not sorted --- src/vcpkg/ci-baseline.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vcpkg/ci-baseline.cpp b/src/vcpkg/ci-baseline.cpp index 1c2a92aa67..fca144ffff 100644 --- a/src/vcpkg/ci-baseline.cpp +++ b/src/vcpkg/ci-baseline.cpp @@ -392,7 +392,15 @@ namespace vcpkg bool CiFeatureBaselineEntry::will_fail(const InternalFeatureSet& internal_feature_set) const { - return Util::Vectors::contains(fail_configurations, internal_feature_set); + if (std::is_sorted(internal_feature_set.begin(), internal_feature_set.end())) + { + return Util::Vectors::contains(fail_configurations, internal_feature_set); + } + return Util::any_of(fail_configurations, [&](auto& fail_configuration) { + return fail_configuration.size() == internal_feature_set.size() && + Util::all_of(internal_feature_set, + [&](auto& feature) { return Util::contains(fail_configuration, feature); }); + }); } std::string to_string(CiFeatureBaselineState state) From c67d769b0e5c3a9c522a75449e4a5b395a1c0d19 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sun, 26 Mar 2023 21:20:26 +0200 Subject: [PATCH 33/69] Don't use moved from variable --- src/vcpkg/commands.test-features.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 318e1432d5..395bbf5d37 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -300,6 +300,7 @@ namespace vcpkg::Commands::TestFeatures if (actual_cascade != expected_cascade) { unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir, build_time}); + return; } bool expected_fail = (baseline.state == CiFeatureBaselineState::Fail || baseline.will_fail(spec.features)); bool actual_fail = (result == CiFeatureBaselineState::Fail); From 7f89ea89facb27034d9487906d58c33d70f73424 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 4 Apr 2023 19:11:04 +0200 Subject: [PATCH 34/69] Fix msvc build --- include/vcpkg/dependencies.h | 6 ++++++ src/vcpkg/commands.test-features.cpp | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/vcpkg/dependencies.h b/include/vcpkg/dependencies.h index 857b061a05..289e69cf55 100644 --- a/include/vcpkg/dependencies.h +++ b/include/vcpkg/dependencies.h @@ -109,6 +109,12 @@ namespace vcpkg struct ActionPlan { + ActionPlan() = default; + ActionPlan& operator=(const ActionPlan&) = default; + ActionPlan(const ActionPlan&) = default; + ActionPlan& operator=(ActionPlan&&) = default; + ActionPlan(ActionPlan&&) noexcept = default; + bool empty() const { return remove_actions.empty() && already_installed.empty() && install_actions.empty(); } size_t size() const { return remove_actions.size() + already_installed.size() + install_actions.size(); } void print_unsupported_warnings(); diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 394abf9d5b..18d3c3723e 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -86,7 +86,7 @@ namespace } else { - feature = Strings::concat("all_", ++counter); + feature = fmt::format("all_{}", ++counter); } auto new_base_path = base_path / Strings::concat(spec.package_spec.name(), '_', feature); filesystem.create_directory(new_base_path, VCPKG_LINE_INFO); @@ -142,7 +142,7 @@ namespace vcpkg::Commands::TestFeatures []() { return create_example_string("test-features llvm"); }, 0, SIZE_MAX, - {CI_SWITCHES, CI_SETTINGS}, + {CI_SWITCHES, CI_SETTINGS, {}}, nullptr, }; From f111e1562f9011e42d80c4446e1d8658bfa58c0d Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 4 Apr 2023 19:30:25 +0200 Subject: [PATCH 35/69] Move CiFeatureBaseline classes into own files since they don't share code with the CiBaseline classes --- include/vcpkg/ci-baseline.h | 27 ---- include/vcpkg/ci-feature-baseline.h | 47 +++++++ include/vcpkg/fwd/ci-baseline.h | 8 -- src/vcpkg/ci-baseline.cpp | 188 ------------------------- src/vcpkg/ci-feature-baseline.cpp | 199 +++++++++++++++++++++++++++ src/vcpkg/commands.test-features.cpp | 2 +- 6 files changed, 247 insertions(+), 224 deletions(-) create mode 100644 include/vcpkg/ci-feature-baseline.h create mode 100644 src/vcpkg/ci-feature-baseline.cpp diff --git a/include/vcpkg/ci-baseline.h b/include/vcpkg/ci-baseline.h index 0afb72b638..d6e7cd3a46 100644 --- a/include/vcpkg/ci-baseline.h +++ b/include/vcpkg/ci-baseline.h @@ -1,7 +1,6 @@ #pragma once #include #include -#include #include #include @@ -30,25 +29,6 @@ namespace vcpkg friend bool operator!=(const CiBaselineLine& lhs, const CiBaselineLine& rhs) { return !(lhs == rhs); } }; - struct CiFeatureBaselineEntry - { - CiFeatureBaselineState state = CiFeatureBaselineState::Pass; - std::set skip_features; - std::set no_separate_feature_test; - std::set cascade_features; - std::vector> fail_configurations; - bool will_fail(const InternalFeatureSet& internal_feature_set) const; - }; - - struct CiFeatureBaseline - { - std::unordered_map ports; - const CiFeatureBaselineEntry& get_port(const std::string& port_name) const; - }; - - void to_string(std::string& out, CiFeatureBaselineState state); - std::string to_string(CiFeatureBaselineState state); - struct TripletExclusions { Triplet triplet; @@ -75,13 +55,6 @@ namespace vcpkg std::vector parse_ci_baseline(StringView text, StringView origin, ParseMessages& messages); - CiFeatureBaseline parse_ci_feature_baseline(StringView text, - StringView origin, - ParseMessages& messages, - Triplet triplet, - Triplet host_triplet, - CMakeVars::CMakeVarProvider& var_provider); - struct CiBaselineData { SortedVector expected_failures; diff --git a/include/vcpkg/ci-feature-baseline.h b/include/vcpkg/ci-feature-baseline.h new file mode 100644 index 0000000000..c47fce7d82 --- /dev/null +++ b/include/vcpkg/ci-feature-baseline.h @@ -0,0 +1,47 @@ +#pragma once +#include +#include + +#include + +#include +#include +#include +#include + +namespace vcpkg +{ + enum class CiFeatureBaselineState + { + Skip, + Fail, + Cascade, + Pass, + }; + + struct CiFeatureBaselineEntry + { + CiFeatureBaselineState state = CiFeatureBaselineState::Pass; + std::set skip_features; + std::set no_separate_feature_test; + std::set cascade_features; + std::vector> fail_configurations; + bool will_fail(const InternalFeatureSet& internal_feature_set) const; + }; + + struct CiFeatureBaseline + { + std::unordered_map ports; + const CiFeatureBaselineEntry& get_port(const std::string& port_name) const; + }; + + void to_string(std::string& out, CiFeatureBaselineState state); + std::string to_string(CiFeatureBaselineState state); + + CiFeatureBaseline parse_ci_feature_baseline(StringView text, + StringView origin, + ParseMessages& messages, + Triplet triplet, + Triplet host_triplet, + CMakeVars::CMakeVarProvider& var_provider); +} diff --git a/include/vcpkg/fwd/ci-baseline.h b/include/vcpkg/fwd/ci-baseline.h index 89e0033fdb..79b80cad3f 100644 --- a/include/vcpkg/fwd/ci-baseline.h +++ b/include/vcpkg/fwd/ci-baseline.h @@ -4,7 +4,6 @@ namespace vcpkg { struct CiBaseline; struct CiBaselineLine; - struct CiFeatureBaseline; struct TripletExclusions; struct ExclusionsMap; struct ExclusionPredicate; @@ -15,13 +14,6 @@ namespace vcpkg Fail, Pass, }; - enum class CiFeatureBaselineState - { - Skip, - Fail, - Cascade, - Pass, - }; enum class SkipFailures : bool { No, diff --git a/src/vcpkg/ci-baseline.cpp b/src/vcpkg/ci-baseline.cpp index 063645eece..40fba32acc 100644 --- a/src/vcpkg/ci-baseline.cpp +++ b/src/vcpkg/ci-baseline.cpp @@ -3,7 +3,6 @@ #include #include -#include #include @@ -245,191 +244,4 @@ namespace vcpkg } return {}; } - - namespace - { - bool respect_entry(const ParsedQualifiedSpecifier& entry, - Triplet triplet, - Triplet host_triplet, - CMakeVars::CMakeVarProvider& var_provider) - { - if (auto maybe_triplet = entry.triplet.get()) - { - return *maybe_triplet == triplet; - } - else if (auto maybe_platform = entry.platform.get()) - { - return maybe_platform->evaluate( - var_provider.get_or_load_dep_info_vars(PackageSpec{entry.name, triplet}, host_triplet)); - } - return true; - } - } - - CiFeatureBaseline parse_ci_feature_baseline(StringView text, - StringView origin, - ParseMessages& messages, - Triplet triplet, - Triplet host_triplet, - CMakeVars::CMakeVarProvider& var_provider) - { - CiFeatureBaseline result; - ParserBase parser(text, origin); - for (;;) - { - parser.skip_whitespace(); - if (parser.at_eof()) - { - // success - return result; - } - - if (parser.cur() == '#') - { - parser.skip_line(); - continue; - } - - // port-name = (fail|skip)\b - auto maybe_spec = parse_qualified_specifier(parser); - if (!maybe_spec) break; - auto& spec = maybe_spec.value_or_exit(VCPKG_LINE_INFO); - if (spec.platform.has_value() && spec.triplet.has_value()) - { - parser.add_error(msg::format(msgBaselineOnlyPlatformExpressionOrTriplet)); - break; - } - - parser.skip_tabs_spaces(); - if (parser.require_character('=')) - { - break; - } - - parser.skip_tabs_spaces(); - - static constexpr StringLiteral FAIL = "fail"; - static constexpr StringLiteral SKIP = "skip"; - static constexpr StringLiteral CASCADE = "cascade"; - static constexpr StringLiteral NO_TEST = "no-separate-feature-test"; - static constexpr CiFeatureBaselineState NO_TEST_STATE = static_cast(100); - CiFeatureBaselineState state; - if (parser.try_match_keyword(FAIL)) - { - state = CiFeatureBaselineState::Fail; - } - else if (parser.try_match_keyword(SKIP)) - { - state = CiFeatureBaselineState::Skip; - } - else if (parser.try_match_keyword(CASCADE)) - { - state = CiFeatureBaselineState::Cascade; - } - else if (parser.try_match_keyword(NO_TEST)) - { - state = NO_TEST_STATE; - } - else - { - parser.add_error(msg::format(msgExpectedFailOrSkip)); - break; - } - - parser.skip_tabs_spaces(); - auto trailing = parser.cur(); - if (trailing == '#') - { - parser.skip_line(); - } - else if (trailing == '\r' || trailing == '\n') - { - parser.skip_newline(); - } - else if (trailing != Unicode::end_of_file) - { - parser.add_error(msg::format(msgUnknownBaselineFileContent)); - break; - } - - if (respect_entry(spec, triplet, host_triplet, var_provider)) - { - if (spec.features.has_value()) - { - auto& features = *spec.features.get(); - if (state == CiFeatureBaselineState::Skip) - { - result.ports[spec.name].skip_features.insert(features.begin(), features.end()); - } - else if (state == CiFeatureBaselineState::Cascade) - { - result.ports[spec.name].cascade_features.insert(features.begin(), features.end()); - } - else if (state == CiFeatureBaselineState::Fail) - { - features.emplace_back("core"); - result.ports[spec.name].fail_configurations.push_back( - Util::sort_unique_erase(std::move(features))); - } - else if (state == NO_TEST_STATE) - { - result.ports[spec.name].no_separate_feature_test.insert(features.begin(), features.end()); - } - } - else - { - result.ports[spec.name].state = state; - } - } - } - - // failure - messages = std::move(parser).extract_messages(); - result.ports.clear(); - return result; - } - - const CiFeatureBaselineEntry& CiFeatureBaseline::get_port(const std::string& port_name) const - { - auto iter = ports.find(port_name); - if (iter != ports.end()) - { - return iter->second; - } - static CiFeatureBaselineEntry empty_entry; - return empty_entry; - } - - bool CiFeatureBaselineEntry::will_fail(const InternalFeatureSet& internal_feature_set) const - { - if (std::is_sorted(internal_feature_set.begin(), internal_feature_set.end())) - { - return Util::Vectors::contains(fail_configurations, internal_feature_set); - } - return Util::any_of(fail_configurations, [&](auto& fail_configuration) { - return fail_configuration.size() == internal_feature_set.size() && - Util::all_of(internal_feature_set, - [&](auto& feature) { return Util::contains(fail_configuration, feature); }); - }); - } - - std::string to_string(CiFeatureBaselineState state) - { - std::string s; - to_string(s, state); - return s; - } - - void to_string(std::string& out, CiFeatureBaselineState state) - { - switch (state) - { - case CiFeatureBaselineState::Fail: out += "fail"; return; - case CiFeatureBaselineState::Pass: out += "pass"; return; - case CiFeatureBaselineState::Cascade: out += "cascade"; return; - case CiFeatureBaselineState::Skip: out += "skip"; return; - } - Checks::unreachable(VCPKG_LINE_INFO); - } - } diff --git a/src/vcpkg/ci-feature-baseline.cpp b/src/vcpkg/ci-feature-baseline.cpp new file mode 100644 index 0000000000..636f944ec1 --- /dev/null +++ b/src/vcpkg/ci-feature-baseline.cpp @@ -0,0 +1,199 @@ +#include +#include + +#include +#include +#include + +using namespace vcpkg; + +namespace vcpkg +{ + + namespace + { + bool respect_entry(const ParsedQualifiedSpecifier& entry, + Triplet triplet, + Triplet host_triplet, + CMakeVars::CMakeVarProvider& var_provider) + { + if (auto maybe_triplet = entry.triplet.get()) + { + return *maybe_triplet == triplet; + } + else if (auto maybe_platform = entry.platform.get()) + { + return maybe_platform->evaluate( + var_provider.get_or_load_dep_info_vars(PackageSpec{entry.name, triplet}, host_triplet)); + } + return true; + } + } + + CiFeatureBaseline parse_ci_feature_baseline(StringView text, + StringView origin, + ParseMessages& messages, + Triplet triplet, + Triplet host_triplet, + CMakeVars::CMakeVarProvider& var_provider) + { + CiFeatureBaseline result; + ParserBase parser(text, origin); + for (;;) + { + parser.skip_whitespace(); + if (parser.at_eof()) + { + // success + return result; + } + + if (parser.cur() == '#') + { + parser.skip_line(); + continue; + } + + // port-name = (fail|skip)\b + auto maybe_spec = parse_qualified_specifier(parser); + if (!maybe_spec) break; + auto& spec = maybe_spec.value_or_exit(VCPKG_LINE_INFO); + if (spec.platform.has_value() && spec.triplet.has_value()) + { + parser.add_error(msg::format(msgBaselineOnlyPlatformExpressionOrTriplet)); + break; + } + + parser.skip_tabs_spaces(); + if (parser.require_character('=')) + { + break; + } + + parser.skip_tabs_spaces(); + + static constexpr StringLiteral FAIL = "fail"; + static constexpr StringLiteral SKIP = "skip"; + static constexpr StringLiteral CASCADE = "cascade"; + static constexpr StringLiteral NO_TEST = "no-separate-feature-test"; + static constexpr CiFeatureBaselineState NO_TEST_STATE = static_cast(100); + CiFeatureBaselineState state; + if (parser.try_match_keyword(FAIL)) + { + state = CiFeatureBaselineState::Fail; + } + else if (parser.try_match_keyword(SKIP)) + { + state = CiFeatureBaselineState::Skip; + } + else if (parser.try_match_keyword(CASCADE)) + { + state = CiFeatureBaselineState::Cascade; + } + else if (parser.try_match_keyword(NO_TEST)) + { + state = NO_TEST_STATE; + } + else + { + parser.add_error(msg::format(msgExpectedFailOrSkip)); + break; + } + + parser.skip_tabs_spaces(); + auto trailing = parser.cur(); + if (trailing == '#') + { + parser.skip_line(); + } + else if (trailing == '\r' || trailing == '\n') + { + parser.skip_newline(); + } + else if (trailing != Unicode::end_of_file) + { + parser.add_error(msg::format(msgUnknownBaselineFileContent)); + break; + } + + if (respect_entry(spec, triplet, host_triplet, var_provider)) + { + if (spec.features.has_value()) + { + auto& features = *spec.features.get(); + if (state == CiFeatureBaselineState::Skip) + { + result.ports[spec.name].skip_features.insert(features.begin(), features.end()); + } + else if (state == CiFeatureBaselineState::Cascade) + { + result.ports[spec.name].cascade_features.insert(features.begin(), features.end()); + } + else if (state == CiFeatureBaselineState::Fail) + { + features.emplace_back("core"); + result.ports[spec.name].fail_configurations.push_back( + Util::sort_unique_erase(std::move(features))); + } + else if (state == NO_TEST_STATE) + { + result.ports[spec.name].no_separate_feature_test.insert(features.begin(), features.end()); + } + } + else + { + result.ports[spec.name].state = state; + } + } + } + + // failure + messages = std::move(parser).extract_messages(); + result.ports.clear(); + return result; + } + + const CiFeatureBaselineEntry& CiFeatureBaseline::get_port(const std::string& port_name) const + { + auto iter = ports.find(port_name); + if (iter != ports.end()) + { + return iter->second; + } + static CiFeatureBaselineEntry empty_entry; + return empty_entry; + } + + bool CiFeatureBaselineEntry::will_fail(const InternalFeatureSet& internal_feature_set) const + { + if (std::is_sorted(internal_feature_set.begin(), internal_feature_set.end())) + { + return Util::Vectors::contains(fail_configurations, internal_feature_set); + } + return Util::any_of(fail_configurations, [&](auto& fail_configuration) { + return fail_configuration.size() == internal_feature_set.size() && + Util::all_of(internal_feature_set, + [&](auto& feature) { return Util::contains(fail_configuration, feature); }); + }); + } + + std::string to_string(CiFeatureBaselineState state) + { + std::string s; + to_string(s, state); + return s; + } + + void to_string(std::string& out, CiFeatureBaselineState state) + { + switch (state) + { + case CiFeatureBaselineState::Fail: out += "fail"; return; + case CiFeatureBaselineState::Pass: out += "pass"; return; + case CiFeatureBaselineState::Cascade: out += "cascade"; return; + case CiFeatureBaselineState::Skip: out += "skip"; return; + } + Checks::unreachable(VCPKG_LINE_INFO); + } + +} diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 18d3c3723e..0200d7fc14 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include From 935ffd9b1f501d432c2cc17f591f681480c8a4bc Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Fri, 5 May 2023 19:06:55 +0200 Subject: [PATCH 36/69] core is not allowed in non fail baseline entries --- include/vcpkg/base/message-data.inc.h | 4 ++++ locales/messages.json | 1 + src/vcpkg/ci-feature-baseline.cpp | 10 ++++++++++ 3 files changed, 15 insertions(+) diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 3ab30140a4..32e03a902a 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -1853,6 +1853,10 @@ DECLARE_MESSAGE(NewSpecifyNameVersionOrApplication, DECLARE_MESSAGE(NewVersionCannotBeEmpty, (), "", "--version cannot be empty.") DECLARE_MESSAGE(NoArgumentsForOption, (msg::option), "", "The option --{option} does not accept an argument.") DECLARE_MESSAGE(NoCachedPackages, (), "", "No packages are cached.") +DECLARE_MESSAGE(NoCoreFeatureAllowedInNonFailBaselineEntry, + (), + "", + "'core' is not allowed in the list of features if the entry is not of type ' = fail'") DECLARE_MESSAGE(NoError, (), "", "no error") DECLARE_MESSAGE(NoInstalledPackages, (), diff --git a/locales/messages.json b/locales/messages.json index cb6881f758..54477647c8 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -1045,6 +1045,7 @@ "NoArgumentsForOption": "The option --{option} does not accept an argument.", "_NoArgumentsForOption.comment": "An example of {option} is editable.", "NoCachedPackages": "No packages are cached.", + "NoCoreFeatureAllowedInNonFailBaselineEntry": "'core' is not allowed in the list of features if the entry is not of type ' = fail'", "NoError": "no error", "NoInstalledPackages": "No packages are installed. Did you mean `search`?", "_NoInstalledPackages.comment": "The name 'search' is the name of a command that is not localized.", diff --git a/src/vcpkg/ci-feature-baseline.cpp b/src/vcpkg/ci-feature-baseline.cpp index 666bdc26a8..7a9bcb55fa 100644 --- a/src/vcpkg/ci-feature-baseline.cpp +++ b/src/vcpkg/ci-feature-baseline.cpp @@ -71,6 +71,7 @@ namespace vcpkg parser.skip_tabs_spaces(); + auto cur_loc = parser.cur_loc(); static constexpr StringLiteral FAIL = "fail"; static constexpr StringLiteral SKIP = "skip"; static constexpr StringLiteral CASCADE = "cascade"; @@ -114,6 +115,15 @@ namespace vcpkg parser.add_error(msg::format(msgUnknownBaselineFileContent)); break; } + if (state != CiFeatureBaselineState::Fail && spec.features.has_value()) + { + const bool contains_core = Util::contains(*spec.features.get(), "core"); + if (contains_core) + { + parser.add_error(msg::format(msgNoCoreFeatureAllowedInNonFailBaselineEntry), cur_loc); + break; + } + } if (respect_entry(spec, triplet, host_triplet, var_provider)) { From fc6c3d895d6097b1a89e8e4833da301288a8ca8c Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Fri, 5 May 2023 21:13:43 +0200 Subject: [PATCH 37/69] Add support for options --- include/vcpkg/base/message-data.inc.h | 4 ++++ include/vcpkg/ci-feature-baseline.h | 2 ++ locales/messages.json | 2 ++ src/vcpkg/ci-feature-baseline.cpp | 17 +++++++++++++++++ src/vcpkg/commands.test-features.cpp | 18 +++++++++++++++++- 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 32e03a902a..3f9e5144d3 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -995,6 +995,10 @@ DECLARE_MESSAGE(FailedVendorAuthentication, "", "One or more {vendor} credential providers failed to authenticate. See '{url}' for more details " "on how to provide credentials.") +DECLARE_MESSAGE(FeatureBaselineExpectedFeatures, + (msg::value), + "{value} is a keyword ", + "When using '{value}' a list of features must be specified.") DECLARE_MESSAGE(FeedbackAppreciated, (), "", "Thank you for your feedback!") DECLARE_MESSAGE(FilesContainAbsolutePath1, (), diff --git a/include/vcpkg/ci-feature-baseline.h b/include/vcpkg/ci-feature-baseline.h index c47fce7d82..05b6322526 100644 --- a/include/vcpkg/ci-feature-baseline.h +++ b/include/vcpkg/ci-feature-baseline.h @@ -26,6 +26,8 @@ namespace vcpkg std::set no_separate_feature_test; std::set cascade_features; std::vector> fail_configurations; + // A list of sets of features of which excatly one must be selected + std::vector> options; bool will_fail(const InternalFeatureSet& internal_feature_set) const; }; diff --git a/locales/messages.json b/locales/messages.json index 54477647c8..85c6bae99f 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -630,6 +630,8 @@ "_FailedToWriteManifest.comment": "An example of {path} is /foo/bar.", "FailedVendorAuthentication": "One or more {vendor} credential providers failed to authenticate. See '{url}' for more details on how to provide credentials.", "_FailedVendorAuthentication.comment": "An example of {vendor} is Azure. An example of {url} is https://github.com/microsoft/vcpkg.", + "FeatureBaselineExpectedFeatures": "When using '{value}' a list of features must be specified.", + "_FeatureBaselineExpectedFeatures.comment": "{value} is a keyword ", "FeedbackAppreciated": "Thank you for your feedback!", "FetchingBaselineInfo": "Fetching baseline information from {package_name}...", "_FetchingBaselineInfo.comment": "An example of {package_name} is zlib.", diff --git a/src/vcpkg/ci-feature-baseline.cpp b/src/vcpkg/ci-feature-baseline.cpp index 7a9bcb55fa..a6bf4be31f 100644 --- a/src/vcpkg/ci-feature-baseline.cpp +++ b/src/vcpkg/ci-feature-baseline.cpp @@ -76,7 +76,9 @@ namespace vcpkg static constexpr StringLiteral SKIP = "skip"; static constexpr StringLiteral CASCADE = "cascade"; static constexpr StringLiteral NO_TEST = "no-separate-feature-test"; + static constexpr StringLiteral OPTIONS = "options"; static constexpr CiFeatureBaselineState NO_TEST_STATE = static_cast(100); + static constexpr CiFeatureBaselineState OPTIONS_STATE = static_cast(101); CiFeatureBaselineState state; if (parser.try_match_keyword(FAIL)) { @@ -94,6 +96,10 @@ namespace vcpkg { state = NO_TEST_STATE; } + else if (parser.try_match_keyword(OPTIONS)) + { + state = OPTIONS_STATE; + } else { parser.add_error(msg::format(msgExpectedFailOrSkip)); @@ -148,9 +154,20 @@ namespace vcpkg { result.ports[spec.name].no_separate_feature_test.insert(features.begin(), features.end()); } + else if (state == OPTIONS_STATE) + { + result.ports[spec.name].options.push_back(features); + } } else { + if (state == NO_TEST_STATE || state == OPTIONS_STATE) + { + parser.add_error(msg::format(msgFeatureBaselineExpectedFeatures, + msg::value = (state == NO_TEST_STATE ? NO_TEST : OPTIONS)), + cur_loc); + break; + } result.ports[spec.name].state = state; } } diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index dc6b9a7dc1..f25bae943e 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -233,6 +233,10 @@ namespace vcpkg::Commands::TestFeatures if (test_feature_core && !Util::Sets::contains(baseline.skip_features, "core")) { specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); + for (const auto& option_set : baseline.options) + { + specs_to_test.back().features.push_back(option_set.front()); + } } InternalFeatureSet all_features{{"core"}}; for (const auto& feature : port->feature_paragraphs) @@ -244,12 +248,24 @@ namespace vcpkg::Commands::TestFeatures // will them simply cascade too if (!Util::Sets::contains(baseline.cascade_features, feature->name)) { - all_features.push_back(feature->name); + if (Util::all_of(baseline.options, [&](const auto& options) { + return !Util::contains(options, feature->name) || options.front() == feature->name; + })) + { + all_features.push_back(feature->name); + } } if (test_features_seperatly && !Util::Sets::contains(baseline.no_separate_feature_test, feature->name)) { specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); + for (const auto& options : baseline.options) + { + if (!Util::contains(options, feature->name)) + { + specs_to_test.back().features.push_back(options.front()); + } + } } } } From fab6107337bd4a6fe59a529141e2eaa930a56a72 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Fri, 5 May 2023 23:00:30 +0200 Subject: [PATCH 38/69] Add combination-fails and feature-fails so that failing features are not included in the all feature test. --- include/vcpkg/base/message-data.inc.h | 9 ++-- include/vcpkg/ci-feature-baseline.h | 2 + locales/messages.json | 6 ++- src/vcpkg/ci-feature-baseline.cpp | 67 +++++++++++++++++++++------ src/vcpkg/commands.test-features.cpp | 7 +-- 5 files changed, 68 insertions(+), 23 deletions(-) diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 3f9e5144d3..803b322be8 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -997,8 +997,9 @@ DECLARE_MESSAGE(FailedVendorAuthentication, "on how to provide credentials.") DECLARE_MESSAGE(FeatureBaselineExpectedFeatures, (msg::value), - "{value} is a keyword ", + "{value} is a keyword", "When using '{value}' a list of features must be specified.") +DECLARE_MESSAGE(FeatureBaselineNoFeaturesForFail, (), "", "When using '= fail' no list of features is allowed.") DECLARE_MESSAGE(FeedbackAppreciated, (), "", "Thank you for your feedback!") DECLARE_MESSAGE(FilesContainAbsolutePath1, (), @@ -1858,9 +1859,9 @@ DECLARE_MESSAGE(NewVersionCannotBeEmpty, (), "", "--version cannot be empty.") DECLARE_MESSAGE(NoArgumentsForOption, (msg::option), "", "The option --{option} does not accept an argument.") DECLARE_MESSAGE(NoCachedPackages, (), "", "No packages are cached.") DECLARE_MESSAGE(NoCoreFeatureAllowedInNonFailBaselineEntry, - (), - "", - "'core' is not allowed in the list of features if the entry is not of type ' = fail'") + (msg::value), + "{value} is a keyword", + "'core' is not allowed in the list of features if the entry is of type '{value}'") DECLARE_MESSAGE(NoError, (), "", "no error") DECLARE_MESSAGE(NoInstalledPackages, (), diff --git a/include/vcpkg/ci-feature-baseline.h b/include/vcpkg/ci-feature-baseline.h index 05b6322526..adf2f9cdcb 100644 --- a/include/vcpkg/ci-feature-baseline.h +++ b/include/vcpkg/ci-feature-baseline.h @@ -17,6 +17,7 @@ namespace vcpkg Fail, Cascade, Pass, + FirstFree // only a marker for the last enum entry }; struct CiFeatureBaselineEntry @@ -25,6 +26,7 @@ namespace vcpkg std::set skip_features; std::set no_separate_feature_test; std::set cascade_features; + std::set failing_features; std::vector> fail_configurations; // A list of sets of features of which excatly one must be selected std::vector> options; diff --git a/locales/messages.json b/locales/messages.json index 85c6bae99f..cca85f46c8 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -631,7 +631,8 @@ "FailedVendorAuthentication": "One or more {vendor} credential providers failed to authenticate. See '{url}' for more details on how to provide credentials.", "_FailedVendorAuthentication.comment": "An example of {vendor} is Azure. An example of {url} is https://github.com/microsoft/vcpkg.", "FeatureBaselineExpectedFeatures": "When using '{value}' a list of features must be specified.", - "_FeatureBaselineExpectedFeatures.comment": "{value} is a keyword ", + "_FeatureBaselineExpectedFeatures.comment": "{value} is a keyword", + "FeatureBaselineNoFeaturesForFail": "When using '= fail' no list of features is allowed.", "FeedbackAppreciated": "Thank you for your feedback!", "FetchingBaselineInfo": "Fetching baseline information from {package_name}...", "_FetchingBaselineInfo.comment": "An example of {package_name} is zlib.", @@ -1047,7 +1048,8 @@ "NoArgumentsForOption": "The option --{option} does not accept an argument.", "_NoArgumentsForOption.comment": "An example of {option} is editable.", "NoCachedPackages": "No packages are cached.", - "NoCoreFeatureAllowedInNonFailBaselineEntry": "'core' is not allowed in the list of features if the entry is not of type ' = fail'", + "NoCoreFeatureAllowedInNonFailBaselineEntry": "'core' is not allowed in the list of features if the entry is of type '{value}'", + "_NoCoreFeatureAllowedInNonFailBaselineEntry.comment": "{value} is a keyword", "NoError": "no error", "NoInstalledPackages": "No packages are installed. Did you mean `search`?", "_NoInstalledPackages.comment": "The name 'search' is the name of a command that is not localized.", diff --git a/src/vcpkg/ci-feature-baseline.cpp b/src/vcpkg/ci-feature-baseline.cpp index a6bf4be31f..1bde1c7f6c 100644 --- a/src/vcpkg/ci-feature-baseline.cpp +++ b/src/vcpkg/ci-feature-baseline.cpp @@ -75,10 +75,19 @@ namespace vcpkg static constexpr StringLiteral FAIL = "fail"; static constexpr StringLiteral SKIP = "skip"; static constexpr StringLiteral CASCADE = "cascade"; + static constexpr StringLiteral PASS = "pass"; static constexpr StringLiteral NO_TEST = "no-separate-feature-test"; static constexpr StringLiteral OPTIONS = "options"; - static constexpr CiFeatureBaselineState NO_TEST_STATE = static_cast(100); - static constexpr CiFeatureBaselineState OPTIONS_STATE = static_cast(101); + static constexpr StringLiteral FEATURE_FAIL = "feature-fails"; + static constexpr StringLiteral COMBINATION_FAIL = "combination-fails"; + static constexpr int first_free = static_cast(CiFeatureBaselineState::FirstFree); + static constexpr CiFeatureBaselineState NO_TEST_STATE = static_cast(first_free); + static constexpr CiFeatureBaselineState OPTIONS_STATE = static_cast(first_free + 1); + static constexpr CiFeatureBaselineState FEATURE_FAIL_STATE = + static_cast(first_free + 2); + static constexpr CiFeatureBaselineState COMBINATION_FAIL_STATE = + static_cast(first_free + 3); + const StringLiteral names[] = {FAIL, SKIP, CASCADE, PASS, NO_TEST, OPTIONS, FEATURE_FAIL, COMBINATION_FAIL}; CiFeatureBaselineState state; if (parser.try_match_keyword(FAIL)) { @@ -100,6 +109,14 @@ namespace vcpkg { state = OPTIONS_STATE; } + else if (parser.try_match_keyword(FEATURE_FAIL)) + { + state = FEATURE_FAIL_STATE; + } + else if (parser.try_match_keyword(COMBINATION_FAIL)) + { + state = COMBINATION_FAIL_STATE; + } else { parser.add_error(msg::format(msgExpectedFailOrSkip)); @@ -121,14 +138,32 @@ namespace vcpkg parser.add_error(msg::format(msgUnknownBaselineFileContent)); break; } - if (state != CiFeatureBaselineState::Fail && spec.features.has_value()) + if (spec.features.has_value()) { - const bool contains_core = Util::contains(*spec.features.get(), "core"); - if (contains_core) + if (state == CiFeatureBaselineState::Fail) { - parser.add_error(msg::format(msgNoCoreFeatureAllowedInNonFailBaselineEntry), cur_loc); + parser.add_error(msg::format(msgFeatureBaselineNoFeaturesForFail), cur_loc); break; } + if (state != COMBINATION_FAIL_STATE && state != OPTIONS_STATE) + { + const bool contains_core = Util::contains(*spec.features.get(), "core"); + if (contains_core) + { + parser.add_error(msg::format(msgNoCoreFeatureAllowedInNonFailBaselineEntry, + msg::value = names[static_cast(state)]), + cur_loc); + break; + } + } + } + else if (state == NO_TEST_STATE || state == OPTIONS_STATE || state == FEATURE_FAIL_STATE || + state == COMBINATION_FAIL_STATE) + { + parser.add_error( + msg::format(msgFeatureBaselineExpectedFeatures, msg::value = (names[static_cast(state)])), + cur_loc); + break; } if (respect_entry(spec, triplet, host_triplet, var_provider)) @@ -144,12 +179,16 @@ namespace vcpkg { result.ports[spec.name].cascade_features.insert(features.begin(), features.end()); } - else if (state == CiFeatureBaselineState::Fail) + else if (state == COMBINATION_FAIL_STATE) { features.emplace_back("core"); result.ports[spec.name].fail_configurations.push_back( Util::sort_unique_erase(std::move(features))); } + else if (state == FEATURE_FAIL_STATE) + { + result.ports[spec.name].failing_features.insert(features.begin(), features.end()); + } else if (state == NO_TEST_STATE) { result.ports[spec.name].no_separate_feature_test.insert(features.begin(), features.end()); @@ -161,13 +200,6 @@ namespace vcpkg } else { - if (state == NO_TEST_STATE || state == OPTIONS_STATE) - { - parser.add_error(msg::format(msgFeatureBaselineExpectedFeatures, - msg::value = (state == NO_TEST_STATE ? NO_TEST : OPTIONS)), - cur_loc); - break; - } result.ports[spec.name].state = state; } } @@ -192,6 +224,12 @@ namespace vcpkg bool CiFeatureBaselineEntry::will_fail(const InternalFeatureSet& internal_feature_set) const { + if (!failing_features.empty() && Util::any_of(internal_feature_set, [&](const auto& feature) { + return Util::Sets::contains(failing_features, feature); + })) + { + return true; + } if (std::is_sorted(internal_feature_set.begin(), internal_feature_set.end())) { return Util::Vectors::contains(fail_configurations, internal_feature_set); @@ -218,6 +256,7 @@ namespace vcpkg case CiFeatureBaselineState::Pass: out += "pass"; return; case CiFeatureBaselineState::Cascade: out += "cascade"; return; case CiFeatureBaselineState::Skip: out += "skip"; return; + case CiFeatureBaselineState::FirstFree:; } Checks::unreachable(VCPKG_LINE_INFO); } diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index f25bae943e..a5ad1d66d4 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -244,9 +244,10 @@ namespace vcpkg::Commands::TestFeatures if (feature->supports_expression.evaluate(dep_info_vars) && !Util::Sets::contains(baseline.skip_features, feature->name)) { - // if we expect a feature to cascade don't add it the the all features test because this test - // will them simply cascade too - if (!Util::Sets::contains(baseline.cascade_features, feature->name)) + // if we expect a feature to cascade or fail don't add it the the all features test because this + // test will them simply cascade or fail too + if (!Util::Sets::contains(baseline.cascade_features, feature->name) && + !Util::Sets::contains(baseline.failing_features, feature->name)) { if (Util::all_of(baseline.options, [&](const auto& options) { return !Util::contains(options, feature->name) || options.front() == feature->name; From 82b52d516455a3dfb3d29251840070dd3f6b7827 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 6 May 2023 12:53:18 +0200 Subject: [PATCH 39/69] File conflicts are not always the fault of the port --- src/vcpkg/commands.test-features.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index a5ad1d66d4..45f9e207eb 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -418,7 +418,6 @@ namespace vcpkg::Commands::TestFeatures } [[fallthrough]]; case BuildResult::POST_BUILD_CHECKS_FAILED: - case BuildResult::FILE_CONFLICTS: known_failures.insert(result.get_abi().value_or_exit(VCPKG_LINE_INFO)); break; default: break; @@ -441,6 +440,10 @@ namespace vcpkg::Commands::TestFeatures case BuildResult::CACHE_MISSING: case BuildResult::REMOVED: case BuildResult::EXCLUDED: + if (auto abi = summary.results.back().get_abi().get()) + { + known_failures.insert(*abi); + } handle_result(std::move(spec), CiFeatureBaselineState::Fail, baseline, logs_dir, time_to_install); break; } From 6dbedb6528102c46eb82a4e452688a24b1ffab4c Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sun, 7 May 2023 11:48:15 +0200 Subject: [PATCH 40/69] Don't add the core feature twice --- src/vcpkg/commands.test-features.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 45f9e207eb..e6d9e5e2e3 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -235,7 +235,10 @@ namespace vcpkg::Commands::TestFeatures specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core"}}); for (const auto& option_set : baseline.options) { - specs_to_test.back().features.push_back(option_set.front()); + if (option_set.front() != "core") + { + specs_to_test.back().features.push_back(option_set.front()); + } } } InternalFeatureSet all_features{{"core"}}; @@ -262,7 +265,7 @@ namespace vcpkg::Commands::TestFeatures specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); for (const auto& options : baseline.options) { - if (!Util::contains(options, feature->name)) + if (options.front() != "core" && !Util::contains(options, feature->name)) { specs_to_test.back().features.push_back(options.front()); } From 424d7291a1088b2756f37812e5e99158355119d2 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sun, 7 May 2023 12:04:40 +0200 Subject: [PATCH 41/69] Fix msvc warning --- src/vcpkg/commands.test-features.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index e6d9e5e2e3..bdb2fbb261 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -263,11 +263,11 @@ namespace vcpkg::Commands::TestFeatures !Util::Sets::contains(baseline.no_separate_feature_test, feature->name)) { specs_to_test.emplace_back(package_spec, InternalFeatureSet{{"core", feature->name}}); - for (const auto& options : baseline.options) + for (const auto& option_set : baseline.options) { - if (options.front() != "core" && !Util::contains(options, feature->name)) + if (option_set.front() != "core" && !Util::contains(option_set, feature->name)) { - specs_to_test.back().features.push_back(options.front()); + specs_to_test.back().features.push_back(option_set.front()); } } } From 170d2799860f24864b1890be172bacc3aff24f2b Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 23 May 2023 10:18:52 +0200 Subject: [PATCH 42/69] Fetch binary cache before installation --- src/vcpkg/commands.test-features.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 7746934b41..38d0b5e47a 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -399,6 +399,7 @@ namespace vcpkg::Commands::TestFeatures ? *(feature_build_logs_recorder_storage.get()) : null_build_logs_recorder(); ElapsedTimer install_timer; + binary_cache.fetch(install_plan.install_actions); const auto summary = Install::execute_plan( args, install_plan, KeepGoing::YES, paths, status_db, binary_cache, build_logs_recorder); binary_cache.clear_cache(); From c6845cfd26ec175c77765204fc74c8fcfeee3701 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 23 May 2023 16:24:12 +0200 Subject: [PATCH 43/69] Use PortAbiCache to reduce time spend on computing abis --- include/vcpkg/commands.build.h | 18 ++++++- src/vcpkg/commands.build.cpp | 97 +++++++++++++++++++--------------- 2 files changed, 71 insertions(+), 44 deletions(-) diff --git a/include/vcpkg/commands.build.h b/include/vcpkg/commands.build.h index ff17f1f08a..ed06b01bba 100644 --- a/include/vcpkg/commands.build.h +++ b/include/vcpkg/commands.build.h @@ -279,10 +279,26 @@ namespace vcpkg std::vector heuristic_resources; }; + struct PortAbiCache + { + struct AbiCacheEntry + { + std::vector abi_entries; + std::vector files; + std::vector hashes; + Json::Value heuristic_resources; + }; + AbiCacheEntry& get(const Path& port_dir) const; + + private: + mutable std::unordered_map items; + }; + void compute_all_abis(const VcpkgPaths& paths, ActionPlan& action_plan, const CMakeVars::CMakeVarProvider& var_provider, - const StatusParagraphs& status_db); + const StatusParagraphs& status_db, + const PortAbiCache& cache = {}); struct EnvCache { diff --git a/src/vcpkg/commands.build.cpp b/src/vcpkg/commands.build.cpp index 984fe327b6..9426f1c366 100644 --- a/src/vcpkg/commands.build.cpp +++ b/src/vcpkg/commands.build.cpp @@ -1071,7 +1071,8 @@ namespace vcpkg static Optional compute_abi_tag(const VcpkgPaths& paths, const InstallPlanAction& action, - Span dependency_abis) + Span dependency_abis, + const PortAbiCache& cache) { auto& fs = paths.get_filesystem(); Triplet triplet = action.spec.triplet(); @@ -1107,45 +1108,61 @@ namespace vcpkg abi_tag_entries.emplace_back("triplet_abi", triplet_abi); abi_entries_from_abi_info(abi_info, 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 - // just mark the port as no-hash - constexpr int max_port_file_count = 100; - - std::string portfile_cmake_contents; - std::vector files; - std::vector hashes; auto&& port_dir = action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_location; - size_t port_file_count = 0; - Path abs_port_file; - for (auto& port_file : fs.get_regular_files_recursive_lexically_proximate(port_dir, VCPKG_LINE_INFO)) + auto& cache_entry = cache.get(port_dir); + if (cache_entry.files.empty()) { - if (port_file.filename() == ".DS_Store") - { - continue; - } - abs_port_file = port_dir; - abs_port_file /= port_file; + // If there is an unusually large number of files in the port then + // something suspicious is going on. Rather than hash all of them + // just mark the port as no-hash + constexpr int max_port_file_count = 100; + + std::string portfile_cmake_contents; - if (port_file.extension() == ".cmake") + size_t port_file_count = 0; + Path abs_port_file; + for (auto& port_file : fs.get_regular_files_recursive_lexically_proximate(port_dir, VCPKG_LINE_INFO)) { - portfile_cmake_contents += fs.read_contents(abs_port_file, VCPKG_LINE_INFO); + if (port_file.filename() == ".DS_Store") + { + continue; + } + abs_port_file = port_dir; + abs_port_file /= port_file; + + if (port_file.extension() == ".cmake") + { + portfile_cmake_contents += fs.read_contents(abs_port_file, VCPKG_LINE_INFO); + } + + auto hash = vcpkg::Hash::get_file_hash(fs, abs_port_file, Hash::Algorithm::Sha256) + .value_or_exit(VCPKG_LINE_INFO); + cache_entry.abi_entries.emplace_back(port_file, hash); + cache_entry.files.push_back(port_file); + cache_entry.hashes.push_back(std::move(hash)); + + ++port_file_count; + if (port_file_count > max_port_file_count) + { + cache_entry.abi_entries.emplace_back("no_hash_max_portfile", ""); + break; + } } - auto hash = - vcpkg::Hash::get_file_hash(fs, abs_port_file, Hash::Algorithm::Sha256).value_or_exit(VCPKG_LINE_INFO); - abi_tag_entries.emplace_back(port_file, hash); - files.push_back(port_file); - hashes.push_back(std::move(hash)); + cache_entry.heuristic_resources = run_resource_heuristics(portfile_cmake_contents); - ++port_file_count; - if (port_file_count > max_port_file_count) + auto& helpers = paths.get_cmake_script_hashes(); + for (auto&& helper : helpers) { - abi_tag_entries.emplace_back("no_hash_max_portfile", ""); - break; + if (Strings::case_insensitive_ascii_contains(portfile_cmake_contents, helper.first)) + { + cache_entry.abi_entries.emplace_back(helper.first, helper.second); + } } } + Util::Vectors::append(&abi_tag_entries, cache_entry.abi_entries); + abi_tag_entries.emplace_back("cmake", paths.get_tool_version(Tools::CMAKE, stdout_sink)); // This #ifdef is mirrored in tools.cpp's PowershellProvider @@ -1153,15 +1170,6 @@ namespace vcpkg abi_tag_entries.emplace_back("powershell", paths.get_tool_version("powershell-core", stdout_sink)); #endif - auto& helpers = paths.get_cmake_script_hashes(); - for (auto&& helper : helpers) - { - if (Strings::case_insensitive_ascii_contains(portfile_cmake_contents, helper.first)) - { - abi_tag_entries.emplace_back(helper.first, helper.second); - } - } - abi_tag_entries.emplace_back("ports.cmake", paths.get_ports_cmake_hash().to_string()); abi_tag_entries.emplace_back("post_build_checks", "2"); InternalFeatureSet sorted_feature_list = action.feature_list; @@ -1210,9 +1218,9 @@ namespace vcpkg &triplet_abi, Hash::get_file_hash(fs, abi_file_path, Hash::Algorithm::Sha256).value_or_exit(VCPKG_LINE_INFO), abi_file_path, - std::move(files), - std::move(hashes), - run_resource_heuristics(portfile_cmake_contents)}; + cache_entry.files, + cache_entry.hashes, + cache_entry.heuristic_resources}; } Debug::println( @@ -1222,10 +1230,13 @@ namespace vcpkg return nullopt; } + PortAbiCache::AbiCacheEntry& PortAbiCache::get(const Path& port_dir) const { return items[port_dir.native()]; } + void compute_all_abis(const VcpkgPaths& paths, ActionPlan& action_plan, const CMakeVars::CMakeVarProvider& var_provider, - const StatusParagraphs& status_db) + const StatusParagraphs& status_db, + const PortAbiCache& cache) { for (auto it = action_plan.install_actions.begin(); it != action_plan.install_actions.end(); ++it) { @@ -1268,7 +1279,7 @@ namespace vcpkg paths, action.spec.triplet(), var_provider.get_tag_vars(action.spec).value_or_exit(VCPKG_LINE_INFO)); abi_info.toolset = paths.get_toolset(*abi_info.pre_build_info); - auto maybe_abi_tag_and_file = compute_abi_tag(paths, action, dependency_abis); + auto maybe_abi_tag_and_file = compute_abi_tag(paths, action, dependency_abis, cache); if (auto p = maybe_abi_tag_and_file.get()) { abi_info.compiler_info = paths.get_compiler_info(abi_info); From 600a6d7af56bdd230651317f9b93037363fa7ffd Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 23 May 2023 16:25:02 +0200 Subject: [PATCH 44/69] Batch binary caching pre checks to improve speed. --- include/vcpkg/binarycaching.h | 2 +- src/vcpkg/binarycaching.cpp | 8 +++--- src/vcpkg/commands.ci.cpp | 3 +- src/vcpkg/commands.test-features.cpp | 43 +++++++++++++++++++++------- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/include/vcpkg/binarycaching.h b/include/vcpkg/binarycaching.h index 2cf08722d1..1241bf3a6c 100644 --- a/include/vcpkg/binarycaching.h +++ b/include/vcpkg/binarycaching.h @@ -187,7 +187,7 @@ namespace vcpkg /// Checks whether the `actions` are present in the cache, without restoring them. Used by CI to determine /// missing packages. /// Returns a vector where each index corresponds to the matching index in `actions`. - std::vector precheck(View actions); + std::vector precheck(View actions); void clear_cache(); diff --git a/src/vcpkg/binarycaching.cpp b/src/vcpkg/binarycaching.cpp index 9d14de076f..3fbe1d3077 100644 --- a/src/vcpkg/binarycaching.cpp +++ b/src/vcpkg/binarycaching.cpp @@ -2083,11 +2083,11 @@ namespace vcpkg } } - std::vector ReadOnlyBinaryCache::precheck(View actions) + std::vector ReadOnlyBinaryCache::precheck(View actions) { std::vector statuses = Util::fmap(actions, [this](const auto& action) { - if (!action.package_abi()) Checks::unreachable(VCPKG_LINE_INFO); - return &m_status[*action.package_abi().get()]; + Checks::check_exit(VCPKG_LINE_INFO, action && action->package_abi()); + return &m_status[*action->package_abi().get()]; }); std::vector action_ptrs; @@ -2102,7 +2102,7 @@ namespace vcpkg { if (statuses[i]->should_attempt_precheck(provider.get())) { - action_ptrs.push_back(&actions[i]); + action_ptrs.push_back(actions[i]); cache_result.push_back(CacheAvailability::unknown); indexes.push_back(i); } diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 809614030c..84112bd372 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -447,7 +447,8 @@ namespace vcpkg::Commands::CI auto action_plan = compute_full_plan(paths, provider, var_provider, all_default_full_specs, serialize_options); auto binary_cache = BinaryCache::make(args, paths, stdout_sink).value_or_exit(VCPKG_LINE_INFO); - const auto precheck_results = binary_cache.precheck(action_plan.install_actions); + auto install_actions = Util::fmap(action_plan.install_actions, [](const auto& action) { return &action; }); + const auto precheck_results = binary_cache.precheck(install_actions); auto split_specs = compute_action_statuses( ExclusionPredicate{&exclusions_map}, var_provider, precheck_results, known_failures, action_plan); diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 38d0b5e47a..678066b133 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -280,20 +280,44 @@ namespace vcpkg::Commands::TestFeatures } } fmt::print("compute {} install plans\n", specs_to_test.size()); + + std::vector specs; + std::vector actions; CreateInstallPlanOptions install_plan_options{host_triplet, paths.packages(), UnsupportedPortAction::Warn}; auto install_plans = Util::fmap(specs_to_test, [&](auto& spec) { - return std::make_pair( - spec, - create_feature_install_plan( - provider, var_provider, Span(&spec, 1), {}, install_plan_options)); + auto install_plan = create_feature_install_plan( + provider, var_provider, Span(&spec, 1), {}, install_plan_options); + if (install_plan.unsupported_features.empty()) + { + for (auto& actions : install_plan.install_actions) + { + specs.emplace_back(actions.spec, actions.feature_list); + } + actions.push_back(&install_plan.install_actions.back()); + } + return std::make_pair(spec, std::move(install_plan)); }); + fmt::print("load {} tag vars\n", specs.size()); + var_provider.load_tag_vars(specs, provider, host_triplet); + + fmt::print("compute all abis ...\n"); + StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); + PortAbiCache cache; + for (auto& [spec, install_plan] : install_plans) + { + if (install_plan.unsupported_features.empty()) + { + compute_all_abis(paths, install_plan, var_provider, status_db, cache); + } + } + + fmt::print("Precheck binary cache ...\n"); + binary_cache.precheck(actions); Util::stable_sort(install_plans, [](const auto& left, const auto& right) { return left.second.install_actions.size() < right.second.install_actions.size(); }); - StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); - // test port features std::unordered_set known_failures; struct UnexpectedResult @@ -353,8 +377,6 @@ namespace vcpkg::Commands::TestFeatures handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); continue; } - var_provider.load_tag_vars(install_plan, provider, host_triplet); - compute_all_abis(paths, install_plan, var_provider, status_db); if (auto iter = Util::find_if(install_plan.install_actions, [&known_failures](const auto& install_action) { @@ -378,8 +400,9 @@ namespace vcpkg::Commands::TestFeatures continue; } - if (binary_cache.precheck({&install_plan.install_actions.back(), 1}).front() == - CacheAvailability::available) + const InstallPlanAction* action = &install_plan.install_actions.back(); + std::array actions = {action}; + if (binary_cache.precheck(actions).front() == CacheAvailability::available) { handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); continue; From 2793f04ccf355cc22aca41ffb40c10845e9c21ca Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 30 May 2023 22:35:18 +0200 Subject: [PATCH 45/69] BinaryCaching: Only reset state to available if package was restored --- src/vcpkg/binarycaching.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vcpkg/binarycaching.cpp b/src/vcpkg/binarycaching.cpp index 3fbe1d3077..c643397eff 100644 --- a/src/vcpkg/binarycaching.cpp +++ b/src/vcpkg/binarycaching.cpp @@ -2281,7 +2281,13 @@ namespace vcpkg } } - void CacheStatus::mark_unrestored() noexcept { m_status = CacheStatusState::available; } + void CacheStatus::mark_unrestored() noexcept + { + if (m_status == CacheStatusState::restored) + { + m_status = CacheStatusState::available; + } + } const IReadBinaryProvider* CacheStatus::get_available_provider() const noexcept { From e774fb73a52a7e99881bd76b08c1591fcc0ea739 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 31 May 2023 06:06:45 +0200 Subject: [PATCH 46/69] Fix msvc warning --- src/vcpkg/commands.test-features.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 678066b133..32b999a7c6 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -282,7 +282,7 @@ namespace vcpkg::Commands::TestFeatures fmt::print("compute {} install plans\n", specs_to_test.size()); std::vector specs; - std::vector actions; + std::vector actions_to_check; CreateInstallPlanOptions install_plan_options{host_triplet, paths.packages(), UnsupportedPortAction::Warn}; auto install_plans = Util::fmap(specs_to_test, [&](auto& spec) { auto install_plan = create_feature_install_plan( @@ -293,7 +293,7 @@ namespace vcpkg::Commands::TestFeatures { specs.emplace_back(actions.spec, actions.feature_list); } - actions.push_back(&install_plan.install_actions.back()); + actions_to_check.push_back(&install_plan.install_actions.back()); } return std::make_pair(spec, std::move(install_plan)); }); @@ -312,7 +312,7 @@ namespace vcpkg::Commands::TestFeatures } fmt::print("Precheck binary cache ...\n"); - binary_cache.precheck(actions); + binary_cache.precheck(actions_to_check); Util::stable_sort(install_plans, [](const auto& left, const auto& right) { return left.second.install_actions.size() < right.second.install_actions.size(); From c525294afeea5ada3b3626b71d74030169d3018b Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 31 May 2023 12:08:59 +0200 Subject: [PATCH 47/69] Fix msvc warning --- src/vcpkg/commands.test-features.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 32b999a7c6..87a67cc8bd 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -400,12 +400,14 @@ namespace vcpkg::Commands::TestFeatures continue; } - const InstallPlanAction* action = &install_plan.install_actions.back(); - std::array actions = {action}; - if (binary_cache.precheck(actions).front() == CacheAvailability::available) { - handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); - continue; + const InstallPlanAction* action = &install_plan.install_actions.back(); + std::array actions = {action}; + if (binary_cache.precheck(actions).front() == CacheAvailability::available) + { + handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline); + continue; + } } msg::write_unlocalized_text_to_stdout(Color::none, Strings::concat("Test feature ", spec, '\n')); for (auto&& action : install_plan.install_actions) From 6d6f8a95aa12a38b66a2a79bd9e2defe4aaa5be2 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 6 Jun 2023 21:04:21 +0200 Subject: [PATCH 48/69] Fix msvc warning --- src/vcpkg/binarycaching.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vcpkg/binarycaching.cpp b/src/vcpkg/binarycaching.cpp index c643397eff..c08d740aa0 100644 --- a/src/vcpkg/binarycaching.cpp +++ b/src/vcpkg/binarycaching.cpp @@ -2087,6 +2087,7 @@ namespace vcpkg { std::vector statuses = Util::fmap(actions, [this](const auto& action) { Checks::check_exit(VCPKG_LINE_INFO, action && action->package_abi()); + ASSUME(action); return &m_status[*action->package_abi().get()]; }); From 92de08a026f2df5cddc93039c2055b83d513bbb5 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 6 Jun 2023 21:54:30 +0200 Subject: [PATCH 49/69] Localisation --- include/vcpkg/base/message-data.inc.h | 4 ++++ locales/messages.json | 6 ++++++ src/vcpkg/commands.test-features.cpp | 11 +++++------ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index e44617d9aa..bf1a52a3e3 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -619,6 +619,8 @@ DECLARE_MESSAGE(ComparingUtf8Decoders, "", "Comparing Utf8Decoders with different provenance; this is always an error") DECLARE_MESSAGE(CompressFolderFailed, (msg::path), "", "Failed to compress folder \"{path}\":") +DECLARE_MESSAGE(ComputeAllAbis, (), "", "Compute all abis ...") +DECLARE_MESSAGE(ComputeInstallPlans, (msg::count), "", "Compute {count} install plans ...") DECLARE_MESSAGE(ComputingInstallPlan, (), "", "Computing installation plan...") DECLARE_MESSAGE(ConfigurationErrorRegistriesWithoutBaseline, (msg::path, msg::url), @@ -2219,6 +2221,7 @@ DECLARE_MESSAGE(PortMissingManifest, (msg::package_name, msg::path), "", "{package_name} has no vcpkg.json or CONTROL file in {path}") +DECLARE_MESSAGE(PortNotSupported, (msg::package_name, msg::triplet), "", "{package_name} is not supported on {triplet}") DECLARE_MESSAGE(PortsNoDiff, (), "", "There were no changes in the ports between the two commits.") DECLARE_MESSAGE(PortsRemoved, (msg::count), "", "The following {count} ports were removed:") DECLARE_MESSAGE(PortsUpdated, (msg::count), "", "\nThe following {count} ports were updated:") @@ -2229,6 +2232,7 @@ DECLARE_MESSAGE(PortVersionMultipleSpecification, "", "\"port_version\" cannot be combined with an embedded '#' in the version") DECLARE_MESSAGE(PrebuiltPackages, (), "", "There are packages that have not been built. To build them run:") +DECLARE_MESSAGE(PrecheckBinaryCache, (), "", "Check the binary cache") DECLARE_MESSAGE(PreviousIntegrationFileRemains, (), "", "Previous integration file was not removed.") DECLARE_MESSAGE(ProgramReturnedNonzeroExitCode, (msg::tool_name, msg::exit_code), diff --git a/locales/messages.json b/locales/messages.json index cb5fa4438d..444847a2a5 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -362,6 +362,9 @@ "ComparingUtf8Decoders": "Comparing Utf8Decoders with different provenance; this is always an error", "CompressFolderFailed": "Failed to compress folder \"{path}\":", "_CompressFolderFailed.comment": "An example of {path} is /foo/bar.", + "ComputeAllAbis": "Compute all abis ...", + "ComputeInstallPlans": "Compute {count} install plans ...", + "_ComputeInstallPlans.comment": "An example of {count} is 42.", "ComputingInstallPlan": "Computing installation plan...", "ConfigurationErrorRegistriesWithoutBaseline": "The configuration defined in {path} is invalid.\n\nUsing registries requires that a baseline is set for the default registry or that the default registry is null.\n\nSee {url} for more details.", "_ConfigurationErrorRegistriesWithoutBaseline.comment": "An example of {path} is /foo/bar. An example of {url} is https://github.com/microsoft/vcpkg.", @@ -1222,6 +1225,8 @@ "_PortMissingManifest.comment": "An example of {package_name} is zlib. An example of {path} is /foo/bar.", "PortNotInBaseline": "the baseline does not contain an entry for port {package_name}", "_PortNotInBaseline.comment": "An example of {package_name} is zlib.", + "PortNotSupported": "{package_name} is not supported on {triplet}", + "_PortNotSupported.comment": "An example of {package_name} is zlib. An example of {triplet} is x64-windows.", "PortSupportsField": "(supports: \"{supports_expression}\")", "_PortSupportsField.comment": "An example of {supports_expression} is windows & !static.", "PortVersionConflict": "The following packages differ from their port versions:", @@ -1235,6 +1240,7 @@ "PortsUpdated": "\nThe following {count} ports were updated:", "_PortsUpdated.comment": "An example of {count} is 42.", "PrebuiltPackages": "There are packages that have not been built. To build them run:", + "PrecheckBinaryCache": "Check the binary cache", "PreviousIntegrationFileRemains": "Previous integration file was not removed.", "ProgramReturnedNonzeroExitCode": "{tool_name} failed with exit code: ({exit_code}).", "_ProgramReturnedNonzeroExitCode.comment": "The program's console output is appended after this. An example of {tool_name} is aria2. An example of {exit_code} is 127.", diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 5852960cff..22e81f015d 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -227,7 +227,8 @@ namespace vcpkg::Commands::TestFeatures const auto dep_info_vars = var_provider.get_or_load_dep_info_vars(package_spec, host_triplet); if (!port->core_paragraph->supports_expression.evaluate(dep_info_vars)) { - fmt::print("Port {} is not supported on {}\n", port->core_paragraph->name, target_triplet); + msg::println( + msgPortNotSupported, msg::package_name = port->core_paragraph->name, msg::triplet = target_triplet); continue; } if (test_feature_core && !Util::Sets::contains(baseline.skip_features, "core")) @@ -279,7 +280,7 @@ namespace vcpkg::Commands::TestFeatures specs_to_test.emplace_back(package_spec, all_features); } } - fmt::print("compute {} install plans\n", specs_to_test.size()); + msg::println(msgComputeInstallPlans, msg::count = specs_to_test.size()); std::vector specs; std::vector actions_to_check; @@ -297,10 +298,8 @@ namespace vcpkg::Commands::TestFeatures } return std::make_pair(spec, std::move(install_plan)); }); - fmt::print("load {} tag vars\n", specs.size()); + msg::println(msgComputeAllAbis); var_provider.load_tag_vars(specs, provider, host_triplet); - - fmt::print("compute all abis ...\n"); StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); PortAbiCache cache; for (auto& [spec, install_plan] : install_plans) @@ -311,7 +310,7 @@ namespace vcpkg::Commands::TestFeatures } } - fmt::print("Precheck binary cache ...\n"); + msg::println(msgPrecheckBinaryCache); binary_cache.precheck(actions_to_check); Util::stable_sort(install_plans, [](const auto& left, const auto& right) { From 1dc966305a7bbd1b6e75e0de026873b2c5250783 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 6 Jun 2023 22:18:37 +0200 Subject: [PATCH 50/69] More localization --- include/vcpkg/base/message-data.inc.h | 4 ++++ locales/messages.json | 2 ++ src/vcpkg/commands.test-features.cpp | 16 +++++++--------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index bf1a52a3e3..5714c253a6 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -2479,6 +2479,10 @@ DECLARE_MESSAGE(UnexpectedPortversion, (), "'field' means a JSON key/value pair here", "unexpected \"port-version\" without a versioning field") +DECLARE_MESSAGE(UnexpectedState, + (msg::feature_spec, msg::actual, msg::elapsed), + "{actual} is the actual state, e.g. 'pass', 'skip', ...", + "{feature_spec} resulted in the unexpected state {actual} after {elapsed}") DECLARE_MESSAGE(UnexpectedSwitch, (msg::option), "Switch is a command line switch like --switch", diff --git a/locales/messages.json b/locales/messages.json index 444847a2a5..5edb80b92e 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -1392,6 +1392,8 @@ "_UnexpectedPortName.comment": "{expected} is the expected port and {actual} is the port declared by the user. An example of {path} is /foo/bar.", "UnexpectedPortversion": "unexpected \"port-version\" without a versioning field", "_UnexpectedPortversion.comment": "'field' means a JSON key/value pair here", + "UnexpectedState": "{feature_spec} resulted in the unexpected state {actual} after {elapsed}", + "_UnexpectedState.comment": "{actual} is the actual state, e.g. 'pass', 'skip', ... An example of {feature_spec} is zlib[featurea,featureb]. An example of {elapsed} is 3.532 min.", "UnexpectedSwitch": "unexpected switch: {option}", "_UnexpectedSwitch.comment": "Switch is a command line switch like --switch An example of {option} is editable.", "UnexpectedToolOutput": "{tool_name} ({path}) produced unexpected output when attempting to determine the version:", diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 22e81f015d..6080bf893c 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -480,15 +480,13 @@ namespace vcpkg::Commands::TestFeatures for (const auto& result : unexpected_states) { - msg::write_unlocalized_text_to_stderr(Color::error, - Strings::concat(result.spec, - " resulted in the unexpected state ", - result.actual_state, - " ", - result.logs_dir.value_or(""), - " after ", - result.build_time.to_string(), - '\n')); + msg::println(Color::error, + msg::format(msgUnexpectedState, + msg::feature_spec = to_string(result.spec), + msg::actual = to_string(result.actual_state), + msg::elapsed = result.build_time) + .append_raw(" ") + .append_raw(result.logs_dir.value_or(""))); } auto it_output_file = settings.find(OPTION_OUTPUT_FAILURE_ABIS); From 3b21335876eea03ff120c1f9314e05f32d2c24d2 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Mon, 12 Jun 2023 11:25:23 +0200 Subject: [PATCH 51/69] More localization --- include/vcpkg/base/message-data.inc.h | 1 + locales/messages.json | 1 + src/vcpkg/commands.test-features.cpp | 5 ++++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 5714c253a6..a4a9f2338d 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -98,6 +98,7 @@ DECLARE_MESSAGE(AGitObjectSha, (), "", "a git object SHA") DECLARE_MESSAGE(AGitReference, (), "", "a git reference (for example, a branch)") DECLARE_MESSAGE(AGitRegistry, (), "", "a git registry") DECLARE_MESSAGE(AGitRepositoryUrl, (), "", "a git repository URL") +DECLARE_MESSAGE(AllFeatureTestsPassed, (), "", "All feature tests passed.") DECLARE_MESSAGE(AllFormatArgsRawArgument, (msg::value), "example of {value} is 'foo {} bar'", diff --git a/locales/messages.json b/locales/messages.json index 5edb80b92e..6109a3c9ac 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -102,6 +102,7 @@ "_AddingCompletionEntry.comment": "An example of {path} is /foo/bar.", "AdditionalPackagesToExport": "Additional packages (*) need to be exported to complete this operation.", "AdditionalPackagesToRemove": "Additional packages (*) need to be removed to complete this operation.", + "AllFeatureTestsPassed": "All feature tests passed.", "AllFormatArgsRawArgument": "format string \"{value}\" contains a raw format argument", "_AllFormatArgsRawArgument.comment": "example of {value} is 'foo {} bar'", "AllFormatArgsUnbalancedBraces": "unbalanced brace in format string \"{value}\"", diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 6080bf893c..5a2e74bc26 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -408,7 +408,6 @@ namespace vcpkg::Commands::TestFeatures continue; } } - msg::write_unlocalized_text_to_stdout(Color::none, Strings::concat("Test feature ", spec, '\n')); for (auto&& action : install_plan.install_actions) { action.build_options = backcompat_prohibiting_package_options; @@ -488,6 +487,10 @@ namespace vcpkg::Commands::TestFeatures .append_raw(" ") .append_raw(result.logs_dir.value_or(""))); } + if (unexpected_states.empty()) + { + msg::println(msgAllFeatureTestsPassed); + } auto it_output_file = settings.find(OPTION_OUTPUT_FAILURE_ABIS); if (it_output_file != settings.end()) From fe08c5e81306ba77c08f151a59d91ea8a399edf4 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 13 Jun 2023 19:28:33 +0200 Subject: [PATCH 52/69] Fix build --- src/vcpkg/commands.test-features.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 5a2e74bc26..b2c1fc75cb 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -72,7 +72,7 @@ namespace } } - CiBuildLogsRecorder create_for_feature_test(const FullPackageSpec& spec, Filesystem& filesystem) const + CiBuildLogsRecorder create_for_feature_test(const FullPackageSpec& spec, const Filesystem& filesystem) const { static int counter = 0; std::string feature; From d6f922b4f85ff7da89000ca067df4d90a12a88cf Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Fri, 16 Jun 2023 16:21:02 +0200 Subject: [PATCH 53/69] If the first tested feature is an expected cascade the whole tested feature spec is an expected cascade because other feature are only added by options --- src/vcpkg/commands.test-features.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index b2c1fc75cb..d3ab77b486 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -336,9 +336,7 @@ namespace vcpkg::Commands::TestFeatures ElapsedTime build_time = {}) { bool expected_cascade = (baseline.state == CiFeatureBaselineState::Cascade || - (spec.features.size() > 1 && Util::all_of(spec.features, [&](const auto& feature) { - return feature == "core" || Util::Sets::contains(baseline.cascade_features, feature); - }))); + (spec.features.size() > 1 && Util::Sets::contains(baseline.cascade_features, spec.features[1]))); bool actual_cascade = (result == CiFeatureBaselineState::Cascade); if (actual_cascade != expected_cascade) { From ff9a23e1f032f1bc01b372997e7cc1e7eb78e21e Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 17 Jun 2023 00:46:11 +0200 Subject: [PATCH 54/69] Emit error is feature is specified as cascade and feature-fails --- include/vcpkg/base/message-data.inc.h | 4 ++++ src/vcpkg/ci-feature-baseline.cpp | 27 ++++++++++++++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index f09166b87b..3402a77be6 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -1028,6 +1028,10 @@ DECLARE_MESSAGE(FailedVendorAuthentication, "", "One or more {vendor} credential providers failed to authenticate. See '{url}' for more details " "on how to provide credentials.") +DECLARE_MESSAGE(FeatureBaselineEntryAlreadySpecified, + (msg::feature, msg::value), + "{value} is a keyword", + "Feature '{feature}' was already declared as '{value}'.") DECLARE_MESSAGE(FeatureBaselineExpectedFeatures, (msg::value), "{value} is a keyword", diff --git a/src/vcpkg/ci-feature-baseline.cpp b/src/vcpkg/ci-feature-baseline.cpp index 1bde1c7f6c..9657ce12d3 100644 --- a/src/vcpkg/ci-feature-baseline.cpp +++ b/src/vcpkg/ci-feature-baseline.cpp @@ -171,31 +171,44 @@ namespace vcpkg if (spec.features.has_value()) { auto& features = *spec.features.get(); + auto& entry = result.ports[spec.name]; + const auto error_if_already_defined = [&](const auto& set, auto state) { + if (auto iter = Util::find_if( + features, [&](const auto& feature) { return Util::Sets::contains(set, feature); }); + iter != features.end()) + { + parser.add_error(msg::format(msgFeatureBaselineEntryAlreadySpecified, + msg::feature = *iter, + msg::value = (names[static_cast(state)])), + cur_loc); + } + }; if (state == CiFeatureBaselineState::Skip) { - result.ports[spec.name].skip_features.insert(features.begin(), features.end()); + entry.skip_features.insert(features.begin(), features.end()); } else if (state == CiFeatureBaselineState::Cascade) { - result.ports[spec.name].cascade_features.insert(features.begin(), features.end()); + error_if_already_defined(entry.failing_features, FEATURE_FAIL_STATE); + entry.cascade_features.insert(features.begin(), features.end()); } else if (state == COMBINATION_FAIL_STATE) { + error_if_already_defined(entry.cascade_features, CiFeatureBaselineState::Cascade); features.emplace_back("core"); - result.ports[spec.name].fail_configurations.push_back( - Util::sort_unique_erase(std::move(features))); + entry.fail_configurations.push_back(Util::sort_unique_erase(std::move(features))); } else if (state == FEATURE_FAIL_STATE) { - result.ports[spec.name].failing_features.insert(features.begin(), features.end()); + entry.failing_features.insert(features.begin(), features.end()); } else if (state == NO_TEST_STATE) { - result.ports[spec.name].no_separate_feature_test.insert(features.begin(), features.end()); + entry.no_separate_feature_test.insert(features.begin(), features.end()); } else if (state == OPTIONS_STATE) { - result.ports[spec.name].options.push_back(features); + entry.options.push_back(features); } } else From 6d46b6af3d69621d3f380ea4edab22517e8f727d Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 17 Jun 2023 01:15:27 +0200 Subject: [PATCH 55/69] Trigger Build From 3616c9a55a677d70feabb061800d2f69acf8eda6 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 17 Jun 2023 10:22:26 +0200 Subject: [PATCH 56/69] Add message map --- locales/messages.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/locales/messages.json b/locales/messages.json index a0dc32dca8..34c6c4bfda 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -645,6 +645,8 @@ "_FailedToWriteManifest.comment": "An example of {path} is /foo/bar.", "FailedVendorAuthentication": "One or more {vendor} credential providers failed to authenticate. See '{url}' for more details on how to provide credentials.", "_FailedVendorAuthentication.comment": "An example of {vendor} is Azure. An example of {url} is https://github.com/microsoft/vcpkg.", + "FeatureBaselineEntryAlreadySpecified": "Feature '{feature}' was already declared as '{value}'.", + "_FeatureBaselineEntryAlreadySpecified.comment": "{value} is a keyword An example of {feature} is avisynthplus.", "FeatureBaselineExpectedFeatures": "When using '{value}' a list of features must be specified.", "_FeatureBaselineExpectedFeatures.comment": "{value} is a keyword", "FeatureBaselineNoFeaturesForFail": "When using '= fail' no list of features is allowed.", From 7de7b895ed2c53d674f5003b91290eaa3e388ccf Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 21 Jun 2023 14:26:57 +0200 Subject: [PATCH 57/69] Remove unnecessary changes --- src/vcpkg/commands.ci.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 93981f088a..69cc126efb 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -42,7 +42,9 @@ namespace { CiBuildLogsRecorder(const Path& base_path_) : base_path(base_path_) { } - void record_build_result(const VcpkgPaths& paths, const PackageSpec& spec, BuildResult result) const override + virtual void record_build_result(const VcpkgPaths& paths, + const PackageSpec& spec, + BuildResult result) const override { if (result == BuildResult::SUCCEEDED) { @@ -54,7 +56,7 @@ namespace auto children = filesystem.get_regular_files_non_recursive(source_path, IgnoreErrors{}); Util::erase_remove_if(children, NotExtensionCaseInsensitive{".log"}); const auto target_path = base_path / spec.name(); - (void)filesystem.create_directories(target_path, VCPKG_LINE_INFO); + (void)filesystem.create_directory(target_path, VCPKG_LINE_INFO); if (children.empty()) { std::string message = @@ -74,6 +76,7 @@ namespace } } + private: Path base_path; }; } @@ -410,6 +413,9 @@ namespace vcpkg::Commands::CI } } + const IBuildLogsRecorder& build_logs_recorder = + build_logs_recorder_storage ? *(build_logs_recorder_storage.get()) : null_build_logs_recorder(); + auto registry_set = paths.make_registry_set(); PathsPortFileProvider provider( filesystem, *registry_set, make_overlay_provider(filesystem, paths.original_cwd, paths.overlay_ports)); @@ -510,6 +516,7 @@ namespace vcpkg::Commands::CI return abi->string(VCPKG_LINE_INFO).to_string(); }); } + reduce_action_plan(action_plan, split_specs->known, parent_hashes); msg::println(msgElapsedTimeForChecks, msg::elapsed = timer.elapsed()); @@ -528,10 +535,6 @@ namespace vcpkg::Commands::CI { msg::println_warning(msgCISkipInstallation, msg::list = Strings::join(", ", already_installed)); } - - const IBuildLogsRecorder& build_logs_recorder = - build_logs_recorder_storage ? *(build_logs_recorder_storage.get()) : null_build_logs_recorder(); - Install::preclear_packages(paths, action_plan); binary_cache.fetch(action_plan.install_actions); auto summary = Install::execute_plan( From 948a7ba5068e4d65f10674ddc800280d87a41d0e Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 28 Jun 2023 00:07:58 +0200 Subject: [PATCH 58/69] Actually detect errors while parsing + detect more errors. --- src/vcpkg/ci-feature-baseline.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/vcpkg/ci-feature-baseline.cpp b/src/vcpkg/ci-feature-baseline.cpp index 9657ce12d3..04801f376d 100644 --- a/src/vcpkg/ci-feature-baseline.cpp +++ b/src/vcpkg/ci-feature-baseline.cpp @@ -181,25 +181,33 @@ namespace vcpkg msg::feature = *iter, msg::value = (names[static_cast(state)])), cur_loc); + return true; } + return false; }; if (state == CiFeatureBaselineState::Skip) { + if (error_if_already_defined(entry.failing_features, FEATURE_FAIL_STATE)) break; + if (error_if_already_defined(entry.cascade_features, CiFeatureBaselineState::Cascade)) break; entry.skip_features.insert(features.begin(), features.end()); } else if (state == CiFeatureBaselineState::Cascade) { - error_if_already_defined(entry.failing_features, FEATURE_FAIL_STATE); + if (error_if_already_defined(entry.failing_features, FEATURE_FAIL_STATE)) break; + if (error_if_already_defined(entry.skip_features, CiFeatureBaselineState::Skip)) break; entry.cascade_features.insert(features.begin(), features.end()); } else if (state == COMBINATION_FAIL_STATE) { - error_if_already_defined(entry.cascade_features, CiFeatureBaselineState::Cascade); + if (error_if_already_defined(entry.skip_features, CiFeatureBaselineState::Skip)) break; + if (error_if_already_defined(entry.cascade_features, CiFeatureBaselineState::Cascade)) break; features.emplace_back("core"); entry.fail_configurations.push_back(Util::sort_unique_erase(std::move(features))); } else if (state == FEATURE_FAIL_STATE) { + if (error_if_already_defined(entry.skip_features, CiFeatureBaselineState::Skip)) break; + if (error_if_already_defined(entry.cascade_features, CiFeatureBaselineState::Cascade)) break; entry.failing_features.insert(features.begin(), features.end()); } else if (state == NO_TEST_STATE) From 242829928c89a3a81189b0011b480ddcb53ca3cd Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 28 Jun 2023 11:06:36 +0200 Subject: [PATCH 59/69] Restore old CMakeVarProvider interface changed in #1109 --- include/vcpkg-test/mockcmakevarprovider.h | 8 +++-- include/vcpkg/cmakevars.h | 8 ++++- src/vcpkg/cmakevars.cpp | 38 +++++++++++++++++------ src/vcpkg/commands.test-features.cpp | 5 ++- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/include/vcpkg-test/mockcmakevarprovider.h b/include/vcpkg-test/mockcmakevarprovider.h index 1393a5843d..3dd263de97 100644 --- a/include/vcpkg-test/mockcmakevarprovider.h +++ b/include/vcpkg-test/mockcmakevarprovider.h @@ -19,10 +19,12 @@ namespace vcpkg::Test dep_info_vars.emplace(spec, SMap{}); } - void load_tag_vars(const ActionPlan& action_plan, Triplet host_triplet) const override + void load_tag_vars(Span specs, + Span /*port_locations*/, + Triplet host_triplet) const override { - for (auto&& install_action : action_plan.install_actions) - tag_vars.emplace(install_action.spec, SMap{}); + for (auto&& spec : specs) + tag_vars.emplace(spec.package_spec, SMap{}); (void)(host_triplet); } diff --git a/include/vcpkg/cmakevars.h b/include/vcpkg/cmakevars.h index 097cd99f3c..970216b017 100644 --- a/include/vcpkg/cmakevars.h +++ b/include/vcpkg/cmakevars.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -32,7 +34,11 @@ namespace vcpkg::CMakeVars virtual void load_dep_info_vars(Span specs, Triplet host_triplet) const = 0; - virtual void load_tag_vars(const ActionPlan& action_plan, Triplet host_triplet) const = 0; + virtual void load_tag_vars(Span specs, + Span port_locations, + Triplet host_triplet) const = 0; + + void load_tag_vars(const ActionPlan& action_plan, Triplet host_triplet) const; }; std::unique_ptr make_triplet_cmake_var_provider(const VcpkgPaths& paths); diff --git a/src/vcpkg/cmakevars.cpp b/src/vcpkg/cmakevars.cpp index d1fa63c448..6c8859cbc0 100644 --- a/src/vcpkg/cmakevars.cpp +++ b/src/vcpkg/cmakevars.cpp @@ -15,6 +15,23 @@ using namespace vcpkg; namespace vcpkg::CMakeVars { + + void CMakeVarProvider::load_tag_vars(const ActionPlan& action_plan, Triplet host_triplet) const + { + std::vector install_package_specs; + std::vector port_locations; + install_package_specs.reserve(action_plan.install_actions.size()); + port_locations.reserve(action_plan.install_actions.size()); + for (auto&& action : action_plan.install_actions) + { + install_package_specs.emplace_back(action.spec, action.feature_list); + port_locations.emplace_back( + action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_location); + } + + load_tag_vars(install_package_specs, port_locations, host_triplet); + } + const std::unordered_map& CMakeVarProvider::get_or_load_dep_info_vars( const PackageSpec& spec, Triplet host_triplet) const { @@ -39,7 +56,9 @@ namespace vcpkg::CMakeVars void load_dep_info_vars(View specs, Triplet host_triplet) const override; - void load_tag_vars(const ActionPlan& action_plan, Triplet host_triplet) const override; + void load_tag_vars(Span specs, + Span port_locations, + Triplet host_triplet) const override; Optional&> get_generic_triplet_vars( Triplet triplet) const override; @@ -358,18 +377,19 @@ endfunction() } } - void TripletCMakeVarProvider::load_tag_vars(const ActionPlan& action_plan, Triplet host_triplet) const + void TripletCMakeVarProvider::load_tag_vars(Span specs, + Span port_locations, + Triplet host_triplet) const { - if (action_plan.install_actions.empty()) return; + if (specs.empty()) return; std::vector> spec_abi_settings; - spec_abi_settings.reserve(action_plan.install_actions.size()); + spec_abi_settings.reserve(specs.size()); + Checks::check_exit(VCPKG_LINE_INFO, specs.size() == port_locations.size()); - for (const auto& install_action : action_plan.install_actions) + for (size_t i = 0; i < specs.size(); ++i) { - auto& scfl = install_action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO); - const auto override_path = scfl.source_location / "vcpkg-abi-settings.cmake"; - spec_abi_settings.emplace_back(FullPackageSpec{install_action.spec, install_action.feature_list}, - override_path.generic_u8string()); + const auto override_path = port_locations[i] / "vcpkg-abi-settings.cmake"; + spec_abi_settings.emplace_back(specs[i], override_path.generic_u8string()); } std::vector>> vars(spec_abi_settings.size()); diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index d3ab77b486..282d54a049 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -283,6 +283,7 @@ namespace vcpkg::Commands::TestFeatures msg::println(msgComputeInstallPlans, msg::count = specs_to_test.size()); std::vector specs; + std::vector port_locations; std::vector actions_to_check; CreateInstallPlanOptions install_plan_options{host_triplet, paths.packages(), UnsupportedPortAction::Warn}; auto install_plans = Util::fmap(specs_to_test, [&](auto& spec) { @@ -293,13 +294,15 @@ namespace vcpkg::Commands::TestFeatures for (auto& actions : install_plan.install_actions) { specs.emplace_back(actions.spec, actions.feature_list); + port_locations.emplace_back( + actions.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_location); } actions_to_check.push_back(&install_plan.install_actions.back()); } return std::make_pair(spec, std::move(install_plan)); }); msg::println(msgComputeAllAbis); - var_provider.load_tag_vars(specs, provider, host_triplet); + var_provider.load_tag_vars(specs, port_locations, host_triplet); StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); PortAbiCache cache; for (auto& [spec, install_plan] : install_plans) From f003d3390d9b346e8c8d083390f7a7399c12878f Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 28 Jun 2023 13:03:14 +0200 Subject: [PATCH 60/69] More localization + more information in result text --- include/vcpkg/base/message-data.inc.h | 17 ++++++ locales/messages.json | 8 +++ src/vcpkg/commands.test-features.cpp | 84 +++++++++++++++++++-------- 3 files changed, 84 insertions(+), 25 deletions(-) diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 3402a77be6..631dedbe6d 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -738,6 +738,10 @@ DECLARE_MESSAGE(DeleteVcpkgConfigFromManifest, (msg::path), "", "-- Or remove \"vcpkg-configuration\" from the manifest file {path}.") +DECLARE_MESSAGE(DependencyWillFail, + (msg::feature_spec), + "'cascade' is a keyword and should not be translated", + "Dependency {feature_spec} will not build => cascade") DECLARE_MESSAGE(DeprecatedPrefabDebugOption, (), "", "--prefab-debug is now deprecated.") DECLARE_MESSAGE(DetectCompilerHash, (msg::triplet), "", "Detecting compiler hash for triplet {triplet}...") DECLARE_MESSAGE(DocumentedFieldsSuggestUpdate, @@ -1943,6 +1947,10 @@ DECLARE_MESSAGE(NugetTimeoutExpectsSinglePositiveInteger, (), "", "unexpected arguments: binary config 'nugettimeout' expects a single positive integer argument") +DECLARE_MESSAGE(OnlySupports, + (msg::feature_spec, msg::supports_expression), + "", + "{feature_spec} only supports {supports_expression}") DECLARE_MESSAGE(OptionalCommand, (), "", "optional command") DECLARE_MESSAGE(OptionMustBeInteger, (msg::option), "", "Value of --{option} must be an integer.") DECLARE_MESSAGE(OptionRequired, (msg::option), "", "--{option} option is required.") @@ -2335,6 +2343,10 @@ DECLARE_MESSAGE(SkipClearingInvalidDir, (msg::path), "", "Skipping clearing contents of {path} because it was not a directory.") +DECLARE_MESSAGE(SkipTestingOfPort, + (msg::feature_spec, msg::triplet), + "", + "Skipping testing of {feature_spec} because the following dependencies are not supported on {triplet}:") DECLARE_MESSAGE(SourceFieldPortNameMismatch, (msg::package_name, msg::path), "{package_name} and \"{path}\" are both names of installable ports/packages. 'Source', " @@ -2488,6 +2500,11 @@ DECLARE_MESSAGE(UnexpectedState, (msg::feature_spec, msg::actual, msg::elapsed), "{actual} is the actual state, e.g. 'pass', 'skip', ...", "{feature_spec} resulted in the unexpected state {actual} after {elapsed}") +DECLARE_MESSAGE(UnexpectedStateCascase, + (msg::feature_spec, msg::actual), + "{actual} is the actual state, e.g. 'pass', 'skip', ...", + "{feature_spec} resulted in the unexpected state {actual} because the following " + "dependencies did not build:") DECLARE_MESSAGE(UnexpectedSwitch, (msg::option), "Switch is a command line switch like --switch", diff --git a/locales/messages.json b/locales/messages.json index 34c6c4bfda..acdb03da33 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -435,6 +435,8 @@ "_DefaultTriplet.comment": "An example of {triplet} is x64-windows.", "DeleteVcpkgConfigFromManifest": "-- Or remove \"vcpkg-configuration\" from the manifest file {path}.", "_DeleteVcpkgConfigFromManifest.comment": "An example of {path} is /foo/bar.", + "DependencyWillFail": "Dependency {feature_spec} will not build => cascade", + "_DependencyWillFail.comment": "'cascade' is a keyword and should not be translated An example of {feature_spec} is zlib[featurea,featureb].", "DeprecatedPrefabDebugOption": "--prefab-debug is now deprecated.", "DetectCompilerHash": "Detecting compiler hash for triplet {triplet}...", "_DetectCompilerHash.comment": "An example of {triplet} is x64-windows.", @@ -1092,6 +1094,8 @@ "NugetPackageFileSucceededButCreationFailed": "NuGet package creation succeeded, but no .nupkg was produced. Expected: \"{path}\"", "_NugetPackageFileSucceededButCreationFailed.comment": "An example of {path} is /foo/bar.", "NugetTimeoutExpectsSinglePositiveInteger": "unexpected arguments: binary config 'nugettimeout' expects a single positive integer argument", + "OnlySupports": "{feature_spec} only supports {supports_expression}", + "_OnlySupports.comment": "An example of {feature_spec} is zlib[featurea,featureb]. An example of {supports_expression} is windows & !static.", "OptionMustBeInteger": "Value of --{option} must be an integer.", "_OptionMustBeInteger.comment": "An example of {option} is editable.", "OptionRequired": "--{option} option is required.", @@ -1292,6 +1296,8 @@ "_ShallowRepositoryDetected.comment": "An example of {path} is /foo/bar.", "SkipClearingInvalidDir": "Skipping clearing contents of {path} because it was not a directory.", "_SkipClearingInvalidDir.comment": "An example of {path} is /foo/bar.", + "SkipTestingOfPort": "Skipping testing of {feature_spec} because the following dependencies are not supported on {triplet}:", + "_SkipTestingOfPort.comment": "An example of {feature_spec} is zlib[featurea,featureb]. An example of {triplet} is x64-windows.", "SourceFieldPortNameMismatch": "The 'Source' field inside the CONTROL file, or \"name\" field inside the vcpkg.json file has the name {package_name} and does not match the port directory \"{path}\".", "_SourceFieldPortNameMismatch.comment": "{package_name} and \"{path}\" are both names of installable ports/packages. 'Source', 'CONTROL', 'vcpkg.json', and 'name' references are locale-invariant. An example of {package_name} is zlib. An example of {path} is /foo/bar.", "SpecifiedFeatureTurnedOff": "'{command_name}' feature specifically turned off, but --{option} was specified.", @@ -1397,6 +1403,8 @@ "_UnexpectedPortversion.comment": "'field' means a JSON key/value pair here", "UnexpectedState": "{feature_spec} resulted in the unexpected state {actual} after {elapsed}", "_UnexpectedState.comment": "{actual} is the actual state, e.g. 'pass', 'skip', ... An example of {feature_spec} is zlib[featurea,featureb]. An example of {elapsed} is 3.532 min.", + "UnexpectedStateCascase": "{feature_spec} resulted in the unexpected state {actual} because the following dependencies did not build:", + "_UnexpectedStateCascase.comment": "{actual} is the actual state, e.g. 'pass', 'skip', ... An example of {feature_spec} is zlib[featurea,featureb].", "UnexpectedSwitch": "unexpected switch: {option}", "_UnexpectedSwitch.comment": "Switch is a command line switch like --switch An example of {option} is editable.", "UnexpectedToolOutput": "{tool_name} ({path}) produced unexpected output when attempting to determine the version:", diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 282d54a049..1ddd3ca176 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -328,6 +328,7 @@ namespace vcpkg::Commands::TestFeatures CiFeatureBaselineState actual_state; Optional logs_dir; ElapsedTime build_time; + std::string cascade_reason; }; std::vector unexpected_states; @@ -335,6 +336,7 @@ namespace vcpkg::Commands::TestFeatures const auto handle_result = [&](FullPackageSpec&& spec, CiFeatureBaselineState result, CiFeatureBaselineEntry baseline, + std::string cascade_reason = {}, Optional logs_dir = nullopt, ElapsedTime build_time = {}) { bool expected_cascade = @@ -343,14 +345,16 @@ namespace vcpkg::Commands::TestFeatures bool actual_cascade = (result == CiFeatureBaselineState::Cascade); if (actual_cascade != expected_cascade) { - unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir, build_time}); + unexpected_states.push_back( + UnexpectedResult{std::move(spec), result, logs_dir, build_time, std::move(cascade_reason)}); return; } bool expected_fail = (baseline.state == CiFeatureBaselineState::Fail || baseline.will_fail(spec.features)); bool actual_fail = (result == CiFeatureBaselineState::Fail); if (expected_fail != actual_fail) { - unexpected_states.push_back(UnexpectedResult{std::move(spec), result, logs_dir, build_time}); + unexpected_states.push_back( + UnexpectedResult{std::move(spec), result, logs_dir, build_time, std::move(cascade_reason)}); } }; @@ -363,18 +367,21 @@ namespace vcpkg::Commands::TestFeatures if (!install_plan.unsupported_features.empty()) { - std::string out; + std::vector out; for (const auto& entry : install_plan.unsupported_features) { - Strings::append(out, entry.first, " only supported on ", to_string(entry.second), '\n'); + out.push_back(msg::format(msgOnlySupports, + msg::feature_spec = entry.first.to_string(), + msg::supports_expression = to_string(entry.second)) + .extract_data()); } - msg::write_unlocalized_text_to_stdout(Color::none, - Strings::concat("Skipping testing of ", - install_plan.install_actions.back().displayname(), - " because of the following warnings: \n", - out, - '\n')); - handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); + msg::print(msg::format(msgSkipTestingOfPort, + msg::feature_spec = install_plan.install_actions.back().displayname(), + msg::triplet = target_triplet) + .append_raw('\n') + .append_raw(Strings::join("\n", out)) + .append_raw('\n')); + handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline, Strings::join(", ", out)); continue; } @@ -386,9 +393,8 @@ namespace vcpkg::Commands::TestFeatures }); iter != install_plan.install_actions.end()) { - msg::write_unlocalized_text_to_stdout( - Color::none, Strings::concat(spec, " dependency ", iter->displayname(), " will fail => cascade\n")); - handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline); + msg::println(msgDependencyWillFail, msg::feature_spec = iter->displayname()); + handle_result(std::move(spec), CiFeatureBaselineState::Cascade, baseline, iter->displayname()); continue; } @@ -429,6 +435,7 @@ namespace vcpkg::Commands::TestFeatures args, install_plan, KeepGoing::YES, paths, status_db, binary_cache, build_logs_recorder); binary_cache.clear_cache(); + std::string failed_dependencies; for (const auto& result : summary.results) { switch (result.build_result.value_or_exit(VCPKG_LINE_INFO).code) @@ -445,6 +452,14 @@ namespace vcpkg::Commands::TestFeatures result.get_install_plan_action().value_or_exit(VCPKG_LINE_INFO)), VCPKG_LINE_INFO); } + if (result.get_spec() != spec.package_spec) + { + if (!failed_dependencies.empty()) + { + Strings::append(failed_dependencies, ", "); + } + Strings::append(failed_dependencies, result.get_spec()); + } [[fallthrough]]; case BuildResult::POST_BUILD_CHECKS_FAILED: known_failures.insert(result.get_abi().value_or_exit(VCPKG_LINE_INFO)); @@ -457,11 +472,16 @@ namespace vcpkg::Commands::TestFeatures { case BuildResult::DOWNLOADED: case vcpkg::BuildResult::SUCCEEDED: - handle_result(std::move(spec), CiFeatureBaselineState::Pass, baseline, logs_dir, time_to_install); + handle_result( + std::move(spec), CiFeatureBaselineState::Pass, baseline, {}, logs_dir, time_to_install); break; case vcpkg::BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES: - handle_result( - std::move(spec), CiFeatureBaselineState::Cascade, baseline, logs_dir, time_to_install); + handle_result(std::move(spec), + CiFeatureBaselineState::Cascade, + baseline, + std::move(failed_dependencies), + logs_dir, + time_to_install); break; case BuildResult::BUILD_FAILED: case BuildResult::POST_BUILD_CHECKS_FAILED: @@ -473,20 +493,34 @@ namespace vcpkg::Commands::TestFeatures { known_failures.insert(*abi); } - handle_result(std::move(spec), CiFeatureBaselineState::Fail, baseline, logs_dir, time_to_install); + handle_result( + std::move(spec), CiFeatureBaselineState::Fail, baseline, {}, logs_dir, time_to_install); break; } } + msg::println(); for (const auto& result : unexpected_states) { - msg::println(Color::error, - msg::format(msgUnexpectedState, - msg::feature_spec = to_string(result.spec), - msg::actual = to_string(result.actual_state), - msg::elapsed = result.build_time) - .append_raw(" ") - .append_raw(result.logs_dir.value_or(""))); + if (result.actual_state == CiFeatureBaselineState::Cascade && !result.cascade_reason.empty()) + { + msg::println(Color::error, + msg::format(msgUnexpectedStateCascase, + msg::feature_spec = to_string(result.spec), + msg::actual = to_string(result.actual_state)) + .append_raw(" ") + .append_raw(result.cascade_reason)); + } + else + { + msg::println(Color::error, + msg::format(msgUnexpectedState, + msg::feature_spec = to_string(result.spec), + msg::actual = to_string(result.actual_state), + msg::elapsed = result.build_time) + .append_raw(" ") + .append_raw(result.logs_dir.value_or(""))); + } } if (unexpected_states.empty()) { From e208e4d77dd80df75982f145cf9c77a4eea5e86c Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 15 Aug 2023 19:41:58 +0200 Subject: [PATCH 61/69] Fix warning --- src/vcpkg/commands.build.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vcpkg/commands.build.cpp b/src/vcpkg/commands.build.cpp index 96e1b41780..b29b5da293 100644 --- a/src/vcpkg/commands.build.cpp +++ b/src/vcpkg/commands.build.cpp @@ -1155,7 +1155,6 @@ namespace vcpkg constexpr int max_port_file_count = 100; std::string portfile_cmake_contents; - auto&& port_dir = action.source_control_file_and_location.value_or_exit(VCPKG_LINE_INFO).source_location; auto raw_files = fs.get_regular_files_recursive_lexically_proximate(port_dir, VCPKG_LINE_INFO); if (raw_files.size() > max_port_file_count) { From 3a08f95e5dd31a3ba05d15f749ad931c4e2ca826 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Mon, 28 Aug 2023 01:16:37 +0200 Subject: [PATCH 62/69] Add command to format a ci.feature.baseline.txt file --- .../ci-feature-baseline/asci-range.txt | 95 +++++++++++++++++++ .../ci-feature-baseline/ci.baseline.txt | 16 ++++ .../expected/asci-range.txt | 95 +++++++++++++++++++ .../expected/ci.baseline.txt | 16 ++++ .../expected/keep-blocks.txt | 13 +++ .../ci-feature-baseline/keep-blocks.txt | 13 +++ .../format-feature-baseline.ps1 | 19 ++++ include/vcpkg/base/message-data.inc.h | 1 + include/vcpkg/base/strings.h | 5 +- .../vcpkg/commands.format-feature-baselinet.h | 11 +++ locales/messages.json | 1 + src/vcpkg/commands.cpp | 2 + .../commands.format-feature-baseline.cpp | 88 +++++++++++++++++ 13 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 azure-pipelines/e2e-assets/ci-feature-baseline/asci-range.txt create mode 100644 azure-pipelines/e2e-assets/ci-feature-baseline/ci.baseline.txt create mode 100644 azure-pipelines/e2e-assets/ci-feature-baseline/expected/asci-range.txt create mode 100644 azure-pipelines/e2e-assets/ci-feature-baseline/expected/ci.baseline.txt create mode 100644 azure-pipelines/e2e-assets/ci-feature-baseline/expected/keep-blocks.txt create mode 100644 azure-pipelines/e2e-assets/ci-feature-baseline/keep-blocks.txt create mode 100644 azure-pipelines/end-to-end-tests-dir/format-feature-baseline.ps1 create mode 100644 include/vcpkg/commands.format-feature-baselinet.h create mode 100644 src/vcpkg/commands.format-feature-baseline.cpp diff --git a/azure-pipelines/e2e-assets/ci-feature-baseline/asci-range.txt b/azure-pipelines/e2e-assets/ci-feature-baseline/asci-range.txt new file mode 100644 index 0000000000..ac86eeb099 --- /dev/null +++ b/azure-pipelines/e2e-assets/ci-feature-baseline/asci-range.txt @@ -0,0 +1,95 @@ + Was sorted by the "Sort Lines Ascending" command in VSCode (# was excluded because it is a comment) + | 32 | 20 | 00100000 +! | 33 | 21 | 00100001 +" | 34 | 22 | 00100010 +$ | 36 | 24 | 00100100 +% | 37 | 25 | 00100101 +& | 38 | 26 | 00100110 +' | 39 | 27 | 00100111 +( | 40 | 28 | 00101000 +) | 41 | 29 | 00101001 +* | 42 | 2A | 00101010 ++ | 43 | 2B | 00101011 +, | 44 | 2C | 00101100 +- | 45 | 2D | 00101101 +. | 46 | 2E | 00101110 +/ | 47 | 2F | 00101111 +0 | 48 | 30 | 00110000 +1 | 49 | 31 | 00110001 +2 | 50 | 32 | 00110010 +3 | 51 | 33 | 00110011 +4 | 52 | 34 | 00110100 +5 | 53 | 35 | 00110101 +6 | 54 | 36 | 00110110 +7 | 55 | 37 | 00110111 +8 | 56 | 38 | 00111000 +9 | 57 | 39 | 00111001 +: | 58 | 3A | 00111010 +; | 59 | 3B | 00111011 +< | 60 | 3C | 00111100 += | 61 | 3D | 00111101 +> | 62 | 3E | 00111110 +? | 63 | 3F | 00111111 +@ | 64 | 40 | 01000000 +A | 65 | 41 | 01000001 +B | 66 | 42 | 01000010 +C | 67 | 43 | 01000011 +D | 68 | 44 | 01000100 +E | 69 | 45 | 01000101 +F | 70 | 46 | 01000110 +G | 71 | 47 | 01000111 +H | 72 | 48 | 01001000 +I | 73 | 49 | 01001001 +J | 74 | 4A | 01001010 +K | 75 | 4B | 01001011 +L | 76 | 4C | 01001100 +M | 77 | 4D | 01001101 +N | 78 | 4E | 01001110 +O | 79 | 4F | 01001111 +P | 80 | 50 | 01010000 +Q | 81 | 51 | 01010001 +R | 82 | 52 | 01010010 +S | 83 | 53 | 01010011 +T | 84 | 54 | 01010100 +U | 85 | 55 | 01010101 +V | 86 | 56 | 01010110 +W | 87 | 57 | 01010111 +X | 88 | 58 | 01011000 +Y | 89 | 59 | 01011001 +Z | 90 | 5A | 01011010 +[ | 91 | 5B | 01011011 +\ | 92 | 5C | 01011100 +] | 93 | 5D | 01011101 +^ | 94 | 5E | 01011110 +_ | 95 | 5F | 01011111 +` | 96 | 60 | 01100000 +a | 97 | 61 | 01100001 +b | 98 | 62 | 01100010 +c | 99 | 63 | 01100011 +d | 100 | 64 | 01100100 +e | 101 | 65 | 01100101 +f | 102 | 66 | 01100110 +g | 103 | 67 | 01100111 +h | 104 | 68 | 01101000 +i | 105 | 69 | 01101001 +j | 106 | 6A | 01101010 +k | 107 | 6B | 01101011 +l | 108 | 6C | 01101100 +m | 109 | 6D | 01101101 +n | 110 | 6E | 01101110 +o | 111 | 6F | 01101111 +p | 112 | 70 | 01110000 +q | 113 | 71 | 01110001 +r | 114 | 72 | 01110010 +s | 115 | 73 | 01110011 +t | 116 | 74 | 01110100 +u | 117 | 75 | 01110101 +v | 118 | 76 | 01110110 +w | 119 | 77 | 01110111 +x | 120 | 78 | 01111000 +y | 121 | 79 | 01111001 +z | 122 | 7A | 01111010 +{ | 123 | 7B | 01111011 +| | 124 | 7C | 01111100 +} | 125 | 7D | 01111101 +~ | 126 | 7E | 01111110 \ No newline at end of file diff --git a/azure-pipelines/e2e-assets/ci-feature-baseline/ci.baseline.txt b/azure-pipelines/e2e-assets/ci-feature-baseline/ci.baseline.txt new file mode 100644 index 0000000000..991685359f --- /dev/null +++ b/azure-pipelines/e2e-assets/ci-feature-baseline/ci.baseline.txt @@ -0,0 +1,16 @@ +not-sup-host-b:arm64-osx=fail +not-sup-host-b:x64-osx=fail +not-sup-host-b:x86-windows=fail +not-sup-host-b:x64-windows=fail +not-sup-host-b:arm64-windows=fail +not-sup-host-b:x64-linux=fail +not-sup-host-b:arm64-linux=fail + + +dep-on-feature-not-sup:arm64-osx=fail +dep-on-feature-not-sup:x64-osx=fail +dep-on-feature-not-sup:x86-windows=fail +dep-on-feature-not-sup:x64-windows=fail +dep-on-feature-not-sup:arm64-windows=fail +dep-on-feature-not-sup:x64-linux=fail +dep-on-feature-not-sup:arm64-linux=fail diff --git a/azure-pipelines/e2e-assets/ci-feature-baseline/expected/asci-range.txt b/azure-pipelines/e2e-assets/ci-feature-baseline/expected/asci-range.txt new file mode 100644 index 0000000000..c11da9c948 --- /dev/null +++ b/azure-pipelines/e2e-assets/ci-feature-baseline/expected/asci-range.txt @@ -0,0 +1,95 @@ + Was sorted by the "Sort Lines Ascending" command in VSCode (# was excluded because it is a comment) + | 32 | 20 | 00100000 +_ | 95 | 5F | 01011111 +- | 45 | 2D | 00101101 +, | 44 | 2C | 00101100 +; | 59 | 3B | 00111011 +: | 58 | 3A | 00111010 +! | 33 | 21 | 00100001 +? | 63 | 3F | 00111111 +. | 46 | 2E | 00101110 +' | 39 | 27 | 00100111 +" | 34 | 22 | 00100010 +( | 40 | 28 | 00101000 +) | 41 | 29 | 00101001 +[ | 91 | 5B | 01011011 +] | 93 | 5D | 01011101 +{ | 123 | 7B | 01111011 +} | 125 | 7D | 01111101 +@ | 64 | 40 | 01000000 +* | 42 | 2A | 00101010 +/ | 47 | 2F | 00101111 +\ | 92 | 5C | 01011100 +& | 38 | 26 | 00100110 +% | 37 | 25 | 00100101 +` | 96 | 60 | 01100000 +^ | 94 | 5E | 01011110 ++ | 43 | 2B | 00101011 +< | 60 | 3C | 00111100 += | 61 | 3D | 00111101 +> | 62 | 3E | 00111110 +| | 124 | 7C | 01111100 +~ | 126 | 7E | 01111110 +$ | 36 | 24 | 00100100 +0 | 48 | 30 | 00110000 +1 | 49 | 31 | 00110001 +2 | 50 | 32 | 00110010 +3 | 51 | 33 | 00110011 +4 | 52 | 34 | 00110100 +5 | 53 | 35 | 00110101 +6 | 54 | 36 | 00110110 +7 | 55 | 37 | 00110111 +8 | 56 | 38 | 00111000 +9 | 57 | 39 | 00111001 +A | 65 | 41 | 01000001 +a | 97 | 61 | 01100001 +B | 66 | 42 | 01000010 +b | 98 | 62 | 01100010 +C | 67 | 43 | 01000011 +c | 99 | 63 | 01100011 +d | 100 | 64 | 01100100 +D | 68 | 44 | 01000100 +e | 101 | 65 | 01100101 +E | 69 | 45 | 01000101 +f | 102 | 66 | 01100110 +F | 70 | 46 | 01000110 +g | 103 | 67 | 01100111 +G | 71 | 47 | 01000111 +h | 104 | 68 | 01101000 +H | 72 | 48 | 01001000 +i | 105 | 69 | 01101001 +I | 73 | 49 | 01001001 +j | 106 | 6A | 01101010 +J | 74 | 4A | 01001010 +k | 107 | 6B | 01101011 +K | 75 | 4B | 01001011 +l | 108 | 6C | 01101100 +L | 76 | 4C | 01001100 +m | 109 | 6D | 01101101 +M | 77 | 4D | 01001101 +n | 110 | 6E | 01101110 +N | 78 | 4E | 01001110 +o | 111 | 6F | 01101111 +O | 79 | 4F | 01001111 +p | 112 | 70 | 01110000 +P | 80 | 50 | 01010000 +q | 113 | 71 | 01110001 +Q | 81 | 51 | 01010001 +r | 114 | 72 | 01110010 +R | 82 | 52 | 01010010 +s | 115 | 73 | 01110011 +S | 83 | 53 | 01010011 +t | 116 | 74 | 01110100 +T | 84 | 54 | 01010100 +u | 117 | 75 | 01110101 +U | 85 | 55 | 01010101 +v | 118 | 76 | 01110110 +V | 86 | 56 | 01010110 +w | 119 | 77 | 01110111 +W | 87 | 57 | 01010111 +x | 120 | 78 | 01111000 +X | 88 | 58 | 01011000 +y | 121 | 79 | 01111001 +Y | 89 | 59 | 01011001 +z | 122 | 7A | 01111010 +Z | 90 | 5A | 01011010 diff --git a/azure-pipelines/e2e-assets/ci-feature-baseline/expected/ci.baseline.txt b/azure-pipelines/e2e-assets/ci-feature-baseline/expected/ci.baseline.txt new file mode 100644 index 0000000000..e392fa30b4 --- /dev/null +++ b/azure-pipelines/e2e-assets/ci-feature-baseline/expected/ci.baseline.txt @@ -0,0 +1,16 @@ +not-sup-host-b:arm64-linux=fail +not-sup-host-b:arm64-osx=fail +not-sup-host-b:arm64-windows=fail +not-sup-host-b:x64-linux=fail +not-sup-host-b:x64-osx=fail +not-sup-host-b:x64-windows=fail +not-sup-host-b:x86-windows=fail + + +dep-on-feature-not-sup:arm64-linux=fail +dep-on-feature-not-sup:arm64-osx=fail +dep-on-feature-not-sup:arm64-windows=fail +dep-on-feature-not-sup:x64-linux=fail +dep-on-feature-not-sup:x64-osx=fail +dep-on-feature-not-sup:x64-windows=fail +dep-on-feature-not-sup:x86-windows=fail diff --git a/azure-pipelines/e2e-assets/ci-feature-baseline/expected/keep-blocks.txt b/azure-pipelines/e2e-assets/ci-feature-baseline/expected/keep-blocks.txt new file mode 100644 index 0000000000..703f65f024 --- /dev/null +++ b/azure-pipelines/e2e-assets/ci-feature-baseline/expected/keep-blocks.txt @@ -0,0 +1,13 @@ +# first line +# second line + +a = fail +b = fail +c = fail + + +# new block + +a = cascade +b = cascade +c = cascade diff --git a/azure-pipelines/e2e-assets/ci-feature-baseline/keep-blocks.txt b/azure-pipelines/e2e-assets/ci-feature-baseline/keep-blocks.txt new file mode 100644 index 0000000000..8592a6453a --- /dev/null +++ b/azure-pipelines/e2e-assets/ci-feature-baseline/keep-blocks.txt @@ -0,0 +1,13 @@ +# first line +# second line + +b = fail +c = fail +a = fail + + +# new block + +b = cascade +c = cascade +a = cascade \ No newline at end of file diff --git a/azure-pipelines/end-to-end-tests-dir/format-feature-baseline.ps1 b/azure-pipelines/end-to-end-tests-dir/format-feature-baseline.ps1 new file mode 100644 index 0000000000..b30687501b --- /dev/null +++ b/azure-pipelines/end-to-end-tests-dir/format-feature-baseline.ps1 @@ -0,0 +1,19 @@ +. $PSScriptRoot/../end-to-end-tests-prelude.ps1 + +$ciFeatureBaselines = (Get-Item "$PSScriptRoot/../e2e-assets/ci-feature-baseline").FullName +$testProjects = Get-ChildItem "$ciFeatureBaselines/*.txt" -File +$testProjects | % { + $asItem = Get-Item $_ + $full = $asItem.FullName + $name = $asItem.Name + $expectedPath = "$ciFeatureBaselines/expected/$name" + $tempItemPath = "$TestingRoot/$name" + Write-Trace "test that format-feature-baseline on $full produces $expectedPath" + [string]$expected = Get-Content $expectedPath -Raw + Copy-Item $asItem $tempItemPath + Run-Vcpkg format-feature-baseline $tempItemPath + $actual = Get-Content $tempItemPath -Raw + if ($expected -ne $actual) { + throw "Expected formatting $full to produce $expectedPath but was $tempItemPath" + } +} \ No newline at end of file diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 7d1a593466..ca1e7a29ca 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -1066,6 +1066,7 @@ DECLARE_MESSAGE(FeatureBaselineExpectedFeatures, (msg::value), "{value} is a keyword", "When using '{value}' a list of features must be specified.") +DECLARE_MESSAGE(FeatureBaselineFormatted, (), "", "Succeeded in formatting the feature baseline file.") DECLARE_MESSAGE(FeatureBaselineNoFeaturesForFail, (), "", "When using '= fail' no list of features is allowed.") DECLARE_MESSAGE(FilesContainAbsolutePath1, (), diff --git a/include/vcpkg/base/strings.h b/include/vcpkg/base/strings.h index 5e1329945b..c9bb792360 100644 --- a/include/vcpkg/base/strings.h +++ b/include/vcpkg/base/strings.h @@ -256,7 +256,10 @@ namespace vcpkg::Strings template void on_end(Fn cb) { - cb(StringView{previous_partial_line}); + if (!previous_partial_line.empty()) + { + cb(StringView{previous_partial_line}); + } previous_partial_line.clear(); last_was_cr = false; } diff --git a/include/vcpkg/commands.format-feature-baselinet.h b/include/vcpkg/commands.format-feature-baselinet.h new file mode 100644 index 0000000000..142399e5c9 --- /dev/null +++ b/include/vcpkg/commands.format-feature-baselinet.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include + +namespace vcpkg +{ + extern const CommandMetadata CommandFormatFeatureBaselineMetadata; + void command_format_feature_baseline_and_exit(const VcpkgCmdArguments& args, const Filesystem& fs); +} diff --git a/locales/messages.json b/locales/messages.json index 21b6c1c459..8d456ddfcc 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -664,6 +664,7 @@ "_FeatureBaselineEntryAlreadySpecified.comment": "{value} is a keyword An example of {feature} is avisynthplus.", "FeatureBaselineExpectedFeatures": "When using '{value}' a list of features must be specified.", "_FeatureBaselineExpectedFeatures.comment": "{value} is a keyword", + "FeatureBaselineFormatted": "Succeeded in formatting the feature baseline file.", "FeatureBaselineNoFeaturesForFail": "When using '= fail' no list of features is allowed.", "FetchingBaselineInfo": "Fetching baseline information from {package_name}...", "_FetchingBaselineInfo.comment": "An example of {package_name} is zlib.", diff --git a/src/vcpkg/commands.cpp b/src/vcpkg/commands.cpp index a7432f69aa..1f80569fce 100644 --- a/src/vcpkg/commands.cpp +++ b/src/vcpkg/commands.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,7 @@ namespace vcpkg {"bootstrap-standalone", command_bootstrap_standalone_and_exit}, {"contact", command_contact_and_exit}, {"x-download", command_download_and_exit}, + {"format-feature-baseline", command_format_feature_baseline_and_exit}, {"hash", command_hash_and_exit}, {"x-init-registry", command_init_registry_and_exit}, {"version", command_version_and_exit}, diff --git a/src/vcpkg/commands.format-feature-baseline.cpp b/src/vcpkg/commands.format-feature-baseline.cpp new file mode 100644 index 0000000000..d3fd57df7b --- /dev/null +++ b/src/vcpkg/commands.format-feature-baseline.cpp @@ -0,0 +1,88 @@ +#include +#include + +#include +#include + +using namespace vcpkg; + +namespace +{ + bool is_comment(const std::string& line) + { + auto index = line.find_first_not_of(" \t"); + if (index != std::string::npos) + { + return line[index] == '#'; + } + return true; + } + + // The file should only contain ascii characters. Hardcode the unicode collation order for the ascii range. + constexpr uint8_t comparison_indices[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 38, 42, 54, 64, 55, 53, 41, 43, 44, 50, 58, + 35, 34, 40, 51, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 37, 36, 59, 60, 61, 39, 49, 75, + 77, 79, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, + 122, 124, 126, 45, 52, 46, 57, 33, 56, 76, 78, 80, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, + 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 47, 62, 48, 63}; + + struct cmp_char + { + auto operator()(char l_, char r_) + { + auto l = static_cast(l_); + auto r = static_cast(r_); + if (l >= sizeof(comparison_indices) || r >= sizeof(comparison_indices)) + { + return l < r; + } + return comparison_indices[l] < comparison_indices[r]; + } + }; + + struct cmp_str + { + auto operator()(const std::string& left, const std::string& right) + { + return std::lexicographical_compare(left.begin(), left.end(), right.begin(), right.end(), cmp_char{}); + } + }; +} + +namespace vcpkg +{ + constexpr CommandMetadata CommandFormatManifestMetadata = { + [] { return create_example_string("format-feature-baseline "); }, + 1, + 1, + {{}, {}, {}}, + nullptr, + }; + + void command_format_feature_baseline_and_exit(const VcpkgCmdArguments& args, const Filesystem& fs) + { + auto parsed_args = args.parse_arguments(CommandFormatManifestMetadata); + + auto lines = fs.read_lines(parsed_args.command_arguments.at(0)).value_or_exit(VCPKG_LINE_INFO); + for (auto start = lines.begin(); start != lines.end();) + { + if (is_comment(*start)) + { + ++start; + continue; + } + auto end = start + 1; + while (end != lines.end() && !is_comment(*end)) + { + ++end; + } + std::sort(start, end, cmp_str{}); + start = end; + } + fs.write_lines(parsed_args.command_arguments.at(0), lines, VCPKG_LINE_INFO); + + msg::println(msgFeatureBaselineFormatted); + Checks::exit_success(VCPKG_LINE_INFO); + } +} // namespace vcpkg From 4a2d427f8e9437b048c4e6e65ad04250b97174f0 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Mon, 28 Aug 2023 18:30:42 +0200 Subject: [PATCH 63/69] windows: Allow writing to file that is read --- src/vcpkg/base/files.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vcpkg/base/files.cpp b/src/vcpkg/base/files.cpp index 673b0d3783..361b457d51 100644 --- a/src/vcpkg/base/files.cpp +++ b/src/vcpkg/base/files.cpp @@ -1415,9 +1415,10 @@ namespace vcpkg ReadFilePointer::ReadFilePointer(const Path& file_path, std::error_code& ec) : FilePointer(file_path) { #if defined(_WIN32) - ec.assign(::_wfopen_s(&m_fs, to_stdfs_path(file_path).c_str(), L"rb"), std::generic_category()); + m_fs = ::_wfsopen(to_stdfs_path(file_path).c_str(), L"rb", _SH_DENYNO); #else // ^^^ _WIN32 / !_WIN32 vvv m_fs = ::fopen(file_path.c_str(), "rb"); +#endif // ^^^ !_WIN32 if (m_fs) { ec.clear(); @@ -1426,7 +1427,6 @@ namespace vcpkg { ec.assign(errno, std::generic_category()); } -#endif // ^^^ !_WIN32 } ReadFilePointer& ReadFilePointer::operator=(ReadFilePointer&& other) noexcept From 8b112b9643c9b9f52bfbc66a852dbe590e53eadb Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 29 Aug 2023 02:56:44 +0200 Subject: [PATCH 64/69] Revert "windows: Allow writing to file that is read" This reverts commit 4a2d427f8e9437b048c4e6e65ad04250b97174f0. --- src/vcpkg/base/files.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vcpkg/base/files.cpp b/src/vcpkg/base/files.cpp index ccf5fef5b6..ca9aa92254 100644 --- a/src/vcpkg/base/files.cpp +++ b/src/vcpkg/base/files.cpp @@ -1397,10 +1397,9 @@ namespace vcpkg ReadFilePointer::ReadFilePointer(const Path& file_path, std::error_code& ec) : FilePointer(file_path) { #if defined(_WIN32) - m_fs = ::_wfsopen(to_stdfs_path(file_path).c_str(), L"rb", _SH_DENYNO); + ec.assign(::_wfopen_s(&m_fs, to_stdfs_path(file_path).c_str(), L"rb"), std::generic_category()); #else // ^^^ _WIN32 / !_WIN32 vvv m_fs = ::fopen(file_path.c_str(), "rb"); -#endif // ^^^ !_WIN32 if (m_fs) { ec.clear(); @@ -1409,6 +1408,7 @@ namespace vcpkg { ec.assign(errno, std::generic_category()); } +#endif // ^^^ !_WIN32 } ReadFilePointer& ReadFilePointer::operator=(ReadFilePointer&& other) noexcept From 3c048e6ad7a3e64455b06c96ec9793ba7551d128 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 16 Sep 2023 21:33:15 +0200 Subject: [PATCH 65/69] Rename options and rename command to x-test-features --- src/vcpkg/commands.test-features.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 02415c8598..348f6a8686 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -102,9 +102,9 @@ namespace vcpkg { static constexpr StringLiteral OPTION_FAILURE_LOGS = "failure-logs"; static constexpr StringLiteral OPTION_CI_FEATURE_BASELINE = "ci-feature-baseline"; - static constexpr StringLiteral OPTION_DONT_TEST_FEATURE_CORE = "dont-test-feature-core"; - static constexpr StringLiteral OPTION_DONT_TEST_FEATURES_COMBINED = "dont-test-features-combined"; - static constexpr StringLiteral OPTION_DONT_TEST_FEATURES_SEPARATELY = "dont-test-features-separately"; + static constexpr StringLiteral OPTION_NO_FEATURE_CORE_TEST = "no-feature-core-test"; + static constexpr StringLiteral OPTION_NO_FEATURES_COMBINED_TEST = "no-features-combined-test"; + static constexpr StringLiteral OPTION_NO_FEATURES_SEPARATED_TESTS = "no-features-separated-tests"; static constexpr StringLiteral OPTION_OUTPUT_FAILURE_ABIS = "write-failure-abis-to"; static constexpr StringLiteral OPTION_ALL_PORTS = "all"; @@ -125,13 +125,13 @@ namespace vcpkg static constexpr std::array CI_SWITCHES = {{ {OPTION_ALL_PORTS, []() { return LocalizedString::from_raw("Runs the specified tests for all ports"); }}, - {OPTION_DONT_TEST_FEATURE_CORE, + {OPTION_NO_FEATURE_CORE_TEST, []() { return LocalizedString::from_raw("Tests the 'core' feature for every specified port"); }}, - {OPTION_DONT_TEST_FEATURES_SEPARATELY, + {OPTION_NO_FEATURES_SEPARATED_TESTS, []() { return LocalizedString::from_raw("Tests every feature of a port seperatly for every specified port"); }}, - {OPTION_DONT_TEST_FEATURES_COMBINED, + {OPTION_NO_FEATURES_COMBINED_TEST, []() { return LocalizedString::from_raw( "Tests the combination of every feature of a port for every specified port"); @@ -139,9 +139,9 @@ namespace vcpkg }}; constexpr CommandMetadata CommandTestFeaturesMetadata = { - "test-features", + "x-test-features", msgCmdTestFeaturesSynopsis, - {"vcpkg test-features gdal"}, + {"vcpkg x-test-features gdal"}, "https://learn.microsoft.com/vcpkg/commands/test-features", AutocompletePriority::Public, 0, @@ -160,10 +160,10 @@ namespace vcpkg const auto all_ports = Util::Sets::contains(options.switches, OPTION_ALL_PORTS); - const auto test_feature_core = !Util::Sets::contains(options.switches, OPTION_DONT_TEST_FEATURE_CORE); - const auto test_features_combined = !Util::Sets::contains(options.switches, OPTION_DONT_TEST_FEATURES_COMBINED); + const auto test_feature_core = !Util::Sets::contains(options.switches, OPTION_NO_FEATURE_CORE_TEST); + const auto test_features_combined = !Util::Sets::contains(options.switches, OPTION_NO_FEATURES_COMBINED_TEST); const auto test_features_seperatly = - !Util::Sets::contains(options.switches, OPTION_DONT_TEST_FEATURES_SEPARATELY); + !Util::Sets::contains(options.switches, OPTION_NO_FEATURES_SEPARATED_TESTS); auto binary_cache = BinaryCache::make(args, paths, stdout_sink).value_or_exit(VCPKG_LINE_INFO); From 3ab6b832295d585f74ae99f0a5e970d269e510fe Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 17 Apr 2024 19:03:11 +0200 Subject: [PATCH 66/69] Fix merge conflict --- src/vcpkg/commands.build.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/vcpkg/commands.build.cpp b/src/vcpkg/commands.build.cpp index ffddd38768..8a82fd22cf 100644 --- a/src/vcpkg/commands.build.cpp +++ b/src/vcpkg/commands.build.cpp @@ -1171,6 +1171,19 @@ namespace vcpkg msgHashPortManyFiles, msg::package_name = action.spec.name(), msg::count = raw_files.size()); } + for (size_t i = 0; i < abi_info.pre_build_info->hash_additional_files.size(); ++i) + { + auto& file = abi_info.pre_build_info->hash_additional_files[i]; + if (file.is_relative() || !fs.is_regular_file(file)) + { + Checks::msg_exit_with_message( + VCPKG_LINE_INFO, msgInvalidValueHashAdditionalFiles, msg::path = file); + } + abi_tag_entries.emplace_back( + fmt::format("additional_file_{}", i), + Hash::get_file_hash(fs, file, Hash::Algorithm::Sha256).value_or_exit(VCPKG_LINE_INFO)); + } + for (auto& port_file : raw_files) { if (port_file.filename() == FileDotDsStore) From ea7e63eea796bf813bd65f95568bfc2863dc941a Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 17 Apr 2024 19:09:20 +0200 Subject: [PATCH 67/69] Message db --- include/vcpkg/base/message-data.inc.h | 5 ----- locales/messages.json | 2 -- 2 files changed, 7 deletions(-) diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 5404ee56fd..53fdd737de 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -286,11 +286,6 @@ DECLARE_MESSAGE(BaselineMissing, "git add versions\n" "git commit -m \"Update version database\"\n" "to set {version} as the baseline version.") -DECLARE_MESSAGE(BaselineMissingDefault, - (msg::commit_sha, msg::url), - "", - "The baseline.json from commit `\"{commit_sha}\"` in the repo {url} was invalid (did not " - "contain a \"default\" field).") DECLARE_MESSAGE(BaselineOnlyPlatformExpressionOrTriplet, (), "", diff --git a/locales/messages.json b/locales/messages.json index 86182f86e4..8db828b1d9 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -189,8 +189,6 @@ "_BaselineGitShowFailed.comment": "An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949.", "BaselineMissing": "Baseline version not found. Run:\nvcpkg x-add-version {package_name}\ngit add versions\ngit commit -m \"Update version database\"\nto set {version} as the baseline version.", "_BaselineMissing.comment": "An example of {package_name} is zlib. An example of {version} is 1.3.8.", - "BaselineMissingDefault": "The baseline.json from commit `\"{commit_sha}\"` in the repo {url} was invalid (did not contain a \"default\" field).", - "_BaselineMissingDefault.comment": "An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949. An example of {url} is https://github.com/microsoft/vcpkg.", "BaselineOnlyPlatformExpressionOrTriplet": "You can not specify a platform expression and a triplet", "BinarySourcesArg": "Binary caching sources. See 'vcpkg help binarycaching'", "_BinarySourcesArg.comment": "'vcpkg help binarycaching' is a command line and should not be localized", From 43cd7c2554ccef0c28601e28579685d6fad681f0 Mon Sep 17 00:00:00 2001 From: autoantwort Date: Mon, 18 Nov 2024 22:24:26 +0100 Subject: [PATCH 68/69] Fix merge conflicts --- include/vcpkg/commands.build.h | 2 +- src/vcpkg/commands.test-features.cpp | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/vcpkg/commands.build.h b/include/vcpkg/commands.build.h index 493f1a187e..f8da7fa1f6 100644 --- a/include/vcpkg/commands.build.h +++ b/include/vcpkg/commands.build.h @@ -255,7 +255,7 @@ namespace vcpkg std::vector abi_entries; std::vector files; std::vector hashes; - Json::Value heuristic_resources; + Json::Object heuristic_resources; }; AbiCacheEntry& get(const Path& port_dir) const; diff --git a/src/vcpkg/commands.test-features.cpp b/src/vcpkg/commands.test-features.cpp index 9a200f42c6..d6dd2c7ee1 100644 --- a/src/vcpkg/commands.test-features.cpp +++ b/src/vcpkg/commands.test-features.cpp @@ -180,8 +180,7 @@ namespace vcpkg } auto registry_set = paths.make_registry_set(); - PathsPortFileProvider provider(*registry_set, - make_overlay_provider(filesystem, paths.original_cwd, paths.overlay_ports)); + PathsPortFileProvider provider(*registry_set, make_overlay_provider(filesystem, paths.overlay_ports)); auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths); auto& var_provider = *var_provider_storage; @@ -440,7 +439,6 @@ namespace vcpkg CleanDownloads::No, DownloadTool::Builtin, BackcompatFeatures::Prohibit, - PrintUsage::No, KeepGoing::Yes, }; const auto summary = install_execute_plan(args, From 8c2055bb4b68cd4221d870350f7d571c179c4da8 Mon Sep 17 00:00:00 2001 From: autoantwort Date: Mon, 18 Nov 2024 23:24:17 +0100 Subject: [PATCH 69/69] Fix warning --- src/vcpkg/commands.build.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/vcpkg/commands.build.cpp b/src/vcpkg/commands.build.cpp index a9003a2c2d..703fac3369 100644 --- a/src/vcpkg/commands.build.cpp +++ b/src/vcpkg/commands.build.cpp @@ -1273,17 +1273,20 @@ namespace vcpkg Util::Vectors::append(abi_tag_entries, cache_entry.abi_entries); - size_t i = 0; - for (auto& filestr : abi_info.pre_build_info->hash_additional_files) { - Path file(filestr); - if (file.is_relative() || !fs.is_regular_file(file)) + size_t i = 0; + for (auto& filestr : abi_info.pre_build_info->hash_additional_files) { - Checks::msg_exit_with_message(VCPKG_LINE_INFO, msgInvalidValueHashAdditionalFiles, msg::path = file); + Path file(filestr); + if (file.is_relative() || !fs.is_regular_file(file)) + { + Checks::msg_exit_with_message( + VCPKG_LINE_INFO, msgInvalidValueHashAdditionalFiles, msg::path = file); + } + const auto hash = + vcpkg::Hash::get_file_hash(fs, file, Hash::Algorithm::Sha256).value_or_exit(VCPKG_LINE_INFO); + abi_tag_entries.emplace_back(fmt::format("additional_file_{}", i++), hash); } - const auto hash = - vcpkg::Hash::get_file_hash(fs, file, Hash::Algorithm::Sha256).value_or_exit(VCPKG_LINE_INFO); - abi_tag_entries.emplace_back(fmt::format("additional_file_{}", i++), hash); } for (size_t i = 0; i < abi_info.pre_build_info->post_portfile_includes.size(); ++i)