diff --git a/include/vcpkg-test/util.h b/include/vcpkg-test/util.h index c27a732824..5a4b9c7070 100644 --- a/include/vcpkg-test/util.h +++ b/include/vcpkg-test/util.h @@ -33,6 +33,15 @@ namespace Catch } }; + template<> + struct StringMaker + { + static std::string convert(vcpkg::FeatureSpec const& value) + { + return vcpkg::Strings::concat(value.spec().name(), '[', value.feature(), "]:", value.spec().triplet()); + } + }; + template<> struct StringMaker { @@ -107,6 +116,19 @@ namespace vcpkg::Test return std::move(*opt.get()); } + inline std::vector parse_test_fspecs(StringView sv, Triplet t = X86_WINDOWS) + { + std::vector ret; + Parse::ParserBase parser(sv, "test"); + while (!parser.at_eof()) + { + auto opt = parse_qualified_specifier(parser); + REQUIRE(opt.has_value()); + ret.push_back(unwrap(opt.get()->to_full_spec(t, ImplicitDefault::YES))); + } + return ret; + } + template void check_ranges(const R1& r1, const R2& r2) { diff --git a/include/vcpkg/base/expected.h b/include/vcpkg/base/expected.h index 5a04bc5986..913cc09c72 100644 --- a/include/vcpkg/base/expected.h +++ b/include/vcpkg/base/expected.h @@ -165,11 +165,13 @@ namespace vcpkg return this->m_t.get(); } + using const_ref_type = decltype(*std::declval::const_pointer>()); + using move_ref_type = decltype(std::move(*std::declval::pointer>())); template using map_t = decltype(std::declval()(*std::declval::const_pointer>())); - template> - ExpectedT map(F f) const& + template + ExpectedT, S> map(F f) const& { if (has_value()) { @@ -177,7 +179,7 @@ namespace vcpkg } else { - return {error(), expected_right_tag}; + return ExpectedT, S>{m_s}; } } @@ -185,8 +187,8 @@ namespace vcpkg using move_map_t = decltype(std::declval()(std::move(*std::declval::pointer>()))); - template> - ExpectedT map(F f) && + template + ExpectedT, S> map(F f) && { if (has_value()) { @@ -194,37 +196,43 @@ namespace vcpkg } else { - return {std::move(*this).error(), expected_right_tag}; + return ExpectedT, S>{std::move(m_s)}; } } - template> - U then(F f) const& + template + std::invoke_result_t then(F f, Args&&... args) const& { if (has_value()) { - return f(*m_t.get()); + return std::invoke(f, *m_t.get(), static_cast(args)...); } else { - return U{error(), expected_right_tag}; + return std::invoke_result_t{m_s}; } } - template> - U then(F f) && + template + std::invoke_result_t then(F f, Args&&... args) && { if (has_value()) { - return f(std::move(*m_t.get())); + return std::invoke(f, std::move(*m_t.get()), static_cast(args)...); } else { - return U{std::move(*this).error(), expected_right_tag}; + return std::invoke_result_t{std::move(m_s)}; } } private: + template + friend struct ExpectedT; + + explicit ExpectedT(const ErrorHolder& err) : m_s(err) { } + explicit ExpectedT(ErrorHolder&& err) : m_s(static_cast&&>(err)) { } + void exit_if_error(const LineInfo& line_info) const { if (m_s.has_error()) diff --git a/include/vcpkg/dependencies.h b/include/vcpkg/dependencies.h index 70b2e91774..9e4d72e694 100644 --- a/include/vcpkg/dependencies.h +++ b/include/vcpkg/dependencies.h @@ -86,7 +86,7 @@ namespace vcpkg::Dependencies std::map> feature_dependencies; std::vector package_dependencies; - std::vector feature_list; + InternalFeatureSet feature_list; Triplet host_triplet; Optional abi_info; @@ -196,13 +196,6 @@ namespace vcpkg::Dependencies const StatusParagraphs& status_db, const CreateInstallPlanOptions& options = {Triplet{}}); - // `features` should have "default" instead of missing "core". This is only exposed for testing purposes. - std::vector resolve_deps_as_top_level(const SourceControlFile& scf, - Triplet triplet, - Triplet host_triplet, - std::vector features, - CMakeVars::CMakeVarProvider& var_provider); - ExpectedS create_versioned_install_plan(const PortFileProvider::IVersionedPortfileProvider& vprovider, const PortFileProvider::IBaselineProvider& bprovider, const PortFileProvider::IOverlayProvider& oprovider, diff --git a/include/vcpkg/input.h b/include/vcpkg/input.h index 917b5af10a..aa31ad4d32 100644 --- a/include/vcpkg/input.h +++ b/include/vcpkg/input.h @@ -6,10 +6,13 @@ namespace vcpkg::Input { PackageSpec check_and_get_package_spec(std::string&& spec_string, Triplet default_triplet, - CStringView example_text); + CStringView example_text, + const VcpkgPaths& paths); + FullPackageSpec check_and_get_full_package_spec(std::string&& spec_string, Triplet default_triplet, - CStringView example_text); + CStringView example_text, + const VcpkgPaths& paths); void check_triplet(Triplet t, const VcpkgPaths& paths); } diff --git a/include/vcpkg/packagespec.h b/include/vcpkg/packagespec.h index 8929e2cedd..a5f3213a00 100644 --- a/include/vcpkg/packagespec.h +++ b/include/vcpkg/packagespec.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -92,6 +93,12 @@ namespace vcpkg std::string m_feature; }; + /// In an internal feature set, "default" represents default features and missing "core" has no semantic + struct InternalFeatureSet : std::vector + { + using std::vector::vector; + }; + /// /// /// Full specification of a package. Contains all information to reference @@ -101,37 +108,22 @@ namespace vcpkg struct FullPackageSpec { PackageSpec package_spec; - std::vector features; + InternalFeatureSet features; FullPackageSpec() = default; - explicit FullPackageSpec(PackageSpec spec, std::vector features = {}) + explicit FullPackageSpec(PackageSpec spec, InternalFeatureSet features) : package_spec(std::move(spec)), features(std::move(features)) { } - std::vector to_feature_specs(const std::vector& default_features, - const std::vector& all_features) const; - - static ExpectedS from_string(const std::string& spec_as_string, Triplet default_triplet); + /// Splats into individual FeatureSpec's + void expand_fspecs_to(std::vector& oFut) const; - bool operator==(const FullPackageSpec& o) const + friend bool operator==(const FullPackageSpec& l, const FullPackageSpec& r) { - return package_spec == o.package_spec && features == o.features; + return l.package_spec == r.package_spec && l.features == r.features; } - bool operator!=(const FullPackageSpec& o) const { return !(*this == o); } - }; - - /// - /// - /// Contains all information to reference a collection of features in a single package by their names. - /// - /// - struct Features - { - std::string name; - std::vector features; - - static ExpectedS from_string(const std::string& input); + friend bool operator!=(const FullPackageSpec& l, const FullPackageSpec& r) { return !(l == r); } }; struct DependencyConstraint @@ -147,6 +139,12 @@ namespace vcpkg } }; + enum class ImplicitDefault : bool + { + NO, + YES, + }; + struct Dependency { std::string name; @@ -157,6 +155,9 @@ namespace vcpkg Json::Object extra_info; + /// @param id adds "default" if "core" not present. + FullPackageSpec to_full_spec(Triplet target, Triplet host, ImplicitDefault id) const; + friend bool operator==(const Dependency& lhs, const Dependency& rhs); friend bool operator!=(const Dependency& lhs, const Dependency& rhs) { return !(lhs == rhs); } }; @@ -180,6 +181,12 @@ namespace vcpkg Optional> features; Optional triplet; Optional platform; + + /// @param id add "default" if "core" is not present + /// @return nullopt on success. On failure, caller should supplement returned string with more context. + ExpectedS to_full_spec(Triplet default_triplet, ImplicitDefault id) const; + + ExpectedS to_package_spec(Triplet default_triplet) const; }; Optional parse_feature_name(Parse::ParserBase& parser); diff --git a/include/vcpkg/sourceparagraph.h b/include/vcpkg/sourceparagraph.h index 2e65dded6a..4338dcb706 100644 --- a/include/vcpkg/sourceparagraph.h +++ b/include/vcpkg/sourceparagraph.h @@ -19,7 +19,8 @@ namespace vcpkg std::vector filter_dependencies(const std::vector& deps, Triplet t, Triplet host, - const std::unordered_map& cmake_vars); + const std::unordered_map& cmake_vars, + ImplicitDefault id); struct Type { diff --git a/include/vcpkg/triplet.h b/include/vcpkg/triplet.h index eb32383855..575fde8b52 100644 --- a/include/vcpkg/triplet.h +++ b/include/vcpkg/triplet.h @@ -19,7 +19,7 @@ namespace vcpkg public: constexpr Triplet() noexcept : m_instance(&DEFAULT_INSTANCE) { } - static Triplet from_canonical_name(std::string&& triplet_as_string); + static Triplet from_canonical_name(std::string triplet_as_string); const std::string& canonical_name() const; const std::string& to_string() const; diff --git a/locales/en.json b/locales/en.json index c7142fb118..9ede9e0de5 100644 --- a/locales/en.json +++ b/locales/en.json @@ -14,6 +14,8 @@ "ErrorRequirePackagesToInstall": "Error: No packages were listed for installation and no manifest was found.", "ErrorVcvarsUnsupported": "Error: in triplet {triplet}: Use of Visual Studio's Developer Prompt is unsupported on non-Windows hosts.\nDefine 'VCPKG_CMAKE_SYSTEM_NAME' or 'VCPKG_CHAINLOAD_TOOLCHAIN_FILE' in the triplet file.", "ForceSystemBinariesOnWeirdPlatforms": "Environment variable VCPKG_FORCE_SYSTEM_BINARIES must be set on arm, s390x, and ppc64le platforms.", + "IllegalFeatures": "Error: List of features is not allowed in this contect", + "IllegalPlatformSpec": "Error: Platform qualifier is not allowed in this context", "NoLocalizationForMessages": "No localization for the following messages:", "SeeURL": "See {url} for more information.", "UnsupportedSystemName": "Error: Could not map VCPKG_CMAKE_SYSTEM_NAME '{value}' to a vcvarsall platform. Supported system names are '', 'Windows' and 'WindowsStore'.", diff --git a/src/vcpkg-test/dependencies.cpp b/src/vcpkg-test/dependencies.cpp index e36e9b1cb3..c8b1c90f24 100644 --- a/src/vcpkg-test/dependencies.cpp +++ b/src/vcpkg-test/dependencies.cpp @@ -99,16 +99,16 @@ T unwrap(ExpectedS e) return std::move(*e.get()); } -static void check_name_and_version(const Dependencies::InstallPlanAction& ipa, - StringLiteral name, - Versions::Version v, - std::initializer_list features = {}) +static void check_name_and_features(const Dependencies::InstallPlanAction& ipa, + StringLiteral name, + std::initializer_list features) { CHECK(ipa.spec.name() == name); CHECK(ipa.source_control_file_and_location.has_value()); - CHECK(ipa.feature_list.size() == features.size() + 1); { INFO("ipa.feature_list = [" << Strings::join(", ", ipa.feature_list) << "]"); + INFO("features = [" << Strings::join(", ", features) << "]"); + CHECK(ipa.feature_list.size() == features.size() + 1); for (auto&& f : features) { INFO("f = \"" << f.c_str() << "\""); @@ -116,6 +116,14 @@ static void check_name_and_version(const Dependencies::InstallPlanAction& ipa, } CHECK(Util::find(ipa.feature_list, "core") != ipa.feature_list.end()); } +} + +static void check_name_and_version(const Dependencies::InstallPlanAction& ipa, + StringLiteral name, + Versions::Version v, + std::initializer_list features = {}) +{ + check_name_and_features(ipa, name, features); if (auto scfl = ipa.source_control_file_and_location.get()) { CHECK(scfl->source_control_file->core_paragraph->version == v.text()); @@ -201,6 +209,8 @@ struct MockOverlayProvider : PortFileProvider::IOverlayProvider return it->second; } + SourceControlFileAndLocation& emplace(const std::string& name) { return emplace(name, {"1", 0}); } + virtual void load_all_control_files(std::map&) const override { Checks::unreachable(VCPKG_LINE_INFO); @@ -231,27 +241,24 @@ static ExpectedS create_versioned_install_plan( Dependencies::UnsupportedPortAction::Error); } -namespace vcpkg::Dependencies +static ExpectedS create_versioned_install_plan( + const PortFileProvider::IVersionedPortfileProvider& provider, + const PortFileProvider::IBaselineProvider& bprovider, + const PortFileProvider::IOverlayProvider& oprovider, + const CMakeVars::CMakeVarProvider& var_provider, + const std::vector& deps, + const std::vector& overrides, + const PackageSpec& toplevel) { - static ExpectedS create_versioned_install_plan( - const PortFileProvider::IVersionedPortfileProvider& provider, - const PortFileProvider::IBaselineProvider& bprovider, - const PortFileProvider::IOverlayProvider& oprovider, - const CMakeVars::CMakeVarProvider& var_provider, - const std::vector& deps, - const std::vector& overrides, - const PackageSpec& toplevel) - { - return vcpkg::Dependencies::create_versioned_install_plan(provider, - bprovider, - oprovider, - var_provider, - deps, - overrides, - toplevel, - Test::ARM_UWP, - Dependencies::UnsupportedPortAction::Error); - } + return vcpkg::Dependencies::create_versioned_install_plan(provider, + bprovider, + oprovider, + var_provider, + deps, + overrides, + toplevel, + Test::ARM_UWP, + Dependencies::UnsupportedPortAction::Error); } TEST_CASE ("basic version install single", "[versionplan]") @@ -1932,8 +1939,8 @@ TEST_CASE ("version overlay ports", "[versionplan]") { const MockBaselineProvider empty_bp; - auto install_plan = unwrap(Dependencies::create_versioned_install_plan( - vp, empty_bp, oprovider, var_provider, {{"a"}}, {}, toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, empty_bp, oprovider, var_provider, {{"a"}}, {}, toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); @@ -1941,8 +1948,8 @@ TEST_CASE ("version overlay ports", "[versionplan]") SECTION ("transitive") { - auto install_plan = unwrap( - Dependencies::create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"b"}}, {}, toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"b"}}, {}, toplevel_spec())); REQUIRE(install_plan.size() == 2); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); @@ -1951,8 +1958,8 @@ TEST_CASE ("version overlay ports", "[versionplan]") SECTION ("transitive constraint") { - auto install_plan = unwrap( - Dependencies::create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"c"}}, {}, toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"c"}}, {}, toplevel_spec())); REQUIRE(install_plan.size() == 2); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); @@ -1961,59 +1968,59 @@ TEST_CASE ("version overlay ports", "[versionplan]") SECTION ("none") { - auto install_plan = unwrap( - Dependencies::create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"a"}}, {}, toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, bp, oprovider, var_provider, {{"a"}}, {}, toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); } SECTION ("constraint") { - auto install_plan = unwrap(Dependencies::create_versioned_install_plan( - vp, - bp, - oprovider, - var_provider, - { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}, - }, - {}, - toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + { + Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}, + }, + {}, + toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); } SECTION ("constraint+override") { - auto install_plan = unwrap(Dependencies::create_versioned_install_plan( - vp, - bp, - oprovider, - var_provider, - { - Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}, - }, - { - DependencyOverride{"a", "2", 0}, - }, - toplevel_spec())); + auto install_plan = + unwrap(create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + { + Dependency{"a", {}, {}, {Constraint::Type::Minimum, "1", 1}}, + }, + { + DependencyOverride{"a", "2", 0}, + }, + toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); } SECTION ("override") { - auto install_plan = unwrap(Dependencies::create_versioned_install_plan(vp, - bp, - oprovider, - var_provider, - { - Dependency{"a"}, - }, - { - DependencyOverride{"a", "2", 0}, - }, - toplevel_spec())); + auto install_plan = unwrap(create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + { + Dependency{"a"}, + }, + { + DependencyOverride{"a", "2", 0}, + }, + toplevel_spec())); REQUIRE(install_plan.size() == 1); check_name_and_version(install_plan.install_actions[0], "a", {"overlay", 0}); @@ -2042,12 +2049,12 @@ TEST_CASE ("respect supports expression", "[versionplan]") { // override from non supported to supported version MockOverlayProvider oprovider; - install_plan = Dependencies::create_versioned_install_plan( + install_plan = create_versioned_install_plan( vp, bp, oprovider, var_provider, {Dependency{"a"}}, {DependencyOverride{"a", "1", 1}}, toplevel_spec()); CHECK(install_plan.has_value()); // override from supported to non supported version bp.v["a"] = {"1", 1}; - install_plan = Dependencies::create_versioned_install_plan( + install_plan = create_versioned_install_plan( vp, bp, oprovider, var_provider, {Dependency{"a"}}, {DependencyOverride{"a", "1", 0}}, toplevel_spec()); CHECK_FALSE(install_plan.has_value()); } @@ -2080,23 +2087,23 @@ TEST_CASE ("respect supports expressions of features", "[versionplan]") { // override from non supported to supported version MockOverlayProvider oprovider; - install_plan = Dependencies::create_versioned_install_plan(vp, - bp, - oprovider, - var_provider, - {Dependency{"a", {"x"}}}, - {DependencyOverride{"a", "1", 1}}, - toplevel_spec()); + install_plan = create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + {Dependency{"a", {"x"}}}, + {DependencyOverride{"a", "1", 1}}, + toplevel_spec()); CHECK(install_plan.has_value()); // override from supported to non supported version bp.v["a"] = {"1", 1}; - install_plan = Dependencies::create_versioned_install_plan(vp, - bp, - oprovider, - var_provider, - {Dependency{"a", {"x"}}}, - {DependencyOverride{"a", "1", 0}}, - toplevel_spec()); + install_plan = create_versioned_install_plan(vp, + bp, + oprovider, + var_provider, + {Dependency{"a", {"x"}}}, + {DependencyOverride{"a", "1", 0}}, + toplevel_spec()); CHECK_FALSE(install_plan.has_value()); } } diff --git a/src/vcpkg-test/plan.cpp b/src/vcpkg-test/plan.cpp index b9fd772a42..bf1d3b4b15 100644 --- a/src/vcpkg-test/plan.cpp +++ b/src/vcpkg-test/plan.cpp @@ -72,9 +72,8 @@ TEST_CASE ("basic install scheme", "[plan]") PortFileProvider::MapPortFileProvider map_port(spec_map.map); MockCMakeVarProvider var_provider; - auto fullspec_a = FullPackageSpec{spec_a, {}}; auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&fullspec_a, 1}, StatusParagraphs(std::move(status_paragraphs))); + map_port, var_provider, Test::parse_test_fspecs("a[core]"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 3); REQUIRE(install_plan.install_actions.at(0).spec.name() == "c"); @@ -99,8 +98,7 @@ TEST_CASE ("multiple install scheme", "[plan]") PortFileProvider::MapPortFileProvider map_port(spec_map.map); MockCMakeVarProvider var_provider; - std::vector full_package_specs{ - FullPackageSpec{spec_a}, FullPackageSpec{spec_b}, FullPackageSpec{spec_c}}; + const auto full_package_specs = Test::parse_test_fspecs("a b c"); auto install_plan = Dependencies::create_feature_install_plan( map_port, var_provider, full_package_specs, StatusParagraphs(std::move(status_paragraphs))); @@ -138,13 +136,13 @@ TEST_CASE ("existing package scheme", "[plan]") status_paragraphs.push_back(vcpkg::Test::make_status_pgh("a")); PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a")}; + spec_map.emplace("a"); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&spec_a, 1}, StatusParagraphs(std::move(status_paragraphs))); + map_port, var_provider, Test::parse_test_fspecs("a"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 1); const auto p = &install_plan.already_installed.at(0); @@ -158,14 +156,14 @@ TEST_CASE ("user requested package scheme", "[plan]") std::vector> status_paragraphs; PackageSpecMap spec_map; - const auto spec_a = FullPackageSpec{spec_map.emplace("a", "b")}; - const auto spec_b = FullPackageSpec{spec_map.emplace("b")}; + spec_map.emplace("a", "b"); + spec_map.emplace("b"); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; const auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&spec_a, 1}, StatusParagraphs(std::move(status_paragraphs))); + map_port, var_provider, Test::parse_test_fspecs("a"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 2); const auto p = &install_plan.install_actions.at(0); @@ -201,9 +199,8 @@ TEST_CASE ("long install scheme", "[plan]") PortFileProvider::MapPortFileProvider map_port(spec_map.map); MockCMakeVarProvider var_provider; - auto fullspec_a = FullPackageSpec{spec_a}; auto plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&fullspec_a, 1}, StatusParagraphs(std::move(status_paragraphs))); + map_port, var_provider, Test::parse_test_fspecs("a"), StatusParagraphs(std::move(status_paragraphs))); auto& install_plan = plan.install_actions; REQUIRE(install_plan.size() == 8); @@ -219,47 +216,41 @@ TEST_CASE ("long install scheme", "[plan]") TEST_CASE ("basic feature test 1", "[plan]") { - std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a", "b, b[b1]")); - status_paragraphs.push_back(make_status_pgh("b")); - status_paragraphs.push_back(make_status_feature_pgh("b", "b1")); - PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b, b[b1]", {{"a1", "b[b2]"}}), {"a1"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})}; - - PortFileProvider::MapPortFileProvider map_port{spec_map.map}; - MockCMakeVarProvider var_provider; - - auto plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&spec_a, 1}, StatusParagraphs(std::move(status_paragraphs))); + spec_map.emplace("a", "b, b[b1]", {{"a1", "b[b2]"}}); + spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}}); - REQUIRE(plan.size() == 4); - remove_plan_check(plan.remove_actions.at(0), "a"); - remove_plan_check(plan.remove_actions.at(1), "b"); - features_check(plan.install_actions.at(0), "b", {"b1", "core", "b1"}); - features_check(plan.install_actions.at(1), "a", {"a1", "core"}); -} - -TEST_CASE ("basic feature test 2", "[plan]") -{ - std::vector> status_paragraphs; - - PackageSpecMap spec_map; - - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[b1]", {{"a1", "b[b2]"}}), {"a1"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}, {"b3", ""}})}; + const auto fspecs = Test::parse_test_fspecs("a[a1]"); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; - auto plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&spec_a, 1}, StatusParagraphs(std::move(status_paragraphs))); + SECTION ("1") + { + std::vector> status_paragraphs; + status_paragraphs.push_back(make_status_pgh("a", "b, b[b1]")); + status_paragraphs.push_back(make_status_pgh("b")); + status_paragraphs.push_back(make_status_feature_pgh("b", "b1")); + + auto plan = Dependencies::create_feature_install_plan( + map_port, var_provider, fspecs, StatusParagraphs(std::move(status_paragraphs))); + + REQUIRE(plan.size() == 4); + remove_plan_check(plan.remove_actions.at(0), "a"); + remove_plan_check(plan.remove_actions.at(1), "b"); + features_check(plan.install_actions.at(0), "b", {"b1", "core", "b1"}); + features_check(plan.install_actions.at(1), "a", {"a1", "core"}); + } - auto& install_plan = plan.install_actions; - REQUIRE(install_plan.size() == 2); - features_check(install_plan.at(0), "b", {"b1", "b2", "core"}); - features_check(install_plan.at(1), "a", {"a1", "core"}); + SECTION ("2") + { + auto plan = Dependencies::create_feature_install_plan(map_port, var_provider, fspecs, StatusParagraphs()); + + auto& install_plan = plan.install_actions; + REQUIRE(install_plan.size() == 2); + features_check(install_plan.at(0), "b", {"b1", "b2", "core"}); + features_check(install_plan.at(1), "a", {"a1", "core"}); + } } TEST_CASE ("basic feature test 3", "[plan]") @@ -269,16 +260,17 @@ TEST_CASE ("basic feature test 3", "[plan]") PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b")}; - auto spec_c = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; + spec_map.emplace("a", "b", {{"a1", ""}}); + spec_map.emplace("b"); + spec_map.emplace("c", "a[a1]"); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; - std::vector full_package_specs{spec_c, spec_a}; - auto plan = Dependencies::create_feature_install_plan( - map_port, var_provider, full_package_specs, StatusParagraphs(std::move(status_paragraphs))); + auto plan = Dependencies::create_feature_install_plan(map_port, + var_provider, + Test::parse_test_fspecs("c[core] a[core]"), + StatusParagraphs(std::move(status_paragraphs))); REQUIRE(plan.size() == 4); remove_plan_check(plan.remove_actions.at(0), "a"); @@ -296,15 +288,15 @@ TEST_CASE ("basic feature test 4", "[plan]") PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}})}; - auto spec_b = FullPackageSpec{spec_map.emplace("b")}; - auto spec_c = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; + spec_map.emplace("a", "b", {{"a1", ""}}); + spec_map.emplace("b"); + spec_map.emplace("c", "a[a1]"); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&spec_c, 1}, StatusParagraphs(std::move(status_paragraphs))); + map_port, var_provider, Test::parse_test_fspecs("c[core]"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 1); features_check(install_plan.install_actions.at(0), "c", {"core"}); @@ -316,15 +308,14 @@ TEST_CASE ("basic feature test 5", "[plan]") PackageSpecMap spec_map; - auto spec_a = - FullPackageSpec{spec_map.emplace("a", "", {{"a1", "b[b1]"}, {"a2", "b[b2]"}, {"a3", "a[a2]"}}), {"a3"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}})}; + spec_map.emplace("a", "", {{"a1", "b[b1]"}, {"a2", "b[b2]"}, {"a3", "a[a2]"}}); + spec_map.emplace("b", "", {{"b1", ""}, {"b2", ""}}); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&spec_a, 1}, StatusParagraphs(std::move(status_paragraphs))); + map_port, var_provider, Test::parse_test_fspecs("a[a3]"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 2); features_check(install_plan.install_actions.at(0), "b", {"core", "b2"}); @@ -337,15 +328,16 @@ TEST_CASE ("basic feature test 6", "[plan]") status_paragraphs.push_back(make_status_pgh("b")); PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b[core]"), {"core"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {"b1"}}; + spec_map.emplace("a", "b[core]"); + spec_map.emplace("b", "", {{"b1", ""}}); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; - std::vector full_package_specs{spec_a, spec_b}; - auto plan = Dependencies::create_feature_install_plan( - map_port, var_provider, full_package_specs, StatusParagraphs(std::move(status_paragraphs))); + auto plan = Dependencies::create_feature_install_plan(map_port, + var_provider, + Test::parse_test_fspecs("a[core] b[b1]"), + StatusParagraphs(std::move(status_paragraphs))); REQUIRE(plan.size() == 3); remove_plan_check(plan.remove_actions.at(0), "b"); @@ -361,15 +353,15 @@ TEST_CASE ("basic feature test 7", "[plan]") PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a")}; - auto spec_x = FullPackageSpec{spec_map.emplace("x", "a"), {"core"}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {"b1"}}; + spec_map.emplace("a"); + spec_map.emplace("x", "a"); + spec_map.emplace("b", "", {{"b1", ""}}); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; auto plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&spec_b, 1}, StatusParagraphs(std::move(status_paragraphs))); + map_port, var_provider, Test::parse_test_fspecs("b[b1]"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(plan.size() == 5); remove_plan_check(plan.remove_actions.at(0), "x"); @@ -388,21 +380,18 @@ TEST_CASE ("basic feature test 8", "[plan]") status_paragraphs.back()->package.spec = PackageSpec("a", Test::X64_WINDOWS); PackageSpecMap spec_map(Test::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"a1", ""}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b")}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "a[a1]"), {"core"}}; - - spec_map.triplet = Test::X86_WINDOWS; - auto spec_a_86 = FullPackageSpec{PackageSpec{"a", Test::X86_WINDOWS}}; - auto spec_b_86 = FullPackageSpec{PackageSpec{"b", Test::X86_WINDOWS}}; - auto spec_c_86 = FullPackageSpec{PackageSpec{"c", Test::X86_WINDOWS}}; + spec_map.emplace("a", "b", {{"a1", ""}}); + spec_map.emplace("b"); + spec_map.emplace("c", "a[a1]"); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; - std::vector full_package_specs{spec_c_64, spec_a_86, spec_a_64, spec_c_86}; auto plan = Dependencies::create_feature_install_plan( - map_port, var_provider, full_package_specs, StatusParagraphs(std::move(status_paragraphs))); + map_port, + var_provider, + Test::parse_test_fspecs("c[core]:x64-windows a a[core]:x64-windows c"), + StatusParagraphs(std::move(status_paragraphs))); remove_plan_check(plan.remove_actions.at(0), "a", Test::X64_WINDOWS); remove_plan_check(plan.remove_actions.at(1), "a"); @@ -420,18 +409,14 @@ TEST_CASE ("install all features test", "[plan]") std::vector> status_paragraphs; PackageSpecMap spec_map(Test::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}), {"core"}}; - - auto install_specs = FullPackageSpec::from_string("a[*]", Test::X64_WINDOWS); - REQUIRE(install_specs.has_value()); - if (!install_specs.has_value()) return; + spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a[*]:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 1); @@ -446,15 +431,13 @@ TEST_CASE ("install default features test 1", "[plan]") PackageSpecMap spec_map(Test::X64_WINDOWS); spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}, {"1"}); - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Test::X64_WINDOWS); - PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; + // Install "a" (without explicit feature specification) auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); // Expect the default feature "1" to be installed, but not "0" @@ -465,7 +448,7 @@ TEST_CASE ("install default features test 1", "[plan]") TEST_CASE ("install default features test 2", "[plan]") { std::vector> status_paragraphs; - status_paragraphs.push_back(make_status_pgh("a")); + status_paragraphs.push_back(make_status_pgh("a", "", "a1")); status_paragraphs.back()->package.spec = PackageSpec("a", Test::X64_WINDOWS); // Add a port "a" of which "core" is already installed, but we will @@ -474,15 +457,13 @@ TEST_CASE ("install default features test 2", "[plan]") PackageSpecMap spec_map(Test::X64_WINDOWS); spec_map.emplace("a", "", {{"a0", ""}, {"a1", ""}}, {"a1"}); - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Test::X64_WINDOWS); - PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; + // Install "a" (without explicit feature specification) auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); // Expect "a" to get removed for rebuild and then installed with default @@ -500,15 +481,13 @@ TEST_CASE ("install default features test 3", "[plan]") PackageSpecMap spec_map(Test::X64_WINDOWS); spec_map.emplace("a", "", {{"a0", ""}, {"a1", ""}}, {"a1"}); - // Explicitly install "a" without default features - auto install_specs = FullPackageSpec::from_string("a[core]", Test::X64_WINDOWS); - PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; + // Explicitly install "a" without default features auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a[core]:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); // Expect the default feature not to get installed. @@ -526,14 +505,13 @@ TEST_CASE ("install default features of dependency test 1", "[plan]") // "b" has two features, of which "b1" is default. spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Test::X64_WINDOWS); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; + // Install "a" (without explicit feature specification) auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); // Expect "a" to get installed and defaults of "b" through the dependency, @@ -553,17 +531,14 @@ TEST_CASE ("do not install default features of dependency test 1", "[plan]") // "b" has two features, of which "b1" is default. spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); - // Install "a" (without explicit feature specification) - auto spec_a = FullPackageSpec::from_string("a", Test::X64_WINDOWS); - auto spec_b = FullPackageSpec::from_string("b[core]", Test::X64_WINDOWS); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; - std::vector full_package_specs; - full_package_specs.push_back(spec_a.value_or_exit(VCPKG_LINE_INFO)); - full_package_specs.push_back(spec_b.value_or_exit(VCPKG_LINE_INFO)); - auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, full_package_specs, StatusParagraphs(std::move(status_paragraphs))); + auto install_plan = + Dependencies::create_feature_install_plan(map_port, + var_provider, + Test::parse_test_fspecs("a:x64-windows b[core]:x64-windows"), + StatusParagraphs(std::move(status_paragraphs))); // Expect "a" to get installed and defaults of "b" through the dependency, // as no explicit features of "b" are installed by the user. @@ -582,17 +557,14 @@ TEST_CASE ("install default features of dependency test 2", "[plan]") // "b" has two features, of which "b1" is default. spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); - // Install "a" (without explicit feature specification) - auto spec_a = FullPackageSpec::from_string("a", Test::X64_WINDOWS); - auto spec_b = FullPackageSpec::from_string("b[core]", Test::X64_WINDOWS); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; - std::vector full_package_specs; - full_package_specs.push_back(spec_a.value_or_exit(VCPKG_LINE_INFO)); - full_package_specs.push_back(spec_b.value_or_exit(VCPKG_LINE_INFO)); - auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, full_package_specs, StatusParagraphs(std::move(status_paragraphs))); + auto install_plan = + Dependencies::create_feature_install_plan(map_port, + var_provider, + Test::parse_test_fspecs("a:x64-windows b[core]:x64-windows"), + StatusParagraphs(std::move(status_paragraphs))); // Expect "a" to get installed and defaults of "b" through the dependency REQUIRE(install_plan.size() == 2); @@ -613,14 +585,12 @@ TEST_CASE ("do not install default features of existing dependency", "[plan]") status_paragraphs.push_back(make_status_pgh("b")); status_paragraphs.back()->package.spec = PackageSpec("b", Test::X64_WINDOWS); - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Test::X64_WINDOWS); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); // Expect "a" to get installed, but not require rebuilding "b" @@ -641,14 +611,12 @@ TEST_CASE ("install default features of existing dependency", "[plan]") status_paragraphs.push_back(make_status_pgh("b", "", "b1")); status_paragraphs.back()->package.spec = PackageSpec("b", Test::X64_WINDOWS); - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Test::X64_WINDOWS); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); // Expect "b" to be rebuilt @@ -669,14 +637,12 @@ TEST_CASE ("install default features of dependency test 3", "[plan]") // "b" has two features, of which "b1" is default. spec_map.emplace("b", "", {{"b0", ""}, {"b1", ""}}, {"b1"}); - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Test::X64_WINDOWS); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); // Expect "a" to get installed, not the defaults of "b", as the required @@ -696,14 +662,12 @@ TEST_CASE ("install plan action dependencies", "[plan]") auto spec_b = spec_map.emplace("b", "c"); spec_map.emplace("a", "b"); - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Test::X64_WINDOWS); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 3); @@ -728,14 +692,12 @@ TEST_CASE ("install plan action dependencies 2", "[plan]") auto spec_b = spec_map.emplace("b", "c"); spec_map.emplace("a", "c, b"); - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Test::X64_WINDOWS); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 3); @@ -758,14 +720,12 @@ TEST_CASE ("install plan action dependencies 3", "[plan]") PackageSpecMap spec_map(Test::X64_WINDOWS); spec_map.emplace("a", "", {{"0", ""}, {"1", "a[0]"}}, {"1"}); - // Install "a" (without explicit feature specification) - auto install_specs = FullPackageSpec::from_string("a", Test::X64_WINDOWS); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 1); @@ -786,13 +746,8 @@ TEST_CASE ("install with default features", "[plan]") PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; - std::vector full_package_specs{ - FullPackageSpec{a_spec, {"0"}}, - FullPackageSpec{b_spec, {"core"}}, - }; - auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, full_package_specs, StatusParagraphs(std::move(status_db))); + map_port, var_provider, Test::parse_test_fspecs("a[0] b[core]"), status_db); // Install "a" and indicate that "b" should not install default features REQUIRE(install_plan.size() == 3); @@ -897,19 +852,15 @@ TEST_CASE ("transitive features test", "[plan]") std::vector> status_paragraphs; PackageSpecMap spec_map(Test::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"0", "b[0]"}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "c", {{"0", "c[0]"}}), {"core"}}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; - - auto install_specs = FullPackageSpec::from_string("a[*]", Test::X64_WINDOWS); - REQUIRE(install_specs.has_value()); - if (!install_specs.has_value()) return; + spec_map.emplace("a", "b", {{"0", "b[0]"}}); + spec_map.emplace("b", "c", {{"0", "c[0]"}}); + spec_map.emplace("c", "", {{"0", ""}}); PortFileProvider::MapPortFileProvider provider(spec_map.map); MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan(provider, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a[*]:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 3); @@ -923,18 +874,15 @@ TEST_CASE ("no transitive features test", "[plan]") std::vector> status_paragraphs; PackageSpecMap spec_map(Test::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "b", {{"0", ""}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "c", {{"0", ""}}), {"core"}}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; + spec_map.emplace("a", "b", {{"0", ""}}); + spec_map.emplace("b", "c", {{"0", ""}}); + spec_map.emplace("c", "", {{"0", ""}}); - auto install_specs = FullPackageSpec::from_string("a[*]", Test::X64_WINDOWS); - REQUIRE(install_specs.has_value()); - if (!install_specs.has_value()) return; PortFileProvider::MapPortFileProvider provider(spec_map.map); MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan(provider, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a[*]:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 3); @@ -948,18 +896,15 @@ TEST_CASE ("only transitive features test", "[plan]") std::vector> status_paragraphs; PackageSpecMap spec_map(Test::X64_WINDOWS); - auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "", {{"0", "b[0]"}}), {"core"}}; - auto spec_b_64 = FullPackageSpec{spec_map.emplace("b", "", {{"0", "c[0]"}}), {"core"}}; - auto spec_c_64 = FullPackageSpec{spec_map.emplace("c", "", {{"0", ""}}), {"core"}}; + spec_map.emplace("a", "", {{"0", "b[0]"}}); + spec_map.emplace("b", "", {{"0", "c[0]"}}); + spec_map.emplace("c", "", {{"0", ""}}); - auto install_specs = FullPackageSpec::from_string("a[*]", Test::X64_WINDOWS); - REQUIRE(install_specs.has_value()); - if (!install_specs.has_value()) return; PortFileProvider::MapPortFileProvider provider(spec_map.map); MockCMakeVarProvider var_provider; auto install_plan = Dependencies::create_feature_install_plan(provider, var_provider, - {&install_specs.value_or_exit(VCPKG_LINE_INFO), 1}, + Test::parse_test_fspecs("a[*]:x64-windows"), StatusParagraphs(std::move(status_paragraphs))); REQUIRE(install_plan.size() == 3); @@ -1082,18 +1027,16 @@ TEST_CASE ("self-referencing scheme", "[plan]") SECTION ("basic") { - auto fullspec_a = FullPackageSpec{spec_a, {}}; auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&fullspec_a, 1}, {}, {{}, Test::X64_WINDOWS}); + map_port, var_provider, Test::parse_test_fspecs("a"), {}, {{}, Test::X64_WINDOWS}); REQUIRE(install_plan.size() == 1); REQUIRE(install_plan.install_actions.at(0).spec == spec_a); } SECTION ("qualified") { - auto fullspec_b = FullPackageSpec{spec_b, {}}; auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&fullspec_b, 1}, {}, {{}, Test::X64_WINDOWS}); + map_port, var_provider, Test::parse_test_fspecs("b"), {}, {{}, Test::X64_WINDOWS}); REQUIRE(install_plan.size() == 1); REQUIRE(install_plan.install_actions.at(0).spec == spec_b); @@ -1114,10 +1057,9 @@ TEST_CASE ("basic tool port scheme", "[plan]") PortFileProvider::MapPortFileProvider map_port(spec_map.map); MockCMakeVarProvider var_provider; - auto fullspec_a = FullPackageSpec{spec_a, {}}; auto install_plan = Dependencies::create_feature_install_plan(map_port, var_provider, - {&fullspec_a, 1}, + Test::parse_test_fspecs("a"), StatusParagraphs(std::move(status_paragraphs)), {{}, Test::X64_WINDOWS}); @@ -1136,6 +1078,8 @@ TEST_CASE ("basic existing tool port scheme", "[plan]") StatusParagraphs status_db(std::move(pghs)); MockCMakeVarProvider var_provider; + const auto fspecs_a = Test::parse_test_fspecs("a"); + SECTION ("a+b") { PackageSpecMap spec_map; @@ -1146,9 +1090,8 @@ TEST_CASE ("basic existing tool port scheme", "[plan]") PortFileProvider::MapPortFileProvider map_port(spec_map.map); - auto fullspec_a = FullPackageSpec{spec_a, {}}; auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&fullspec_a, 1}, status_db, {{}, Test::X64_WINDOWS}); + map_port, var_provider, fspecs_a, status_db, {{}, Test::X64_WINDOWS}); REQUIRE(install_plan.size() == 1); REQUIRE(install_plan.install_actions.at(0).spec == spec_a); @@ -1163,9 +1106,8 @@ TEST_CASE ("basic existing tool port scheme", "[plan]") PortFileProvider::MapPortFileProvider map_port(spec_map.map); - auto fullspec_a = FullPackageSpec{spec_a, {}}; auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&fullspec_a, 1}, status_db, {{}, Test::X64_WINDOWS}); + map_port, var_provider, fspecs_a, status_db, {{}, Test::X64_WINDOWS}); REQUIRE(install_plan.size() == 2); REQUIRE(install_plan.install_actions.at(0).spec.name() == "a"); @@ -1173,7 +1115,7 @@ TEST_CASE ("basic existing tool port scheme", "[plan]") REQUIRE(install_plan.install_actions.at(1).spec == spec_a); install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&fullspec_a, 1}, status_db, {{}, Test::X86_WINDOWS}); + map_port, var_provider, fspecs_a, status_db, {{}, Test::X86_WINDOWS}); REQUIRE(install_plan.size() == 1); REQUIRE(install_plan.install_actions.at(0).spec == spec_a); @@ -1189,9 +1131,8 @@ TEST_CASE ("basic existing tool port scheme", "[plan]") PortFileProvider::MapPortFileProvider map_port(spec_map.map); - auto fullspec_a = FullPackageSpec{spec_a, {}}; - auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&fullspec_a, 1}, status_db, {{}, Test::ARM_UWP}); + auto install_plan = + Dependencies::create_feature_install_plan(map_port, var_provider, fspecs_a, status_db, {{}, Test::ARM_UWP}); REQUIRE(install_plan.size() == 2); REQUIRE(install_plan.install_actions.at(0).spec.name() == "b"); @@ -1210,9 +1151,8 @@ TEST_CASE ("basic existing tool port scheme", "[plan]") PortFileProvider::MapPortFileProvider map_port(spec_map.map); - auto fullspec_a = FullPackageSpec{spec_a, {}}; auto install_plan = Dependencies::create_feature_install_plan( - map_port, var_provider, {&fullspec_a, 1}, status_db, {{}, Test::X64_WINDOWS}); + map_port, var_provider, fspecs_a, status_db, {{}, Test::X64_WINDOWS}); REQUIRE(install_plan.size() == 1); REQUIRE(install_plan.install_actions.at(0).spec == spec_a); diff --git a/src/vcpkg-test/specifier.cpp b/src/vcpkg-test/specifier.cpp index 5e3b4ea07f..d39429a485 100644 --- a/src/vcpkg-test/specifier.cpp +++ b/src/vcpkg-test/specifier.cpp @@ -13,19 +13,19 @@ TEST_CASE ("specifier conversion", "[specifier]") { SECTION ("full package spec to feature specs") { - constexpr std::size_t SPEC_SIZE = 6; + constexpr std::size_t SPEC_SIZE = 4; PackageSpec a_spec("a", Test::X64_WINDOWS); PackageSpec b_spec("b", Test::X64_WINDOWS); - auto fspecs = FullPackageSpec{a_spec, {"0", "1"}}.to_feature_specs({}, {}); - auto fspecs2 = FullPackageSpec{b_spec, {"2", "3"}}.to_feature_specs({}, {}); - Util::Vectors::append(&fspecs, fspecs2); + std::vector fspecs; + FullPackageSpec{a_spec, {"0", "1"}}.expand_fspecs_to(fspecs); + FullPackageSpec{b_spec, {"2", "3"}}.expand_fspecs_to(fspecs); Util::sort(fspecs); REQUIRE(fspecs.size() == SPEC_SIZE); - std::array features = {"0", "1", "core", "2", "3", "core"}; - std::array specs = {&a_spec, &a_spec, &a_spec, &b_spec, &b_spec, &b_spec}; + std::array features = {"0", "1", "2", "3"}; + std::array specs = {&a_spec, &a_spec, &b_spec, &b_spec}; for (std::size_t i = 0; i < SPEC_SIZE; ++i) { @@ -94,27 +94,30 @@ TEST_CASE ("specifier parsing", "[specifier]") REQUIRE(spec.features.value_or(std::vector{}) == std::vector{"*"}); } - SECTION ("expand wildcards") + SECTION ("dont expand wildcards") { - auto zlib = vcpkg::FullPackageSpec::from_string("zlib[0,1]", Test::X86_UWP).value_or_exit(VCPKG_LINE_INFO); - auto openssl = vcpkg::FullPackageSpec::from_string("openssl[*]", Test::X86_UWP).value_or_exit(VCPKG_LINE_INFO); - auto specs = zlib.to_feature_specs({}, {}); - auto specs2 = openssl.to_feature_specs({}, {}); - Util::Vectors::append(&specs, specs2); + std::vector specs; + const auto fspecs = Test::parse_test_fspecs("zlib[core,0,1]:x86-uwp openssl[*]:x86-uwp"); + for (auto&& fs : fspecs) + fs.expand_fspecs_to(specs); Util::sort(specs); std::vector spectargets{ {{"openssl", Test::X86_UWP}, "core"}, + {{"openssl", Test::X86_UWP}, "default"}, + {{"openssl", Test::X86_UWP}, "*"}, {{"zlib", Test::X86_UWP}, "core"}, {{"zlib", Test::X86_UWP}, "0"}, {{"zlib", Test::X86_UWP}, "1"}, }; Util::sort(spectargets); - REQUIRE(specs.size() == spectargets.size()); - REQUIRE(specs == spectargets); + Test::check_ranges(specs, spectargets); } +} #if defined(_WIN32) +TEST_CASE ("ascii to utf16", "[utf16]") +{ SECTION ("ASCII to utf16") { auto str = vcpkg::Strings::to_utf16("abc"); @@ -126,5 +129,5 @@ TEST_CASE ("specifier parsing", "[specifier]") auto str = vcpkg::Strings::to_utf16("abc -x86-windows"); REQUIRE(str == L"abc -x86-windows"); } -#endif } +#endif diff --git a/src/vcpkg-test/versionplan.cpp b/src/vcpkg-test/versionplan.cpp index a66abb10b7..2e165807d3 100644 --- a/src/vcpkg-test/versionplan.cpp +++ b/src/vcpkg-test/versionplan.cpp @@ -25,6 +25,9 @@ TEST_CASE ("parse depends", "[dependencies]") TEST_CASE ("filter depends", "[dependencies]") { + const std::vector defaults{"core", "default"}; + const std::vector core{"core"}; + const std::unordered_map x64_win_cmake_vars{{"VCPKG_TARGET_ARCHITECTURE", "x64"}, {"VCPKG_CMAKE_SYSTEM_NAME", ""}}; @@ -34,15 +37,26 @@ TEST_CASE ("filter depends", "[dependencies]") auto deps_ = parse_dependencies_list("liba (!uwp), libb, libc (uwp)"); REQUIRE(deps_); auto& deps = *deps_.get(); - auto v = filter_dependencies(deps, Test::X64_WINDOWS, Test::X86_WINDOWS, x64_win_cmake_vars); - REQUIRE(v.size() == 2); - REQUIRE(v.at(0).package_spec.name() == "liba"); - REQUIRE(v.at(1).package_spec.name() == "libb"); + SECTION ("x64-windows") + { + auto v = + filter_dependencies(deps, Test::X64_WINDOWS, Test::X86_WINDOWS, x64_win_cmake_vars, ImplicitDefault::YES); + REQUIRE(v.size() == 2); + REQUIRE(v.at(0).package_spec.name() == "liba"); + REQUIRE(v.at(0).features == defaults); + REQUIRE(v.at(1).package_spec.name() == "libb"); + REQUIRE(v.at(1).features == defaults); + } - auto v2 = filter_dependencies(deps, Test::ARM_UWP, Test::X86_WINDOWS, arm_uwp_cmake_vars); - REQUIRE(v.size() == 2); - REQUIRE(v2.at(0).package_spec.name() == "libb"); - REQUIRE(v2.at(1).package_spec.name() == "libc"); + SECTION ("arm-uwp") + { + auto v2 = filter_dependencies(deps, Test::ARM_UWP, Test::X86_WINDOWS, arm_uwp_cmake_vars, ImplicitDefault::NO); + REQUIRE(v2.size() == 2); + REQUIRE(v2.at(0).package_spec.name() == "libb"); + REQUIRE(v2.at(0).features == core); + REQUIRE(v2.at(1).package_spec.name() == "libc"); + REQUIRE(v2.at(1).features == core); + } } TEST_CASE ("parse feature depends", "[dependencies]") @@ -70,94 +84,21 @@ TEST_CASE ("qualified dependency", "[dependencies]") { using namespace Test; PackageSpecMap spec_map; - auto spec_a = FullPackageSpec{spec_map.emplace("a", "b, b[b1] (linux)"), {}}; - auto spec_b = FullPackageSpec{spec_map.emplace("b", "", {{"b1", ""}}), {}}; + spec_map.emplace("a", "b, b[b1] (linux)"); + spec_map.emplace("b", "", {{"b1", ""}}); PortFileProvider::MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; + var_provider.dep_info_vars[{"a", Triplet::from_canonical_name("x64-linux")}].emplace("VCPKG_CMAKE_SYSTEM_NAME", + "Linux"); - auto plan = vcpkg::Dependencies::create_feature_install_plan(map_port, var_provider, {&spec_a, 1}, {}); + auto plan = + vcpkg::Dependencies::create_feature_install_plan(map_port, var_provider, Test::parse_test_fspecs("a"), {}); REQUIRE(plan.install_actions.size() == 2); REQUIRE(plan.install_actions.at(0).feature_list == std::vector{"core"}); - FullPackageSpec linspec_a{{"a", Triplet::from_canonical_name("x64-linux")}, {}}; - var_provider.dep_info_vars[linspec_a.package_spec].emplace("VCPKG_CMAKE_SYSTEM_NAME", "Linux"); - auto plan2 = vcpkg::Dependencies::create_feature_install_plan(map_port, var_provider, {&linspec_a, 1}, {}); + auto plan2 = vcpkg::Dependencies::create_feature_install_plan( + map_port, var_provider, Test::parse_test_fspecs("a:x64-linux"), {}); REQUIRE(plan2.install_actions.size() == 2); REQUIRE(plan2.install_actions.at(0).feature_list == std::vector{"b1", "core"}); } - -TEST_CASE ("resolve_deps_as_top_level", "[dependencies]") -{ - using namespace Test; - PackageSpecMap spec_map; - FullPackageSpec spec_a{spec_map.emplace("a", "b, b[b1] (linux)"), {}}; - FullPackageSpec spec_b{spec_map.emplace("b", "", {{"b1", ""}}), {}}; - FullPackageSpec spec_c{spec_map.emplace("c", "b", {{"c1", "b[b1]"}, {"c2", "c[c1], a"}}, {"c1"}), {"core"}}; - FullPackageSpec spec_d{spec_map.emplace("d", "c[core]"), {}}; - FullPackageSpec spec_e{spec_map.emplace("e", "c[core]"), {}}; - spec_map.map.at("e").source_control_file->core_paragraph->dependencies[0].host = true; - - PortFileProvider::MapPortFileProvider map_port{spec_map.map}; - MockCMakeVarProvider var_provider; - Triplet t_linux = Triplet::from_canonical_name("x64-linux"); - var_provider.dep_info_vars[{"a", t_linux}].emplace("VCPKG_CMAKE_SYSTEM_NAME", "Linux"); - { - auto deps = vcpkg::Dependencies::resolve_deps_as_top_level( - *spec_map.map.at("a").source_control_file, Test::X86_WINDOWS, Test::ARM_UWP, {}, var_provider); - REQUIRE(deps.size() == 1); - REQUIRE(deps.at(0) == spec_b); - } - { - auto deps = vcpkg::Dependencies::resolve_deps_as_top_level( - *spec_map.map.at("a").source_control_file, t_linux, Test::ARM_UWP, {}, var_provider); - REQUIRE(deps.size() == 1); - REQUIRE(deps.at(0) == FullPackageSpec({"b", t_linux}, {"b1"})); - } - { - // without defaults - auto deps = vcpkg::Dependencies::resolve_deps_as_top_level( - *spec_map.map.at("c").source_control_file, Test::X86_WINDOWS, Test::ARM_UWP, {}, var_provider); - REQUIRE(deps.size() == 1); - REQUIRE(deps.at(0) == spec_b); - } - FullPackageSpec spec_b_with_b1{spec_b.package_spec, {"b1"}}; - { - // with defaults of c (c1) - auto deps = vcpkg::Dependencies::resolve_deps_as_top_level( - *spec_map.map.at("c").source_control_file, Test::X86_WINDOWS, Test::ARM_UWP, {"default"}, var_provider); - REQUIRE(deps.size() == 1); - REQUIRE(deps.at(0) == spec_b_with_b1); - } - { - // with c1 - auto deps = vcpkg::Dependencies::resolve_deps_as_top_level( - *spec_map.map.at("c").source_control_file, Test::X86_WINDOWS, Test::ARM_UWP, {"c1"}, var_provider); - REQUIRE(deps.size() == 1); - REQUIRE(deps.at(0) == spec_b_with_b1); - } - { - // with c2 implying c1 - auto deps = vcpkg::Dependencies::resolve_deps_as_top_level( - *spec_map.map.at("c").source_control_file, Test::X86_WINDOWS, Test::ARM_UWP, {"c2"}, var_provider); - REQUIRE(deps.size() == 2); - REQUIRE(deps.at(0) == spec_a); - REQUIRE(deps.at(1) == spec_b_with_b1); - } - { - // d -> c[core] - auto deps = vcpkg::Dependencies::resolve_deps_as_top_level( - *spec_map.map.at("d").source_control_file, Test::X86_WINDOWS, Test::ARM_UWP, {}, var_provider); - REQUIRE(deps.size() == 1); - REQUIRE(deps.at(0) == spec_c); - } - SECTION ("host dep") - { - // e -> c[core]:$host - auto deps = vcpkg::Dependencies::resolve_deps_as_top_level( - *spec_map.map.at("e").source_control_file, Test::X86_WINDOWS, Test::ARM_UWP, {}, var_provider); - REQUIRE(deps.size() == 1); - REQUIRE(deps.at(0).package_spec.name() == "c"); - REQUIRE(deps.at(0).package_spec.triplet() == Test::ARM_UWP); - } -} diff --git a/src/vcpkg/build.cpp b/src/vcpkg/build.cpp index cb505343eb..46787a0fcc 100644 --- a/src/vcpkg/build.cpp +++ b/src/vcpkg/build.cpp @@ -107,7 +107,7 @@ namespace vcpkg::Build StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); auto action_plan = Dependencies::create_feature_install_plan( - provider, var_provider, std::vector{full_spec}, status_db, {host_triplet}); + provider, var_provider, {&full_spec, 1}, status_db, {host_triplet}); var_provider.load_tag_vars(action_plan, provider, host_triplet); @@ -185,9 +185,7 @@ namespace vcpkg::Build BinaryCache binary_cache{args}; const FullPackageSpec spec = Input::check_and_get_full_package_spec( - std::move(first_arg), default_triplet, COMMAND_STRUCTURE.example_text); - - Input::check_triplet(spec.package_spec.triplet(), paths); + std::move(first_arg), default_triplet, COMMAND_STRUCTURE.example_text, paths); PathsPortFileProvider provider(paths, args.overlay_ports); const auto port_name = spec.package_spec.name(); diff --git a/src/vcpkg/cmakevars.cpp b/src/vcpkg/cmakevars.cpp index 6a07f973e6..8e2920c1ae 100644 --- a/src/vcpkg/cmakevars.cpp +++ b/src/vcpkg/cmakevars.cpp @@ -175,11 +175,19 @@ endfunction() { const FullPackageSpec& spec = *spec_abi_setting.first; + std::string featurelist; + for (auto&& f : spec.features) + { + if (f == "core" || f == "default" || f == "*") continue; + if (!featurelist.empty()) featurelist.push_back(';'); + featurelist.append(f); + } + Strings::append(extraction_file, "vcpkg_get_tags(\"", spec.package_spec.name(), "\" \"", - Strings::join(";", spec.features), + featurelist, "\" \"", emitted_triplets[spec.package_spec.triplet()], "\" \"", @@ -302,7 +310,7 @@ endfunction() { std::vector>> vars(1); // Hack: PackageSpecs should never have .name=="" - FullPackageSpec full_spec({"", triplet}); + FullPackageSpec full_spec({"", triplet}, {}); const auto file_path = create_tag_extraction_file(std::array, 1>{ std::pair{&full_spec, ""}}); launch_and_split(file_path, vars); diff --git a/src/vcpkg/commands.buildexternal.cpp b/src/vcpkg/commands.buildexternal.cpp index afe65c2771..978c92fbbf 100644 --- a/src/vcpkg/commands.buildexternal.cpp +++ b/src/vcpkg/commands.buildexternal.cpp @@ -27,8 +27,7 @@ namespace vcpkg::Commands::BuildExternal BinaryCache binary_cache{args}; const FullPackageSpec spec = Input::check_and_get_full_package_spec( - std::string(args.command_arguments.at(0)), default_triplet, COMMAND_STRUCTURE.example_text); - Input::check_triplet(spec.package_spec.triplet(), paths); + std::string(args.command_arguments.at(0)), default_triplet, COMMAND_STRUCTURE.example_text, paths); auto overlays = args.overlay_ports; overlays.insert(overlays.begin(), args.command_arguments.at(1)); diff --git a/src/vcpkg/commands.check-support.cpp b/src/vcpkg/commands.check-support.cpp index 7656b7a7df..87b511e4be 100644 --- a/src/vcpkg/commands.check-support.cpp +++ b/src/vcpkg/commands.check-support.cpp @@ -108,14 +108,9 @@ namespace vcpkg::Commands const std::vector specs = Util::fmap(args.command_arguments, [&](auto&& arg) { return Input::check_and_get_full_package_spec( - std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text); + std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text, paths); }); - for (auto&& spec : specs) - { - Input::check_triplet(spec.package_spec.triplet(), paths); - } - PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports); auto cmake_vars = CMakeVars::make_triplet_cmake_var_provider(paths); diff --git a/src/vcpkg/commands.ci.cpp b/src/vcpkg/commands.ci.cpp index 7f1a323c0e..63845d82ea 100644 --- a/src/vcpkg/commands.ci.cpp +++ b/src/vcpkg/commands.ci.cpp @@ -528,12 +528,7 @@ namespace vcpkg::Commands::CI std::vector specs = PackageSpec::to_package_specs(all_ports, target_triplet); // Install the default features for every package - auto all_default_full_specs = Util::fmap(specs, [&](auto& spec) { - std::vector default_features = - provider.get_control_file(spec.name()).get()->source_control_file->core_paragraph->default_features; - default_features.emplace_back("core"); - return FullPackageSpec{spec, std::move(default_features)}; - }); + auto all_default_full_specs = Util::fmap(specs, [&](auto& spec) { return FullPackageSpec{spec, {"default"}}; }); Dependencies::CreateInstallPlanOptions serialize_options(host_triplet, Dependencies::UnsupportedPortAction::Warn); diff --git a/src/vcpkg/commands.dependinfo.cpp b/src/vcpkg/commands.dependinfo.cpp index 7c52e86b8a..b0c1351f7b 100644 --- a/src/vcpkg/commands.dependinfo.cpp +++ b/src/vcpkg/commands.dependinfo.cpp @@ -308,14 +308,9 @@ namespace vcpkg::Commands::DependInfo const std::vector specs = Util::fmap(args.command_arguments, [&](auto&& arg) { return Input::check_and_get_full_package_spec( - std::string{arg}, default_triplet, COMMAND_STRUCTURE.example_text); + std::string{arg}, default_triplet, COMMAND_STRUCTURE.example_text, paths); }); - for (auto&& spec : specs) - { - Input::check_triplet(spec.package_spec.triplet(), paths); - } - PathsPortFileProvider provider(paths, args.overlay_ports); auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths); auto& var_provider = *var_provider_storage; diff --git a/src/vcpkg/commands.setinstalled.cpp b/src/vcpkg/commands.setinstalled.cpp index 54ffce1fae..86da98a76c 100644 --- a/src/vcpkg/commands.setinstalled.cpp +++ b/src/vcpkg/commands.setinstalled.cpp @@ -150,14 +150,9 @@ namespace vcpkg::Commands::SetInstalled const std::vector specs = Util::fmap(args.command_arguments, [&](auto&& arg) { return Input::check_and_get_full_package_spec( - std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text); + std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text, paths); }); - for (auto&& spec : specs) - { - Input::check_triplet(spec.package_spec.triplet(), paths); - } - BinaryCache binary_cache{args}; const bool dry_run = Util::Sets::contains(options.switches, OPTION_DRY_RUN); diff --git a/src/vcpkg/commands.upgrade.cpp b/src/vcpkg/commands.upgrade.cpp index 8f17709e7e..4f8fa81ae4 100644 --- a/src/vcpkg/commands.upgrade.cpp +++ b/src/vcpkg/commands.upgrade.cpp @@ -70,14 +70,10 @@ namespace vcpkg::Commands::Upgrade // input sanitization const std::vector specs = Util::fmap(args.command_arguments, [&](auto&& arg) { - return Input::check_and_get_package_spec(std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text); + return Input::check_and_get_package_spec( + std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text, paths); }); - for (auto&& spec : specs) - { - Input::check_triplet(spec.triplet(), paths); - } - Dependencies::ActionPlan action_plan; if (specs.empty()) { diff --git a/src/vcpkg/dependencies.cpp b/src/vcpkg/dependencies.cpp index 99106bcc5f..bbcd7feaed 100644 --- a/src/vcpkg/dependencies.cpp +++ b/src/vcpkg/dependencies.cpp @@ -93,13 +93,15 @@ namespace vcpkg::Dependencies std::vector& out_new_dependencies, Triplet host_triplet) { + const auto& scfl = get_scfl_or_exit(); + ClusterInstallInfo& info = m_install_info.value_or_exit(VCPKG_LINE_INFO); if (feature == "default") { if (!info.defaults_requested) { info.defaults_requested = true; - for (auto&& f : get_scfl_or_exit().source_control_file->core_paragraph->default_features) + for (auto&& f : scfl.source_control_file->core_paragraph->default_features) out_new_dependencies.emplace_back(m_spec, f); } return; @@ -112,7 +114,7 @@ namespace vcpkg::Dependencies } auto maybe_vars = var_provider.get_dep_info_vars(m_spec); Optional&> maybe_qualified_deps = - get_scfl_or_exit().source_control_file->find_dependencies_for_feature(feature); + scfl.source_control_file->find_dependencies_for_feature(feature); if (!maybe_qualified_deps.has_value()) { Checks::exit_with_message( @@ -124,11 +126,12 @@ namespace vcpkg::Dependencies if (auto vars = maybe_vars.get()) { // Qualified dependency resolution is available - auto fullspec_list = filter_dependencies(*qualified_deps, m_spec.triplet(), host_triplet, *vars); + auto fullspec_list = filter_dependencies( + *qualified_deps, m_spec.triplet(), host_triplet, *vars, ImplicitDefault::YES); for (auto&& fspec : fullspec_list) { - Util::Vectors::append(&dep_list, fspec.to_feature_specs({"default"}, {"default"})); + fspec.expand_fspecs_to(dep_list); } Util::sort_unique_erase(dep_list); @@ -141,10 +144,8 @@ namespace vcpkg::Dependencies { if (dep.platform.is_empty()) { - auto t = dep.host ? host_triplet : m_spec.triplet(); - Util::Vectors::append(&dep_list, - FullPackageSpec({dep.name, t}, dep.features) - .to_feature_specs({"default"}, {"default"})); + dep.to_full_spec(m_spec.triplet(), host_triplet, ImplicitDefault::YES) + .expand_fspecs_to(dep_list); } else { @@ -677,74 +678,6 @@ namespace vcpkg::Dependencies m_graph->get(spec).request_type = RequestType::USER_REQUESTED; } - // `features` should have "default" instead of missing "core" - std::vector resolve_deps_as_top_level(const SourceControlFile& scf, - Triplet triplet, - Triplet host_triplet, - std::vector features, - CMakeVars::CMakeVarProvider& var_provider) - { - PackageSpec spec{scf.core_paragraph->name, triplet}; - std::map> specs_to_features; - - Optional ctx_storage = var_provider.get_dep_info_vars(spec); - auto ctx = [&]() -> const PlatformExpression::Context& { - if (!ctx_storage) - { - var_provider.load_dep_info_vars({&spec, 1}, host_triplet); - ctx_storage = var_provider.get_dep_info_vars(spec); - } - return ctx_storage.value_or_exit(VCPKG_LINE_INFO); - }; - - auto handle_deps = [&](View deps) { - for (auto&& dep : deps) - { - if (dep.platform.is_empty() || dep.platform.evaluate(ctx())) - { - if (dep.name == spec.name()) - Util::Vectors::append(&features, dep.features); - else - { - auto t = dep.host ? host_triplet : triplet; - Util::Vectors::append(&specs_to_features[{dep.name, t}], dep.features); - } - } - } - }; - - handle_deps(scf.core_paragraph->dependencies); - enum class State - { - NotVisited = 0, - Visited, - }; - std::map feature_state; - while (!features.empty()) - { - auto feature = std::move(features.back()); - features.pop_back(); - - if (feature_state[feature] == State::Visited) continue; - feature_state[feature] = State::Visited; - if (feature == "default") - { - Util::Vectors::append(&features, scf.core_paragraph->default_features); - } - else - { - auto it = - Util::find_if(scf.feature_paragraphs, [&feature](const std::unique_ptr& ptr) { - return ptr->name == feature; - }); - if (it != scf.feature_paragraphs.end()) handle_deps(it->get()->dependencies); - } - } - return Util::fmap(specs_to_features, [](std::pair>& p) { - return FullPackageSpec(p.first, Util::sort_unique_erase(std::move(p.second))); - }); - } - ActionPlan create_feature_install_plan(const PortFileProvider::PortFileProvider& port_provider, const CMakeVars::CMakeVarProvider& var_provider, View specs, @@ -756,31 +689,11 @@ namespace vcpkg::Dependencies std::vector feature_specs; for (const FullPackageSpec& spec : specs) { - auto maybe_scfl = port_provider.get_control_file(spec.package_spec.name()); - - Checks::check_maybe_upgrade(VCPKG_LINE_INFO, - maybe_scfl.has_value(), - "Error: while loading port `%s`: %s", - spec.package_spec.name(), - maybe_scfl.error()); - - const SourceControlFileAndLocation* scfl = maybe_scfl.get(); - - const std::vector all_features = - Util::fmap(scfl->source_control_file->feature_paragraphs, - [](auto&& feature_paragraph) { return feature_paragraph->name; }); - - auto fspecs = - spec.to_feature_specs(scfl->source_control_file->core_paragraph->default_features, all_features); - feature_specs.insert( - feature_specs.end(), std::make_move_iterator(fspecs.begin()), std::make_move_iterator(fspecs.end())); + pgraph.mark_user_requested(spec.package_spec); + spec.expand_fspecs_to(feature_specs); } Util::sort_unique_erase(feature_specs); - for (const FeatureSpec& spec : feature_specs) - { - pgraph.mark_user_requested(spec.spec()); - } pgraph.install(feature_specs, options.unsupported_port_action); auto res = pgraph.serialize(options.randomizer); @@ -828,12 +741,21 @@ namespace vcpkg::Dependencies while (!next_dependencies.empty()) { // Extract the top of the stack - FeatureSpec spec = std::move(next_dependencies.back()); + const FeatureSpec spec = std::move(next_dependencies.back()); next_dependencies.pop_back(); // Get the cluster for the PackageSpec of the FeatureSpec we are adding to the install graph Cluster& clust = m_graph->get(spec.spec()); - spec = FeatureSpec{clust.m_spec, spec.feature()}; + + if (spec.feature() == "*") + { + // Expand wildcard feature + for (auto&& fpgh : clust.get_scfl_or_exit().source_control_file->feature_paragraphs) + { + next_dependencies.emplace_back(spec.spec(), fpgh->name); + } + continue; + } // If this spec hasn't already had its qualified dependencies resolved if (!m_var_provider.get_dep_info_vars(spec.spec()).has_value()) @@ -1730,6 +1652,10 @@ namespace vcpkg::Dependencies const std::string& feature, const std::string& origin) { + if (feature == "default") + { + return require_port_defaults(ref, origin); + } auto inserted = ref.second.requested_features.emplace(feature).second; if (inserted) { @@ -1961,7 +1887,7 @@ namespace vcpkg::Dependencies const Versions::Version& new_ver, const PackageSpec& origin, View features) -> Optional { - auto&& node = m_graph[spec]; + auto&& node = emplace_package(spec).second; auto overlay = m_o_provider.get_control_file(spec.name()); auto over_it = m_overrides.find(spec.name()); @@ -2004,6 +1930,7 @@ namespace vcpkg::Dependencies for (auto&& f : features) { if (f == "core") continue; + if (f == "default") continue; auto feature = p_vnode->scfl->source_control_file->find_feature(f); if (!feature) { @@ -2125,8 +2052,10 @@ namespace vcpkg::Dependencies auto& back = stack.back(); if (back.deps.empty()) { - emitted[back.ipa.spec] = m_graph[back.ipa.spec].get_node( - to_version(*back.ipa.source_control_file_and_location.get()->source_control_file)); + emitted[back.ipa.spec] = + emplace_package(back.ipa.spec) + .second.get_node( + to_version(*back.ipa.source_control_file_and_location.get()->source_control_file)); ret.install_actions.push_back(std::move(back.ipa)); stack.pop_back(); } diff --git a/src/vcpkg/export.cpp b/src/vcpkg/export.cpp index a1eb43b2cd..453b48a1bf 100644 --- a/src/vcpkg/export.cpp +++ b/src/vcpkg/export.cpp @@ -421,7 +421,7 @@ namespace vcpkg::Export // input sanitization ret.specs = Util::fmap(args.command_arguments, [&](auto&& arg) { return Input::check_and_get_package_spec( - std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text); + std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text, paths); }); } @@ -630,8 +630,6 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console } const StatusParagraphs status_db = database_load_check(paths.get_filesystem(), paths.installed()); const auto opts = handle_export_command_arguments(paths, args, default_triplet, status_db); - for (auto&& spec : opts.specs) - Input::check_triplet(spec.triplet(), paths); // Load ports from ports dirs PortFileProvider::PathsPortFileProvider provider(paths, args.overlay_ports); diff --git a/src/vcpkg/input.cpp b/src/vcpkg/input.cpp index d50ef60f78..eabc0a9777 100644 --- a/src/vcpkg/input.cpp +++ b/src/vcpkg/input.cpp @@ -11,13 +11,17 @@ namespace vcpkg { PackageSpec Input::check_and_get_package_spec(std::string&& spec_string, Triplet default_triplet, - CStringView example_text) + CStringView example_text, + const VcpkgPaths& paths) { const std::string as_lowercase = Strings::ascii_to_lowercase(std::move(spec_string)); - auto expected_spec = FullPackageSpec::from_string(as_lowercase, default_triplet); - if (const auto spec = expected_spec.get()) + + auto expected_spec = + parse_qualified_specifier(as_lowercase).then(&ParsedQualifiedSpecifier::to_package_spec, default_triplet); + if (auto spec = expected_spec.get()) { - return PackageSpec{spec->package_spec}; + Input::check_triplet(spec->triplet(), paths); + return std::move(*spec); } // Intentionally show the lowercased string @@ -39,12 +43,15 @@ namespace vcpkg FullPackageSpec Input::check_and_get_full_package_spec(std::string&& full_package_spec_as_string, Triplet default_triplet, - CStringView example_text) + CStringView example_text, + const VcpkgPaths& paths) { const std::string as_lowercase = Strings::ascii_to_lowercase(std::move(full_package_spec_as_string)); - auto expected_spec = FullPackageSpec::from_string(as_lowercase, default_triplet); + auto expected_spec = parse_qualified_specifier(as_lowercase) + .then(&ParsedQualifiedSpecifier::to_full_spec, default_triplet, ImplicitDefault::YES); if (const auto spec = expected_spec.get()) { + Input::check_triplet(spec->package_spec.triplet(), paths); return *spec; } diff --git a/src/vcpkg/install.cpp b/src/vcpkg/install.cpp index d6a70ff5b9..5795e23db8 100644 --- a/src/vcpkg/install.cpp +++ b/src/vcpkg/install.cpp @@ -946,18 +946,19 @@ namespace vcpkg::Install { features.insert(features.end(), manifest_feature_it->second.begin(), manifest_feature_it->second.end()); } - auto core_it = Util::find(features, "core"); - if (core_it == features.end() && - !Util::Sets::contains(options.switches, OPTION_MANIFEST_NO_DEFAULT_FEATURES)) + if (Util::Sets::contains(options.switches, OPTION_MANIFEST_NO_DEFAULT_FEATURES)) + { + features.push_back("core"); + } + + auto core_it = std::remove(features.begin(), features.end(), "core"); + if (core_it == features.end()) { const auto& default_features = manifest_scf.core_paragraph->default_features; features.insert(features.end(), default_features.begin(), default_features.end()); } else { - // remove "core" because resolve_deps_as_top_level uses default-inversion - // support multiple core features - core_it = std::remove(core_it, features.end(), "core"); features.erase(core_it, features.end()); } Util::sort_unique_erase(features); @@ -1050,14 +1051,9 @@ namespace vcpkg::Install const std::vector specs = Util::fmap(args.command_arguments, [&](auto&& arg) { return Input::check_and_get_full_package_spec( - std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text); + std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text, paths); }); - for (auto&& spec : specs) - { - Input::check_triplet(spec.package_spec.triplet(), paths); - } - // create the plan print2("Computing installation plan...\n"); StatusParagraphs status_db = database_load_check(fs, paths.installed()); diff --git a/src/vcpkg/packagespec.cpp b/src/vcpkg/packagespec.cpp index 14692d8f2a..587ed72e74 100644 --- a/src/vcpkg/packagespec.cpp +++ b/src/vcpkg/packagespec.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -19,55 +20,12 @@ namespace vcpkg Strings::append(out, port(), '[', feature(), "]:", triplet()); } - std::vector FullPackageSpec::to_feature_specs(const std::vector& default_features, - const std::vector& all_features) const + void FullPackageSpec::expand_fspecs_to(std::vector& out) const { - std::vector feature_specs; - - if (Util::find(features, "*") != features.end()) + for (auto&& feature : features) { - feature_specs.emplace_back(package_spec, "core"); - for (const std::string& feature : all_features) - { - feature_specs.emplace_back(package_spec, feature); - } + out.emplace_back(package_spec, feature); } - else - { - bool core = false; - for (const std::string& feature : features) - { - feature_specs.emplace_back(package_spec, feature); - - if (!core) - { - core = feature == "core"; - } - } - - if (!core) - { - feature_specs.emplace_back(package_spec, "core"); - - for (const std::string& def : default_features) - { - feature_specs.emplace_back(package_spec, def); - } - } - } - - return feature_specs; - } - - ExpectedS FullPackageSpec::from_string(const std::string& spec_as_string, Triplet default_triplet) - { - return parse_qualified_specifier(spec_as_string) - .then([&](ParsedQualifiedSpecifier&& p) -> ExpectedS { - if (p.platform) - return "Error: platform specifier not allowed in this context: " + spec_as_string + "\n"; - auto triplet = p.triplet ? Triplet::from_canonical_name(std::move(*p.triplet.get())) : default_triplet; - return FullPackageSpec({p.name, triplet}, p.features.value_or({})); - }); } std::vector PackageSpec::to_package_specs(const std::vector& ports, Triplet triplet) @@ -91,13 +49,61 @@ namespace vcpkg return left.name() == right.name() && left.triplet() == right.triplet(); } - ExpectedS Features::from_string(const std::string& name) + DECLARE_AND_REGISTER_MESSAGE(IllegalPlatformSpec, + (), + "", + "Error: Platform qualifier is not allowed in this context"); + DECLARE_AND_REGISTER_MESSAGE(IllegalFeatures, (), "", "Error: List of features is not allowed in this contect"); + + static InternalFeatureSet normalize_feature_list(View fs, ImplicitDefault id) { - return parse_qualified_specifier(name).then([&](ParsedQualifiedSpecifier&& pqs) -> ExpectedS { - if (pqs.triplet) return "Error: triplet not allowed in this context: " + name + "\n"; - if (pqs.platform) return "Error: platform specifier not allowed in this context: " + name + "\n"; - return Features{pqs.name, pqs.features.value_or({})}; - }); + InternalFeatureSet ret; + bool core = false; + for (auto&& f : fs) + { + if (f == "core") + { + core = true; + } + ret.emplace_back(f); + } + + if (!core) + { + ret.emplace_back("core"); + if (id == ImplicitDefault::YES) + { + ret.emplace_back("default"); + } + } + return ret; + } + + ExpectedS ParsedQualifiedSpecifier::to_full_spec(Triplet default_triplet, ImplicitDefault id) const + { + if (platform) + { + return {msg::format(msgIllegalPlatformSpec).data(), expected_right_tag}; + } + + const Triplet t = triplet ? Triplet::from_canonical_name(*triplet.get()) : default_triplet; + const View fs = !features.get() ? View{} : *features.get(); + return FullPackageSpec{{name, t}, normalize_feature_list(fs, id)}; + } + + ExpectedS ParsedQualifiedSpecifier::to_package_spec(Triplet default_triplet) const + { + if (platform) + { + return {msg::format(msgIllegalPlatformSpec).data(), expected_right_tag}; + } + if (features) + { + return {msg::format(msgIllegalFeatures).data(), expected_right_tag}; + } + + const Triplet t = triplet ? Triplet::from_canonical_name(*triplet.get()) : default_triplet; + return PackageSpec{name, t}; } static bool is_package_name_char(char32_t ch) @@ -136,6 +142,12 @@ namespace vcpkg return nullopt; } + if (ret == "default") + { + parser.add_error("'default' is a reserved feature name"); + return nullopt; + } + if (ret.empty()) { parser.add_error("expected feature name (must be lowercase, digits, '-')"); @@ -267,6 +279,11 @@ namespace vcpkg } bool operator!=(const DependencyConstraint& lhs, const DependencyConstraint& rhs); + FullPackageSpec Dependency::to_full_spec(Triplet target, Triplet host_triplet, ImplicitDefault id) const + { + return FullPackageSpec{{name, host ? host_triplet : target}, normalize_feature_list(features, id)}; + } + bool operator==(const Dependency& lhs, const Dependency& rhs) { if (lhs.name != rhs.name) return false; @@ -274,6 +291,7 @@ namespace vcpkg if (!structurally_equal(lhs.platform, rhs.platform)) return false; if (lhs.extra_info != rhs.extra_info) return false; if (lhs.constraint != rhs.constraint) return false; + if (lhs.host != rhs.host) return false; return true; } diff --git a/src/vcpkg/remove.cpp b/src/vcpkg/remove.cpp index 224281c174..4267f34a20 100644 --- a/src/vcpkg/remove.cpp +++ b/src/vcpkg/remove.cpp @@ -240,11 +240,8 @@ namespace vcpkg::Remove } specs = Util::fmap(args.command_arguments, [&](auto&& arg) { return Input::check_and_get_package_spec( - std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text); + std::string(arg), default_triplet, COMMAND_STRUCTURE.example_text, paths); }); - - for (auto&& spec : specs) - Input::check_triplet(spec.triplet(), paths); } const bool no_purge = Util::Sets::contains(options.switches, OPTION_NO_PURGE); diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 2fe7a2ce27..66d4a4eb30 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -1309,15 +1309,15 @@ namespace vcpkg std::vector filter_dependencies(const std::vector& deps, Triplet target, Triplet host, - const std::unordered_map& cmake_vars) + const std::unordered_map& cmake_vars, + ImplicitDefault id) { std::vector ret; for (auto&& dep : deps) { if (dep.platform.evaluate(cmake_vars)) { - Triplet t = dep.host ? host : target; - ret.emplace_back(FullPackageSpec({dep.name, t}, dep.features)); + ret.emplace_back(dep.to_full_spec(target, host, id)); } } return ret; diff --git a/src/vcpkg/triplet.cpp b/src/vcpkg/triplet.cpp index 2751a88e3e..201aa1c5e5 100644 --- a/src/vcpkg/triplet.cpp +++ b/src/vcpkg/triplet.cpp @@ -28,11 +28,11 @@ namespace std namespace vcpkg { - Triplet Triplet::from_canonical_name(std::string&& triplet_as_string) + Triplet Triplet::from_canonical_name(std::string triplet_as_string) { static std::unordered_set g_triplet_instances; - std::string s(Strings::ascii_to_lowercase(std::move(triplet_as_string))); - const auto p = g_triplet_instances.emplace(std::move(s)); + Strings::ascii_to_lowercase(&triplet_as_string[0], &triplet_as_string[0] + triplet_as_string.size()); + const auto p = g_triplet_instances.emplace(std::move(triplet_as_string)); return &*p.first; }