aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Shaw <t-dansha@microsoft.com>2017-07-19 14:29:28 -0700
committerDaniel Shaw <t-dansha@microsoft.com>2017-07-24 15:21:32 -0700
commit59389ca236b005922cf1101f66c957d2396f6371 (patch)
tree42bbcc25b501967203c63dd55b665ec9f49a41e4
parent1445115906139f5c6d14bcbbacdcc0cfb543fd80 (diff)
downloadvcpkg-59389ca236b005922cf1101f66c957d2396f6371.tar.gz
vcpkg-59389ca236b005922cf1101f66c957d2396f6371.zip
end to end feature pkg draft
-rw-r--r--toolsrc/include/BinaryParagraph.h3
-rw-r--r--toolsrc/include/PackageSpec.h6
-rw-r--r--toolsrc/include/SourceParagraph.h1
-rw-r--r--toolsrc/include/vcpkg_Build.h23
-rw-r--r--toolsrc/include/vcpkg_Commands.h1
-rw-r--r--toolsrc/include/vcpkg_Dependencies.h34
-rw-r--r--toolsrc/src/BinaryParagraph.cpp15
-rw-r--r--toolsrc/src/PackageSpec.cpp47
-rw-r--r--toolsrc/src/commands_install.cpp38
-rw-r--r--toolsrc/src/commands_remove.cpp2
-rw-r--r--toolsrc/src/test_install_plan.cpp118
-rw-r--r--toolsrc/src/tests_paragraph.cpp20
-rw-r--r--toolsrc/src/vcpkg_Build.cpp62
-rw-r--r--toolsrc/src/vcpkg_Dependencies.cpp88
-rw-r--r--toolsrc/src/vcpkg_Input.cpp27
-rw-r--r--toolsrc/src/vcpkg_Parse.cpp12
16 files changed, 359 insertions, 138 deletions
diff --git a/toolsrc/include/BinaryParagraph.h b/toolsrc/include/BinaryParagraph.h
index 4adde5e36..f411b3c39 100644
--- a/toolsrc/include/BinaryParagraph.h
+++ b/toolsrc/include/BinaryParagraph.h
@@ -14,6 +14,9 @@ namespace vcpkg
BinaryParagraph();
explicit BinaryParagraph(std::unordered_map<std::string, std::string> fields);
BinaryParagraph(const SourceParagraph& spgh, const Triplet& triplet);
+ BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh,
+ const FeatureParagraph& fpgh,
+ const Triplet& triplet);
std::string displayname() const;
diff --git a/toolsrc/include/PackageSpec.h b/toolsrc/include/PackageSpec.h
index 62b6fc9de..15b5e5b9b 100644
--- a/toolsrc/include/PackageSpec.h
+++ b/toolsrc/include/PackageSpec.h
@@ -1,5 +1,6 @@
#pragma once
#include "PackageSpecParseResult.h"
+#include "SourceParagraph.h"
#include "Triplet.h"
#include "vcpkg_expected.h"
@@ -7,8 +8,6 @@ namespace vcpkg
{
struct PackageSpec
{
- static ExpectedT<PackageSpec, PackageSpecParseResult> from_string(const std::string& spec_as_string,
- const Triplet& default_triplet);
static std::string to_string(const std::string& name, const Triplet& triplet);
static ExpectedT<PackageSpec, PackageSpecParseResult> from_name_and_triplet(const std::string& name,
const Triplet& triplet);
@@ -30,6 +29,9 @@ namespace vcpkg
{
PackageSpec package_spec;
std::vector<std::string> features;
+
+ static ExpectedT<FullPackageSpec, PackageSpecParseResult> from_string(const std::string& spec_as_string,
+ const Triplet& default_triplet);
};
bool operator==(const PackageSpec& left, const PackageSpec& right);
diff --git a/toolsrc/include/SourceParagraph.h b/toolsrc/include/SourceParagraph.h
index e85884b51..7ddf999cc 100644
--- a/toolsrc/include/SourceParagraph.h
+++ b/toolsrc/include/SourceParagraph.h
@@ -60,6 +60,7 @@ namespace vcpkg
std::vector<std::string> filter_dependencies(const std::vector<Dependency>& deps, const Triplet& t);
+ // zlib[uwp] becomes Dependency{"zlib", "uwp"}
std::vector<Dependency> expand_qualified_dependencies(const std::vector<std::string>& depends);
std::vector<std::string> parse_comma_list(const std::string& str);
diff --git a/toolsrc/include/vcpkg_Build.h b/toolsrc/include/vcpkg_Build.h
index 9a4e2baeb..c4f3e6746 100644
--- a/toolsrc/include/vcpkg_Build.h
+++ b/toolsrc/include/vcpkg_Build.h
@@ -95,14 +95,35 @@ namespace vcpkg::Build
const Triplet& triplet,
fs::path&& port_dir,
const BuildPackageOptions& build_package_options)
- : src(src), triplet(triplet), port_dir(std::move(port_dir)), build_package_options(build_package_options)
+ : src(src)
+ , scf(nullptr)
+ , triplet(triplet)
+ , port_dir(std::move(port_dir))
+ , build_package_options(build_package_options)
+ , feature_list(nullptr)
+ {
+ }
+
+ BuildPackageConfig(const SourceControlFile& src,
+ const Triplet& triplet,
+ fs::path&& port_dir,
+ const BuildPackageOptions& build_package_options,
+ const std::unordered_set<std::string>& feature_list)
+ : src(*src.core_paragraph)
+ , scf(&src)
+ , triplet(triplet)
+ , port_dir(std::move(port_dir))
+ , build_package_options(build_package_options)
+ , feature_list(&feature_list)
{
}
const SourceParagraph& src;
+ const SourceControlFile* scf;
const Triplet& triplet;
fs::path port_dir;
const BuildPackageOptions& build_package_options;
+ const std::unordered_set<std::string>* feature_list;
};
ExtendedBuildResult build_package(const VcpkgPaths& paths,
diff --git a/toolsrc/include/vcpkg_Commands.h b/toolsrc/include/vcpkg_Commands.h
index 67319f240..8348a64e4 100644
--- a/toolsrc/include/vcpkg_Commands.h
+++ b/toolsrc/include/vcpkg_Commands.h
@@ -77,6 +77,7 @@ namespace vcpkg::Commands
namespace Remove
{
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
+ void remove_package(const VcpkgPaths& paths, const PackageSpec& spec, StatusParagraphs* status_db);
}
namespace Update
diff --git a/toolsrc/include/vcpkg_Dependencies.h b/toolsrc/include/vcpkg_Dependencies.h
index ff559c0f1..e3af0fd28 100644
--- a/toolsrc/include/vcpkg_Dependencies.h
+++ b/toolsrc/include/vcpkg_Dependencies.h
@@ -26,12 +26,6 @@ namespace vcpkg::Dependencies
Optional<SourceParagraph> source_paragraph;
Optional<const SourceControlFile*> source_control_file;
};
-
- struct ClusterNode
- {
- std::vector<StatusParagraph> status_paragraphs;
- Optional<const SourceControlFile*> source_paragraph;
- };
}
namespace vcpkg::Dependencies
@@ -48,11 +42,13 @@ namespace vcpkg::Dependencies
std::vector<FeatureSpec> build_edges;
bool plus = false;
};
- std::vector<FeatureSpec> to_feature_specs(const std::vector<std::string> depends,
- const std::unordered_map<std::string, PackageSpec> str_to_spec);
+ std::vector<FeatureSpec> to_feature_specs(const std::vector<std::string>& depends, const Triplet& t);
+
struct Cluster
{
- ClusterNode cluster_data;
+ std::vector<StatusParagraph> status_paragraphs;
+ Optional<const SourceControlFile*> source_control_file;
+ PackageSpec spec;
std::unordered_map<std::string, FeatureNodeEdges> edges;
std::unordered_set<std::string> to_install_features;
std::unordered_set<std::string> original_features;
@@ -65,6 +61,13 @@ namespace vcpkg::Dependencies
Cluster& operator=(const Cluster&) = delete;
};
+ struct ClusterPtr
+ {
+ Cluster* ptr;
+ };
+
+ bool operator==(const ClusterPtr& l, const ClusterPtr& r);
+
enum class InstallPlanType
{
UNKNOWN,
@@ -181,12 +184,21 @@ namespace vcpkg::Dependencies
const StatusParagraphs& status_db);
}
+template<>
+struct std::hash<vcpkg::Dependencies::ClusterPtr>
+{
+ size_t operator()(const vcpkg::Dependencies::ClusterPtr& value) const
+ {
+ return std::hash<vcpkg::PackageSpec>()(value.ptr->spec);
+ }
+};
+
namespace vcpkg::Dependencies
{
struct GraphPlan
{
- Graphs::Graph<Cluster*> remove_graph;
- Graphs::Graph<Cluster*> install_graph;
+ Graphs::Graph<ClusterPtr> remove_graph;
+ Graphs::Graph<ClusterPtr> install_graph;
};
bool mark_plus(const std::string& feature,
Cluster& cluster,
diff --git a/toolsrc/src/BinaryParagraph.cpp b/toolsrc/src/BinaryParagraph.cpp
index e126054a8..b6f3e8a87 100644
--- a/toolsrc/src/BinaryParagraph.cpp
+++ b/toolsrc/src/BinaryParagraph.cpp
@@ -75,6 +75,16 @@ namespace vcpkg
this->depends = filter_dependencies(spgh.depends, triplet);
}
+ BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const FeatureParagraph& fpgh, const Triplet& triplet)
+ {
+ this->spec = PackageSpec::from_name_and_triplet(spgh.name, triplet).value_or_exit(VCPKG_LINE_INFO);
+ this->version = "";
+ this->feature = fpgh.name;
+ this->description = fpgh.description;
+ this->maintainer = "";
+ this->depends = filter_dependencies(fpgh.depends, triplet);
+ }
+
std::string BinaryParagraph::displayname() const { return this->spec.to_string(); }
std::string BinaryParagraph::dir() const { return this->spec.dir(); }
@@ -87,7 +97,10 @@ namespace vcpkg
void serialize(const BinaryParagraph& pgh, std::string& out_str)
{
out_str.append("Package: ").append(pgh.spec.name()).push_back('\n');
- out_str.append("Version: ").append(pgh.version).push_back('\n');
+ if (!pgh.version.empty())
+ out_str.append("Version: ").append(pgh.version).push_back('\n');
+ else if (!pgh.feature.empty())
+ out_str.append("Feature: ").append(pgh.feature).push_back('\n');
if (!pgh.depends.empty())
{
out_str.append("Depends: ");
diff --git a/toolsrc/src/PackageSpec.cpp b/toolsrc/src/PackageSpec.cpp
index 12217ac98..a7e5648cd 100644
--- a/toolsrc/src/PackageSpec.cpp
+++ b/toolsrc/src/PackageSpec.cpp
@@ -10,13 +10,47 @@ namespace vcpkg
return (c == '-') || isdigit(c) || (isalpha(c) && islower(c)) || (c == '[') || (c == ']');
}
- ExpectedT<PackageSpec, PackageSpecParseResult> PackageSpec::from_string(const std::string& spec_as_string,
- const Triplet& default_triplet)
+ ExpectedT<FullPackageSpec, PackageSpecParseResult> FullPackageSpec::from_string(const std::string& spec_as_string,
+ const Triplet& default_triplet)
{
auto pos = spec_as_string.find(':');
- if (pos == std::string::npos)
+ auto pos_l_bracket = spec_as_string.find('[');
+ auto pos_r_bracket = spec_as_string.find(']');
+
+ FullPackageSpec f;
+ if (pos == std::string::npos && pos_l_bracket == std::string::npos)
+ {
+ f.package_spec =
+ PackageSpec::from_name_and_triplet(spec_as_string, default_triplet).value_or_exit(VCPKG_LINE_INFO);
+ return f;
+ }
+ else if (pos == std::string::npos)
+ {
+ if (pos_r_bracket == std::string::npos || pos_l_bracket >= pos_r_bracket)
+ {
+ return PackageSpecParseResult::INVALID_CHARACTERS;
+ }
+ const std::string name = spec_as_string.substr(0, pos_l_bracket);
+ f.package_spec = PackageSpec::from_name_and_triplet(name, default_triplet).value_or_exit(VCPKG_LINE_INFO);
+ f.features = parse_comma_list(spec_as_string.substr(pos_l_bracket + 1, pos_r_bracket - pos_l_bracket - 1));
+ return f;
+ }
+ else if (pos_l_bracket == std::string::npos && pos_r_bracket == std::string::npos)
+ {
+ const std::string name = spec_as_string.substr(0, pos);
+ const Triplet triplet = Triplet::from_canonical_name(spec_as_string.substr(pos + 1));
+ f.package_spec = PackageSpec::from_name_and_triplet(name, triplet).value_or_exit(VCPKG_LINE_INFO);
+ }
+ else
{
- return from_name_and_triplet(spec_as_string, default_triplet);
+ if (pos_r_bracket == std::string::npos || pos_l_bracket >= pos_r_bracket)
+ {
+ return PackageSpecParseResult::INVALID_CHARACTERS;
+ }
+ const std::string name = spec_as_string.substr(0, pos_l_bracket);
+ f.features = parse_comma_list(spec_as_string.substr(pos_l_bracket + 1, pos_r_bracket - pos_l_bracket - 1));
+ const Triplet triplet = Triplet::from_canonical_name(spec_as_string.substr(pos + 1));
+ f.package_spec = PackageSpec::from_name_and_triplet(name, triplet).value_or_exit(VCPKG_LINE_INFO);
}
auto pos2 = spec_as_string.find(':', pos + 1);
@@ -24,10 +58,7 @@ namespace vcpkg
{
return PackageSpecParseResult::TOO_MANY_COLONS;
}
-
- const std::string name = spec_as_string.substr(0, pos);
- const Triplet triplet = Triplet::from_canonical_name(spec_as_string.substr(pos + 1));
- return from_name_and_triplet(name, triplet);
+ return f;
}
ExpectedT<PackageSpec, PackageSpecParseResult> PackageSpec::from_name_and_triplet(const std::string& name,
diff --git a/toolsrc/src/commands_install.cpp b/toolsrc/src/commands_install.cpp
index d340a9cf8..2ce5b6c62 100644
--- a/toolsrc/src/commands_install.cpp
+++ b/toolsrc/src/commands_install.cpp
@@ -16,6 +16,8 @@ namespace vcpkg::Commands::Install
using Dependencies::InstallPlanAction;
using Dependencies::RequestType;
using Dependencies::InstallPlanType;
+ using Dependencies::RemovePlanAction;
+ using Dependencies::RemovePlanType;
InstallDir InstallDir::from_destination_root(const fs::path& destination_root,
const std::string& destination_subdirectory,
@@ -290,7 +292,7 @@ namespace vcpkg::Commands::Install
return BuildResult::SUCCEEDED;
}
- if (plan_type == InstallPlanType::BUILD_AND_INSTALL)
+ if (plan_type == InstallPlanType::BUILD_AND_INSTALL && !g_feature_packages)
{
if (use_head_version)
System::println("Building package %s from HEAD... ", display_name);
@@ -318,7 +320,36 @@ namespace vcpkg::Commands::Install
return BuildResult::SUCCEEDED;
}
- if (plan_type == InstallPlanType::INSTALL)
+ if (plan_type == InstallPlanType::BUILD_AND_INSTALL && g_feature_packages)
+ {
+ if (use_head_version)
+ System::println("Building package %s from HEAD... ", display_name);
+ else
+ System::println("Building package %s... ", display_name);
+
+ const Build::BuildPackageConfig build_config{
+ *action.any_paragraph.source_control_file.value_or_exit(VCPKG_LINE_INFO),
+ action.spec.triplet(),
+ paths.port_dir(action.spec),
+ build_package_options,
+ action.feature_list};
+ const auto result = Build::build_package(paths, build_config, status_db);
+ if (result.code != Build::BuildResult::SUCCEEDED)
+ {
+ System::println(System::Color::error, Build::create_error_message(result.code, action.spec));
+ return result.code;
+ }
+ System::println("Building package %s... done", display_name);
+
+ const BinaryParagraph bpgh =
+ Paragraphs::try_load_cached_package(paths, action.spec).value_or_exit(VCPKG_LINE_INFO);
+ System::println("Installing package %s... ", display_name);
+ install_package(paths, bpgh, &status_db);
+ System::println(System::Color::success, "Installing package %s... done", display_name);
+ return BuildResult::SUCCEEDED;
+ }
+
+ if (plan_type == InstallPlanType::INSTALL && !g_feature_packages)
{
if (use_head_version && is_user_requested)
{
@@ -359,7 +390,8 @@ namespace vcpkg::Commands::Install
// create the plan
StatusParagraphs status_db = database_load_check(paths);
- auto paths_port_file = Dependencies::PathsPortFile(paths);
+
+ Dependencies::PathsPortFile paths_port_file(paths);
std::vector<InstallPlanAction> install_plan =
Dependencies::create_install_plan(paths_port_file, specs, status_db);
Checks::check_exit(VCPKG_LINE_INFO, !install_plan.empty(), "Install plan cannot be empty");
diff --git a/toolsrc/src/commands_remove.cpp b/toolsrc/src/commands_remove.cpp
index e2b5d12a1..eabf2b9ae 100644
--- a/toolsrc/src/commands_remove.cpp
+++ b/toolsrc/src/commands_remove.cpp
@@ -14,7 +14,7 @@ namespace vcpkg::Commands::Remove
using Dependencies::RequestType;
using Update::OutdatedPackage;
- static void remove_package(const VcpkgPaths& paths, const PackageSpec& spec, StatusParagraphs* status_db)
+ void remove_package(const VcpkgPaths& paths, const PackageSpec& spec, StatusParagraphs* status_db)
{
auto& fs = paths.get_filesystem();
StatusParagraph& pkg = **status_db->find(spec.name(), spec.triplet());
diff --git a/toolsrc/src/test_install_plan.cpp b/toolsrc/src/test_install_plan.cpp
index 671b6ed67..d02af5662 100644
--- a/toolsrc/src/test_install_plan.cpp
+++ b/toolsrc/src/test_install_plan.cpp
@@ -13,13 +13,16 @@ namespace UnitTest1
struct PackageSpecMap
{
std::unordered_map<PackageSpec, SourceControlFile> map;
+ Triplet triplet;
+ PackageSpecMap(const Triplet& t) { triplet = t; }
+
PackageSpec get_package_spec(std::vector<std::unordered_map<std::string, std::string>>&& fields)
{
auto m_pgh = vcpkg::SourceControlFile::parse_control_file(std::move(fields));
Assert::IsTrue(m_pgh.has_value());
auto& scf = *m_pgh.get();
- auto spec = PackageSpec::from_name_and_triplet(scf->core_paragraph->name, Triplet::X86_WINDOWS);
+ auto spec = PackageSpec::from_name_and_triplet(scf->core_paragraph->name, triplet);
Assert::IsTrue(spec.has_value());
map.emplace(*spec.get(), std::move(*scf.get()));
return PackageSpec{*spec.get()};
@@ -32,11 +35,14 @@ namespace UnitTest1
static void features_check(Dependencies::AnyAction* install_action,
std::string pkg_name,
- std::vector<std::string> vec)
+ std::vector<std::string> vec,
+ const Triplet& triplet = Triplet::X86_WINDOWS)
{
- const auto& plan = *install_action->install_plan.get();
+ const auto& plan = install_action->install_plan.value_or_exit(VCPKG_LINE_INFO);
const auto& feature_list = plan.feature_list;
+ Assert::AreEqual(plan.spec.triplet().to_string().c_str(), triplet.to_string().c_str());
+
Assert::AreEqual(pkg_name.c_str(),
(*plan.any_paragraph.source_control_file.get())->core_paragraph->name.c_str());
Assert::AreEqual(size_t(vec.size()), feature_list.size());
@@ -53,16 +59,20 @@ namespace UnitTest1
}
}
- static void remove_plan_check(Dependencies::AnyAction* install_action, std::string pkg_name)
+ static void remove_plan_check(Dependencies::AnyAction* remove_action,
+ std::string pkg_name,
+ const Triplet& triplet = Triplet::X86_WINDOWS)
{
- Assert::AreEqual(pkg_name.c_str(), install_action->remove_plan.get()->spec.name().c_str());
+ const auto& plan = remove_action->remove_plan.value_or_exit(VCPKG_LINE_INFO);
+ Assert::AreEqual(plan.spec.triplet().to_string().c_str(), triplet.to_string().c_str());
+ Assert::AreEqual(pkg_name.c_str(), plan.spec.name().c_str());
}
TEST_METHOD(basic_install_scheme)
{
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
- PackageSpecMap spec_map;
+ PackageSpecMap spec_map(Triplet::X86_WINDOWS);
auto spec_a = spec_map.set_package_map("a", "1.2.8", "b");
auto spec_b = spec_map.set_package_map("b", "1.3", "c");
auto spec_c = spec_map.set_package_map("c", "2.5.3", "");
@@ -81,7 +91,7 @@ namespace UnitTest1
{
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
- PackageSpecMap spec_map;
+ PackageSpecMap spec_map(Triplet::X86_WINDOWS);
auto spec_a = spec_map.set_package_map("a", "1.2.8", "d");
auto spec_b = spec_map.set_package_map("b", "1.3", "d, e");
auto spec_c = spec_map.set_package_map("c", "2.5.3", "e, h");
@@ -134,7 +144,7 @@ namespace UnitTest1
{"Depends", ""},
{"Status", "install ok installed"}}));
- PackageSpecMap spec_map;
+ PackageSpecMap spec_map(Triplet::X86_WINDOWS);
auto spec_a = spec_map.set_package_map("a", "1.2.8", "b, c, d, e, f, g, h, j, k");
auto spec_b = spec_map.set_package_map("b", "1.2.8", "c, d, e, f, g, h, j, k");
@@ -188,7 +198,7 @@ namespace UnitTest1
{"Depends", ""},
{"Status", "install ok installed"}}));
- PackageSpecMap spec_map;
+ PackageSpecMap spec_map(Triplet::X86_WINDOWS);
auto spec_a =
FullPackageSpec{spec_map.get_package_spec({
{{"Source", "a"}, {"Version", "1.3.8"}, {"Build-Depends", "b, b[beefeatureone]"}},
@@ -220,7 +230,7 @@ namespace UnitTest1
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
- PackageSpecMap spec_map;
+ PackageSpecMap spec_map(Triplet::X86_WINDOWS);
auto spec_a =
FullPackageSpec{spec_map.get_package_spec(
@@ -259,7 +269,7 @@ namespace UnitTest1
{"Depends", ""},
{"Status", "install ok installed"}}));
- PackageSpecMap spec_map;
+ PackageSpecMap spec_map(Triplet::X86_WINDOWS);
auto spec_a = FullPackageSpec{
spec_map.get_package_spec(
@@ -303,7 +313,7 @@ namespace UnitTest1
{"Depends", ""},
{"Status", "install ok installed"}}));
- PackageSpecMap spec_map;
+ PackageSpecMap spec_map(Triplet::X86_WINDOWS);
auto spec_a = FullPackageSpec{
spec_map.get_package_spec(
@@ -331,7 +341,7 @@ namespace UnitTest1
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
- PackageSpecMap spec_map;
+ PackageSpecMap spec_map(Triplet::X86_WINDOWS);
auto spec_a = FullPackageSpec{
spec_map.get_package_spec(
@@ -366,7 +376,7 @@ namespace UnitTest1
{"Multi-Arch", "same"},
{"Depends", ""},
{"Status", "install ok installed"}}));
- PackageSpecMap spec_map;
+ PackageSpecMap spec_map(Triplet::X86_WINDOWS);
auto spec_a = FullPackageSpec{spec_map.get_package_spec({
{{"Source", "a"}, {"Version", "1.3"}, {"Build-Depends", "b[core]"}},
@@ -407,7 +417,7 @@ namespace UnitTest1
{"Multi-Arch", "same"},
{"Depends", ""},
{"Status", "install ok installed"}}));
- PackageSpecMap spec_map;
+ PackageSpecMap spec_map(Triplet::X86_WINDOWS);
auto spec_a = FullPackageSpec{spec_map.get_package_spec({
{{"Source", "a"}, {"Version", "1.3"}, {"Build-Depends", ""}},
@@ -435,5 +445,83 @@ namespace UnitTest1
features_check(&install_plan[3], "x", {"core"});
features_check(&install_plan[4], "b", {"core", "1"});
}
+
+ TEST_METHOD(basic_feature_test_8)
+ {
+ using Pgh = std::unordered_map<std::string, std::string>;
+
+ std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
+ status_paragraphs.push_back(std::make_unique<StatusParagraph>(Pgh{{"Package", "a"},
+ {"Default-Features", ""},
+ {"Version", "1.3"},
+ {"Architecture", "x64-windows"},
+ {"Multi-Arch", "same"},
+ {"Depends", ""},
+ {"Status", "install ok installed"}}));
+ status_paragraphs.push_back(std::make_unique<StatusParagraph>(Pgh{{"Package", "a"},
+ {"Default-Features", ""},
+ {"Version", "1.3"},
+ {"Architecture", "x86-windows"},
+ {"Multi-Arch", "same"},
+ {"Depends", ""},
+ {"Status", "install ok installed"}}));
+
+ PackageSpecMap spec_map(Triplet::X64_WINDOWS);
+
+ auto spec_a_64 = FullPackageSpec{
+ spec_map.get_package_spec(
+ {{{"Source", "a"}, {"Version", "1.3"}, {"Build-Depends", "b"}},
+ {{"Feature", "one"}, {"Description", "the first feature for a"}, {"Build-Depends", ""}}}),
+ {"core"}};
+ auto spec_b_64 = FullPackageSpec{spec_map.get_package_spec({
+ {{"Source", "b"}, {"Version", "1.3"}, {"Build-Depends", ""}},
+ })};
+ auto spec_c_64 = FullPackageSpec{spec_map.get_package_spec({
+ {{"Source", "c"}, {"Version", "1.3"}, {"Build-Depends", "a[one]"}},
+ }),
+ {"core"}};
+
+ spec_map.triplet = Triplet::X86_WINDOWS;
+ auto spec_a_86 = FullPackageSpec{
+ spec_map.get_package_spec(
+ {{{"Source", "a"}, {"Version", "1.3"}, {"Build-Depends", "b"}},
+ {{"Feature", "one"}, {"Description", "the first feature for a"}, {"Build-Depends", ""}}}),
+ {"core"}};
+ auto spec_b_86 = FullPackageSpec{spec_map.get_package_spec({
+ {{"Source", "b"}, {"Version", "1.3"}, {"Build-Depends", ""}},
+ })};
+ auto spec_c_86 = FullPackageSpec{spec_map.get_package_spec({
+ {{"Source", "c"}, {"Version", "1.3"}, {"Build-Depends", "a[one]"}},
+ }),
+ {"core"}};
+
+ auto install_plan =
+ Dependencies::create_feature_install_plan(spec_map.map,
+ {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);
+ features_check(&install_plan[3], "a", {"one", "core"}, Triplet::X64_WINDOWS);
+ features_check(&install_plan[4], "c", {"core"}, Triplet::X64_WINDOWS);
+ features_check(&install_plan[5], "b", {"core"});
+ features_check(&install_plan[6], "a", {"one", "core"});
+ features_check(&install_plan[7], "c", {"core"});
+ }
};
} \ No newline at end of file
diff --git a/toolsrc/src/tests_paragraph.cpp b/toolsrc/src/tests_paragraph.cpp
index 2a53cc8b4..dd9a40160 100644
--- a/toolsrc/src/tests_paragraph.cpp
+++ b/toolsrc/src/tests_paragraph.cpp
@@ -372,25 +372,27 @@ namespace UnitTest1
TEST_METHOD(package_spec_parse)
{
- vcpkg::ExpectedT<vcpkg::PackageSpec, vcpkg::PackageSpecParseResult> spec =
- vcpkg::PackageSpec::from_string("zlib", vcpkg::Triplet::X86_WINDOWS);
+ vcpkg::ExpectedT<vcpkg::FullPackageSpec, vcpkg::PackageSpecParseResult> spec =
+ vcpkg::FullPackageSpec::from_string("zlib", vcpkg::Triplet::X86_WINDOWS);
Assert::AreEqual(vcpkg::PackageSpecParseResult::SUCCESS, spec.error());
- Assert::AreEqual("zlib", spec.get()->name().c_str());
- Assert::AreEqual(vcpkg::Triplet::X86_WINDOWS.canonical_name(), spec.get()->triplet().canonical_name());
+ Assert::AreEqual("zlib", spec.get()->package_spec.name().c_str());
+ Assert::AreEqual(vcpkg::Triplet::X86_WINDOWS.canonical_name(),
+ spec.get()->package_spec.triplet().canonical_name());
}
TEST_METHOD(package_spec_parse_with_arch)
{
- vcpkg::ExpectedT<vcpkg::PackageSpec, vcpkg::PackageSpecParseResult> spec =
- vcpkg::PackageSpec::from_string("zlib:x64-uwp", vcpkg::Triplet::X86_WINDOWS);
+ vcpkg::ExpectedT<vcpkg::FullPackageSpec, vcpkg::PackageSpecParseResult> spec =
+ vcpkg::FullPackageSpec::from_string("zlib:x64-uwp", vcpkg::Triplet::X86_WINDOWS);
Assert::AreEqual(vcpkg::PackageSpecParseResult::SUCCESS, spec.error());
- Assert::AreEqual("zlib", spec.get()->name().c_str());
- Assert::AreEqual(vcpkg::Triplet::X64_UWP.canonical_name(), spec.get()->triplet().canonical_name());
+ Assert::AreEqual("zlib", spec.get()->package_spec.name().c_str());
+ Assert::AreEqual(vcpkg::Triplet::X64_UWP.canonical_name(),
+ spec.get()->package_spec.triplet().canonical_name());
}
TEST_METHOD(package_spec_parse_with_multiple_colon)
{
- auto ec = vcpkg::PackageSpec::from_string("zlib:x86-uwp:", vcpkg::Triplet::X86_WINDOWS).error();
+ auto ec = vcpkg::FullPackageSpec::from_string("zlib:x86-uwp:", vcpkg::Triplet::X86_WINDOWS).error();
Assert::AreEqual(vcpkg::PackageSpecParseResult::TOO_MANY_COLONS, ec);
}
diff --git a/toolsrc/src/vcpkg_Build.cpp b/toolsrc/src/vcpkg_Build.cpp
index c794b5ede..a0d690f37 100644
--- a/toolsrc/src/vcpkg_Build.cpp
+++ b/toolsrc/src/vcpkg_Build.cpp
@@ -102,6 +102,17 @@ namespace vcpkg::Build
paths.get_filesystem().write_contents(binary_control_file, Strings::serialize(bpgh));
}
+ static void create_binary_feature_control_file(const VcpkgPaths& paths,
+ const SourceParagraph& source_paragraph,
+ const FeatureParagraph& feature_paragraph,
+ const Triplet& triplet,
+ const BuildInfo& build_info)
+ {
+ BinaryParagraph bpgh = BinaryParagraph(source_paragraph, feature_paragraph, triplet);
+ const fs::path binary_control_file = paths.packages / bpgh.dir() / "CONTROL";
+ paths.get_filesystem().write_contents(binary_control_file, Strings::serialize(bpgh));
+ }
+
ExtendedBuildResult build_package(const VcpkgPaths& paths,
const BuildPackageConfig& config,
const StatusParagraphs& status_db)
@@ -135,17 +146,36 @@ namespace vcpkg::Build
const Toolset& toolset = paths.get_toolset(pre_build_info.platform_toolset);
const auto cmd_set_environment = make_build_env_cmd(pre_build_info, toolset);
+ std::string features;
+ if (g_feature_packages)
+ {
+ if (config.feature_list)
+ {
+ for (auto&& feature : *config.feature_list)
+ {
+ features.append(feature + ";");
+ }
+ if (features.size() > 0)
+ {
+ features.pop_back();
+ }
+ }
+ }
+
const std::wstring cmd_launch_cmake = make_cmake_cmd(
cmake_exe_path,
ports_cmake_script_path,
- {{L"CMD", L"BUILD"},
- {L"PORT", config.src.name},
- {L"CURRENT_PORT_DIR", config.port_dir / "/."},
- {L"TARGET_TRIPLET", triplet.canonical_name()},
- {L"VCPKG_PLATFORM_TOOLSET", toolset.version},
- {L"VCPKG_USE_HEAD_VERSION", to_bool(config.build_package_options.use_head_version) ? L"1" : L"0"},
- {L"_VCPKG_NO_DOWNLOADS", !to_bool(config.build_package_options.allow_downloads) ? L"1" : L"0"},
- {L"GIT", git_exe_path}});
+ {
+ {L"CMD", L"BUILD"},
+ {L"PORT", config.src.name},
+ {L"CURRENT_PORT_DIR", config.port_dir / "/."},
+ {L"TARGET_TRIPLET", triplet.canonical_name()},
+ {L"VCPKG_PLATFORM_TOOLSET", toolset.version},
+ {L"VCPKG_USE_HEAD_VERSION", to_bool(config.build_package_options.use_head_version) ? L"1" : L"0"},
+ {L"_VCPKG_NO_DOWNLOADS", !to_bool(config.build_package_options.allow_downloads) ? L"1" : L"0"},
+ {L"GIT", git_exe_path},
+ {L"FEATURES", features},
+ });
const std::wstring command = Strings::wformat(LR"(%s && %s)", cmd_set_environment, cmd_launch_cmake);
@@ -170,7 +200,21 @@ namespace vcpkg::Build
{
return {BuildResult::POST_BUILD_CHECKS_FAILED, {}};
}
-
+ if (g_feature_packages)
+ {
+ if (config.feature_list)
+ {
+ for (auto&& feature : *config.feature_list)
+ {
+ for (auto&& f_pgh : config.scf->feature_paragraphs)
+ {
+ if (f_pgh->name == feature)
+ create_binary_feature_control_file(
+ paths, *config.scf->core_paragraph, *f_pgh, triplet, build_info);
+ }
+ }
+ }
+ }
create_binary_control_file(paths, config.src, triplet, build_info);
// const fs::path port_buildtrees_dir = paths.buildtrees / spec.name;
diff --git a/toolsrc/src/vcpkg_Dependencies.cpp b/toolsrc/src/vcpkg_Dependencies.cpp
index 90168813e..820e51b33 100644
--- a/toolsrc/src/vcpkg_Dependencies.cpp
+++ b/toolsrc/src/vcpkg_Dependencies.cpp
@@ -12,6 +12,8 @@
namespace vcpkg::Dependencies
{
+ bool operator==(const ClusterPtr& l, const ClusterPtr& r) { return l.ptr == r.ptr; }
+
std::vector<PackageSpec> AnyParagraph::dependencies(const Triplet& triplet) const
{
auto to_package_specs = [&](const std::vector<std::string>& dependencies_as_string) {
@@ -337,8 +339,7 @@ namespace vcpkg::Dependencies
return toposort;
}
- std::vector<FeatureSpec> to_feature_specs(const std::vector<std::string> depends,
- const std::unordered_map<std::string, PackageSpec> str_to_spec)
+ std::vector<FeatureSpec> to_feature_specs(const std::vector<std::string>& depends, const Triplet& triplet)
{
std::vector<FeatureSpec> f_specs;
for (auto&& depend : depends)
@@ -350,21 +351,16 @@ namespace vcpkg::Dependencies
auto feature_name = depend.substr(start + 1, end - start - 1);
auto package_name = depend.substr(0, start);
- auto p_spec = str_to_spec.find(package_name);
- if (p_spec != str_to_spec.end())
- {
- auto feature_spec = FeatureSpec{p_spec->second, feature_name};
- f_specs.emplace_back(std::move(feature_spec));
- }
+ auto p_spec = PackageSpec::from_name_and_triplet(package_name, triplet).value_or_exit(VCPKG_LINE_INFO);
+ auto feature_spec = FeatureSpec{p_spec, feature_name};
+ f_specs.emplace_back(std::move(feature_spec));
}
else
{
- auto p_spec = str_to_spec.find(depend);
- if (p_spec != str_to_spec.end())
- {
- auto feature_spec = FeatureSpec{p_spec->second, ""};
- f_specs.emplace_back(std::move(feature_spec));
- }
+ auto p_spec = PackageSpec::from_name_and_triplet(depend, triplet).value_or_exit(VCPKG_LINE_INFO);
+
+ auto feature_spec = FeatureSpec{p_spec, ""};
+ f_specs.emplace_back(std::move(feature_spec));
}
}
return f_specs;
@@ -405,7 +401,7 @@ namespace vcpkg::Dependencies
mark_minus(cluster, pkg_to_cluster, graph_plan);
}
- graph_plan.install_graph.add_vertex(&cluster);
+ graph_plan.install_graph.add_vertex({&cluster});
auto& tracked = cluster.to_install_features;
tracked.insert(updated_feature);
if (tracked.find("core") == tracked.end() && tracked.find("") == tracked.end())
@@ -415,7 +411,7 @@ namespace vcpkg::Dependencies
{
auto& depend_cluster = pkg_to_cluster[depend.spec];
mark_plus(depend.feature_name, depend_cluster, pkg_to_cluster, graph_plan);
- graph_plan.install_graph.add_edge(&cluster, &depend_cluster);
+ graph_plan.install_graph.add_edge({&cluster}, {&depend_cluster});
}
}
@@ -424,7 +420,7 @@ namespace vcpkg::Dependencies
auto& depend_cluster = pkg_to_cluster[depend.spec];
mark_plus(depend.feature_name, depend_cluster, pkg_to_cluster, graph_plan);
if (&depend_cluster == &cluster) continue;
- graph_plan.install_graph.add_edge(&cluster, &depend_cluster);
+ graph_plan.install_graph.add_edge({&cluster}, {&depend_cluster});
}
return true;
}
@@ -434,14 +430,14 @@ namespace vcpkg::Dependencies
if (cluster.will_remove) return;
cluster.will_remove = true;
- graph_plan.remove_graph.add_vertex(&cluster);
+ graph_plan.remove_graph.add_vertex({&cluster});
for (auto&& pair : cluster.edges)
{
auto& remove_edges_edges = pair.second.remove_edges;
for (auto&& depend : remove_edges_edges)
{
auto& depend_cluster = pkg_to_cluster[depend.spec];
- graph_plan.remove_graph.add_edge(&cluster, &depend_cluster);
+ graph_plan.remove_graph.add_edge({&cluster}, {&depend_cluster});
depend_cluster.transient_uninstalled = true;
mark_minus(depend_cluster, pkg_to_cluster, graph_plan);
}
@@ -456,40 +452,37 @@ namespace vcpkg::Dependencies
const std::vector<FullPackageSpec>& specs,
const StatusParagraphs& status_db)
{
- const auto triplet = Triplet::X86_WINDOWS;
std::unordered_map<PackageSpec, Cluster> pkg_spec_to_package_node;
- std::unordered_map<std::string, PackageSpec> str_to_spec;
-
- for (const auto& it : map)
- {
- str_to_spec.emplace(it.first.name(), it.first);
- }
for (const auto& it : map)
{
Cluster& node = pkg_spec_to_package_node[it.first];
+
+ node.spec = it.first;
FeatureNodeEdges core_dependencies;
- core_dependencies.build_edges =
- to_feature_specs(filter_dependencies(it.second.core_paragraph->depends, triplet), str_to_spec);
+ auto core_depends = filter_dependencies(it.second.core_paragraph->depends, node.spec.triplet());
+ core_dependencies.build_edges = to_feature_specs(core_depends, node.spec.triplet());
node.edges["core"] = std::move(core_dependencies);
for (const auto& feature : it.second.feature_paragraphs)
{
FeatureNodeEdges added_edges;
- added_edges.build_edges = to_feature_specs(filter_dependencies(feature->depends, triplet), str_to_spec);
+ auto depends = filter_dependencies(feature->depends, node.spec.triplet());
+ added_edges.build_edges = to_feature_specs(depends, node.spec.triplet());
node.edges.emplace(feature->name, std::move(added_edges));
}
- node.cluster_data.source_paragraph = &it.second;
+ node.source_control_file = &it.second;
}
- for (auto&& status_paragraph : status_db)
+ for (auto&& status_paragraph : get_installed_ports(status_db))
{
auto& spec = status_paragraph->package.spec;
auto& status_paragraph_feature = status_paragraph->package.feature;
Cluster& cluster = pkg_spec_to_package_node[spec];
cluster.transient_uninstalled = false;
- auto reverse_edges = to_feature_specs(status_paragraph->package.depends, str_to_spec);
+ auto reverse_edges =
+ to_feature_specs(status_paragraph->package.depends, status_paragraph->package.spec.triplet());
for (auto&& dependency : reverse_edges)
{
@@ -507,7 +500,7 @@ namespace vcpkg::Dependencies
auto& target_node = pkg_node->second.edges[depends_name];
target_node.remove_edges.emplace_back(FeatureSpec{spec, status_paragraph_feature});
}
- cluster.cluster_data.status_paragraphs.emplace_back(*status_paragraph);
+ cluster.status_paragraphs.emplace_back(*status_paragraph);
if (status_paragraph_feature == "")
{
cluster.original_features.insert("core");
@@ -528,35 +521,40 @@ namespace vcpkg::Dependencies
}
}
- Graphs::GraphAdjacencyProvider<Cluster*> adjacency_remove_graph(graph_plan.remove_graph.adjacency_list());
+ Graphs::GraphAdjacencyProvider<ClusterPtr> adjacency_remove_graph(graph_plan.remove_graph.adjacency_list());
auto remove_vertex_list = graph_plan.remove_graph.vertex_list();
auto remove_toposort = Graphs::topological_sort(remove_vertex_list, adjacency_remove_graph);
- Graphs::GraphAdjacencyProvider<Cluster*> adjacency_install_graph(graph_plan.install_graph.adjacency_list());
+ Graphs::GraphAdjacencyProvider<ClusterPtr> adjacency_install_graph(graph_plan.install_graph.adjacency_list());
auto insert_vertex_list = graph_plan.install_graph.vertex_list();
auto insert_toposort = Graphs::topological_sort(insert_vertex_list, adjacency_install_graph);
std::vector<AnyAction> install_plan;
- for (auto&& cluster : remove_toposort)
+ for (auto&& like_cluster : remove_toposort)
{
- auto scf = *cluster->cluster_data.source_paragraph.get();
+ auto scf = *like_cluster.ptr->source_control_file.get();
AnyAction any_plan;
any_plan.remove_plan = RemovePlanAction{
- str_to_spec[scf->core_paragraph->name], RemovePlanType::REMOVE, RequestType::AUTO_SELECTED};
+ PackageSpec::from_name_and_triplet(scf->core_paragraph->name, like_cluster.ptr->spec.triplet())
+ .value_or_exit(VCPKG_LINE_INFO),
+ RemovePlanType::REMOVE,
+ RequestType::AUTO_SELECTED};
install_plan.emplace_back(std::move(any_plan));
}
- for (auto&& cluster : insert_toposort)
+ for (auto&& like_cluster : insert_toposort)
{
- if (!cluster->transient_uninstalled) continue;
-
- auto scf = *cluster->cluster_data.source_paragraph.get();
- auto& pkg_spec = str_to_spec[scf->core_paragraph->name];
- auto action = InstallPlanAction{
- pkg_spec, map.find(pkg_spec)->second, cluster->to_install_features, RequestType::AUTO_SELECTED};
+ if (!like_cluster.ptr->transient_uninstalled) continue;
+
+ auto scf = *like_cluster.ptr->source_control_file.get();
+ auto pkg_spec =
+ PackageSpec::from_name_and_triplet(scf->core_paragraph->name, like_cluster.ptr->spec.triplet())
+ .value_or_exit(VCPKG_LINE_INFO);
+ auto action =
+ InstallPlanAction{pkg_spec, *scf, like_cluster.ptr->to_install_features, RequestType::AUTO_SELECTED};
AnyAction any_plan;
any_plan.install_plan = std::move(action);
diff --git a/toolsrc/src/vcpkg_Input.cpp b/toolsrc/src/vcpkg_Input.cpp
index fdedd5507..f4e9a07c2 100644
--- a/toolsrc/src/vcpkg_Input.cpp
+++ b/toolsrc/src/vcpkg_Input.cpp
@@ -12,10 +12,10 @@ namespace vcpkg::Input
CStringView example_text)
{
const std::string as_lowercase = Strings::ascii_to_lowercase(package_spec_as_string);
- auto expected_spec = PackageSpec::from_string(as_lowercase, default_triplet);
+ auto expected_spec = FullPackageSpec::from_string(as_lowercase, default_triplet);
if (auto spec = expected_spec.get())
{
- return PackageSpec{*spec};
+ return PackageSpec{spec->package_spec};
}
// Intentionally show the lowercased string
@@ -39,26 +39,11 @@ namespace vcpkg::Input
const Triplet& default_triplet,
CStringView example_text)
{
- int left_pos = (int)full_package_spec_as_string.find('[');
- if (left_pos == std::string::npos)
- {
- return FullPackageSpec{
- check_and_get_package_spec(full_package_spec_as_string, default_triplet, example_text)};
- }
- int right_pos = (int)full_package_spec_as_string.find(']');
- if (left_pos >= right_pos)
- {
- System::println(System::Color::error, "Error: Argument is not formatted correctly \"%s\"");
- Checks::exit_fail(VCPKG_LINE_INFO);
- }
-
- std::string package_spec_as_string = full_package_spec_as_string.substr(0, left_pos);
- const std::string as_lowercase = Strings::ascii_to_lowercase(package_spec_as_string);
- auto expected_spec = PackageSpec::from_string(as_lowercase, default_triplet);
- if (auto&& spec = expected_spec.get())
+ const std::string as_lowercase = Strings::ascii_to_lowercase(full_package_spec_as_string);
+ auto expected_spec = FullPackageSpec::from_string(as_lowercase, default_triplet);
+ if (auto spec = expected_spec.get())
{
- return {*spec,
- parse_comma_list(full_package_spec_as_string.substr(left_pos + 1, right_pos - left_pos - 1))};
+ return *spec;
}
// Intentionally show the lowercased string
diff --git a/toolsrc/src/vcpkg_Parse.cpp b/toolsrc/src/vcpkg_Parse.cpp
index b63ce41a9..659af2939 100644
--- a/toolsrc/src/vcpkg_Parse.cpp
+++ b/toolsrc/src/vcpkg_Parse.cpp
@@ -6,18 +6,6 @@
namespace vcpkg::Parse
{
- static Optional<std::string> get_field(const std::unordered_map<std::string, std::string>& fields,
- const std::string& fieldname)
- {
- auto it = fields.find(fieldname);
- if (it == fields.end())
- {
- return nullopt;
- }
-
- return it->second;
- }
-
static Optional<std::string> remove_field(std::unordered_map<std::string, std::string>* fields,
const std::string& fieldname)
{