[vcpkg] Enable pkg[*] as alias for all features.
MODIFY
include/vcpkg/base/util.h
include/vcpkg/base/util.h
@@ -117,6 +117,22 @@ namespace vcpkg::Util
}
}
+ template<class Range>
+ void sort(Range& cont)
+ {
+ using std::begin;
+ using std::end;
+ std::sort(begin(cont), end(cont));
+ }
+
+ template<class Range1, class Range2>
+ bool all_equal(const Range1& r1, const Range2& r2)
+ {
+ using std::begin;
+ using std::end;
+ return std::equal(begin(r1), end(r1), begin(r2), end(r2));
+ }
+
template<class AssocContainer, class K = std::decay_t<decltype(begin(std::declval<AssocContainer>())->first)>>
std::vector<K> extract_keys(AssocContainer&& input_map)
{

MODIFY
include/vcpkg/packagespec.h
include/vcpkg/packagespec.h
@@ -50,6 +50,22 @@ namespace vcpkg
static std::vector<FeatureSpec> from_strings_and_triplet(const std::vector<std::string>& depends,
const Triplet& t);
+ bool operator<(const FeatureSpec& other) const
+ {
+ if (name() < other.name()) return true;
+ if (name() > other.name()) return false;
+ if (feature() < other.feature()) return true;
+ if (feature() > other.feature()) return false;
+ return triplet() < other.triplet();
+ }
+
+ bool operator==(const FeatureSpec& other) const
+ {
+ return triplet() == other.triplet() && name() == other.name() && feature() == other.feature();
+ }
+
+ bool operator!=(const FeatureSpec& other) const { return !(*this == other); }
+
private:
PackageSpec m_spec;
std::string m_feature;

MODIFY
include/vcpkg/triplet.h
include/vcpkg/triplet.h
@@ -24,6 +24,7 @@ namespace vcpkg
size_t hash_code() const;
bool operator==(const Triplet& other) const;
+ bool operator<(const Triplet& other) const { return canonical_name() < other.canonical_name(); }
private:
static const TripletInstance DEFAULT_INSTANCE;

MODIFY
src/tests.installplan.cpp
src/tests.installplan.cpp
@@ -461,20 +461,6 @@ namespace UnitTest1
FullPackageSpec::to_feature_specs({spec_c_64, spec_a_86, spec_a_64, spec_c_86}),
StatusParagraphs(std::move(status_paragraphs)));
- /*Assert::AreEqual(size_t(8), install_plan.size());
- auto iterator_pos = [&](const PackageSpec& spec, size_t start) -> int {
- auto it = std::find_if(install_plan.begin() + start, install_plan.end(), [&](auto& action) {
- return action.spec == spec;
- });
- Assert::IsTrue(it != install_plan.end());
- return (int)(it - install_plan.begin());
- };
- int a_64_1 = iterator_pos(spec_a_64.package_spec, 0), a_86_1 = iterator_pos(spec_a_86.package_spec, 0),
- b_64 = iterator_pos(spec_b_64.package_spec, 0), b_86 = iterator_pos(spec_b_86.package_spec, 0),
- c_64 = iterator_pos(spec_c_64.package_spec, 0), c_86 = iterator_pos(spec_c_86.package_spec, 0),
- a_64_2 = iterator_pos(spec_a_64.package_spec, a_64_1 + 1),
- a_86_2 = iterator_pos(spec_a_86.package_spec, a_86_1 + 1);*/
-
remove_plan_check(&install_plan[0], "a", Triplet::X64_WINDOWS);
remove_plan_check(&install_plan[1], "a");
features_check(&install_plan[2], "b", {"core"}, Triplet::X64_WINDOWS);
@@ -484,5 +470,24 @@ namespace UnitTest1
features_check(&install_plan[6], "a", {"a1", "core"});
features_check(&install_plan[7], "c", {"core"});
}
+
+ TEST_METHOD(install_all_features_test)
+ {
+ std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
+
+ PackageSpecMap spec_map(Triplet::X64_WINDOWS);
+ auto spec_a_64 = FullPackageSpec{spec_map.emplace("a", "", {{"0", ""}, {"1", ""}}), {"core"}};
+
+ auto install_specs = FullPackageSpec::from_string("a[*]", Triplet::X64_WINDOWS);
+ Assert::IsTrue(install_specs.has_value());
+ if (!install_specs.has_value()) return;
+ auto install_plan = Dependencies::create_feature_install_plan(
+ spec_map.map,
+ FullPackageSpec::to_feature_specs({install_specs.value_or_exit(VCPKG_LINE_INFO)}),
+ StatusParagraphs(std::move(status_paragraphs)));
+
+ Assert::IsTrue(install_plan.size() == 1);
+ features_check(&install_plan[0], "a", {"0", "1", "core"}, Triplet::X64_WINDOWS);
+ }
};
}

MODIFY
src/tests.packagespec.cpp
src/tests.packagespec.cpp
#include <vcpkg/paragraphs.h>
#include <vcpkg/base/strings.h>
+#include <vcpkg/base/util.h>
#pragma comment(lib, "version")
#pragma comment(lib, "winhttp")
@@ -103,6 +104,39 @@ namespace UnitTest1
Assert::AreEqual("", spec->triplet.c_str());
}
+ TEST_METHOD(parsed_specifier_wildcard_feature)
+ {
+ auto maybe_spec = vcpkg::ParsedSpecifier::from_string("zlib[*]");
+ Assert::AreEqual(vcpkg::PackageSpecParseResult::SUCCESS, maybe_spec.error());
+ auto spec = maybe_spec.get();
+ Assert::AreEqual("zlib", spec->name.c_str());
+ Assert::IsTrue(spec->features.size() == 1);
+ Assert::AreEqual("*", spec->features[0].c_str());
+ Assert::AreEqual("", spec->triplet.c_str());
+ }
+
+ TEST_METHOD(expand_wildcards)
+ {
+ auto zlib =
+ vcpkg::FullPackageSpec::from_string("zlib[0,1]", Triplet::X86_UWP).value_or_exit(VCPKG_LINE_INFO);
+ auto openssl =
+ vcpkg::FullPackageSpec::from_string("openssl[*]", Triplet::X86_UWP).value_or_exit(VCPKG_LINE_INFO);
+ auto specs = FullPackageSpec::to_feature_specs({zlib, openssl});
+ Util::sort(specs);
+ auto spectargets = FeatureSpec::from_strings_and_triplet(
+ {
+ "openssl",
+ "zlib",
+ "openssl[*]",
+ "zlib[0]",
+ "zlib[1]",
+ },
+ Triplet::X86_UWP);
+ Util::sort(spectargets);
+ Assert::IsTrue(specs.size() == spectargets.size());
+ Assert::IsTrue(Util::all_equal(specs, spectargets));
+ }
+
TEST_METHOD(utf8_to_utf16)
{
auto str = vcpkg::Strings::to_utf16("abc");

MODIFY
src/vcpkg/dependencies.cpp
src/vcpkg/dependencies.cpp
@@ -157,7 +157,7 @@ namespace vcpkg::Dependencies
InstallPlanAction::InstallPlanAction(const PackageSpec& spec,
const std::unordered_set<std::string>& features,
const RequestType& request_type)
- : spec(spec), plan_type(InstallPlanType::UNKNOWN), request_type(request_type), feature_list(features)
+ : spec(spec), plan_type(InstallPlanType::ALREADY_INSTALLED), request_type(request_type), feature_list(features)
{
}
@@ -605,10 +605,38 @@ namespace vcpkg::Dependencies
{
Cluster& spec_cluster = graph.get(spec.spec());
spec_cluster.request_type = RequestType::USER_REQUESTED;
+ if (spec.feature() == "*")
+ {
+ if (auto p_scf = spec_cluster.source_control_file.value_or(nullptr))
+ {
+ for (auto&& feature : p_scf->feature_paragraphs)
+ {
+ auto res = mark_plus(feature->name, spec_cluster, graph, graph_plan);
+
+ Checks::check_exit(VCPKG_LINE_INFO,
+ res == MarkPlusResult::SUCCESS,
+ "Error: Unable to locate feature %s",
+ spec);
+ }
+
+ auto res = mark_plus("core", spec_cluster, graph, graph_plan);
+
+ Checks::check_exit(
+ VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS, "Error: Unable to locate feature %s", spec);
+ }
+ else
+ {
+ Checks::exit_with_message(
+ VCPKG_LINE_INFO, "Error: Unable to handle '*' because can't find CONTROL for %s", spec.spec());
+ }
+ }
+ else
+ {
auto res = mark_plus(spec.feature(), spec_cluster, graph, graph_plan);
Checks::check_exit(
VCPKG_LINE_INFO, res == MarkPlusResult::SUCCESS, "Error: Unable to locate feature %s", spec);
+ }
graph_plan.install_graph.add_vertex(ClusterPtr{&spec_cluster});
}

[vcpkg] Enable pkg[*] as alias for all features.