partial end to end feature packages hdf5

added vcpkg feature package support to other commands

remove comments

change qualifier bracket to parens

added features to qualified dependencies
This commit is contained in:
Daniel Shaw 2017-07-25 21:29:31 -07:00 committed by Robert Schumacher
parent bd7cd7f56d
commit 307b761df4
20 changed files with 461 additions and 98 deletions

View File

@ -31,5 +31,11 @@ namespace vcpkg
std::vector<std::string> depends;
};
struct BinaryControlFile
{
BinaryParagraph core_paragraph;
std::vector<BinaryParagraph> features;
};
void serialize(const BinaryParagraph& pgh, std::string& out_str);
}

View File

@ -20,7 +20,7 @@ namespace vcpkg::Paragraphs
Parse::ParseExpected<SourceControlFile> try_load_port(const Files::Filesystem& fs, const fs::path& control_path);
Expected<BinaryParagraph> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec);
Expected<BinaryControlFile> try_load_cached_control_package(const VcpkgPaths& paths, const PackageSpec& spec);
struct LoadResults
{

View File

@ -15,13 +15,24 @@ namespace vcpkg
struct Triplet;
struct Dependency
struct Features
{
std::string name;
std::string qualifier;
std::vector<std::string> features;
};
const std::string& to_string(const Dependency& dep);
Features parse_feature_list(const std::string& name);
struct Dependency
{
Features depend;
std::string qualifier;
std::string name() const;
static Dependency parse_dependency(std::string name, std::string qualifier);
};
const std::string to_string(const Dependency& dep);
struct FeatureParagraph
{

View File

@ -17,6 +17,9 @@ namespace vcpkg
const_iterator find(const PackageSpec& spec) const { return find(spec.name(), spec.triplet()); }
const_iterator find(const std::string& name, const Triplet& triplet) const;
iterator find(const std::string& name, const Triplet& triplet);
std::vector<std::unique_ptr<StatusParagraph>*> StatusParagraphs::find_all(const std::string& name,
const Triplet& triplet);
iterator find(const std::string& name, const Triplet& triplet, const std::string& feature);
const_iterator find_installed(const PackageSpec& spec) const
{

View File

@ -59,7 +59,7 @@ namespace vcpkg::Commands
const fs::path& source_dir,
const InstallDir& dirs);
void install_package(const VcpkgPaths& paths,
const BinaryParagraph& binary_paragraph,
const BinaryControlFile& binary_paragraph,
StatusParagraphs* status_db);
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet);
}

View File

@ -90,6 +90,7 @@ namespace vcpkg::Dependencies
InstallPlanAction(InstallPlanAction&&) = default;
InstallPlanAction& operator=(const InstallPlanAction&) = delete;
InstallPlanAction& operator=(InstallPlanAction&&) = default;
std::string displayname() const;
PackageSpec spec;
AnyParagraph any_paragraph;
@ -205,7 +206,9 @@ namespace vcpkg::Dependencies
std::unordered_map<PackageSpec, Cluster>& pkg_to_cluster,
GraphPlan& graph_plan);
void mark_minus(Cluster& cluster, std::unordered_map<PackageSpec, Cluster>& pkg_to_cluster, GraphPlan& graph_plan);
void mark_plus_default(Cluster& cluster,
std::unordered_map<PackageSpec, Cluster>& pkg_to_cluster,
GraphPlan& graph_plan);
std::vector<AnyAction> create_feature_install_plan(const std::unordered_map<PackageSpec, SourceControlFile>& map,
const std::vector<FullPackageSpec>& specs,
const StatusParagraphs& status_db);

View File

@ -87,7 +87,17 @@ namespace vcpkg
this->depends = filter_dependencies(fpgh.depends, triplet);
}
std::string BinaryParagraph::displayname() const { return this->spec.to_string(); }
std::string BinaryParagraph::displayname() const
{
if (this->feature == "")
{
return this->spec.name() + "[core]:" + this->spec.triplet().to_string();
}
else
{
return this->spec.name() + "[" + this->feature + "]:" + this->spec.triplet().to_string();
}
}
std::string BinaryParagraph::dir() const { return this->spec.dir(); }

View File

@ -3,6 +3,7 @@
#include "ParagraphParseResult.h"
#include "Paragraphs.h"
#include "vcpkg_Files.h"
#include "vcpkg_Util.h"
using namespace vcpkg::Parse;
@ -226,14 +227,21 @@ namespace vcpkg::Paragraphs
return error_info;
}
Expected<BinaryParagraph> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec)
Expected<BinaryControlFile> try_load_cached_control_package(const VcpkgPaths& paths, const PackageSpec& spec)
{
Expected<std::unordered_map<std::string, std::string>> pghs =
get_single_paragraph(paths.get_filesystem(), paths.package_dir(spec) / "CONTROL");
Expected<std::vector<std::unordered_map<std::string, std::string>>> pghs =
get_paragraphs(paths.get_filesystem(), paths.package_dir(spec) / "CONTROL");
if (auto p = pghs.get())
{
return BinaryParagraph(*p);
BinaryControlFile bcf;
bcf.core_paragraph = BinaryParagraph(p->front());
p->erase(p->begin());
bcf.features =
Util::fmap(*p, [&](auto&& raw_feature) -> BinaryParagraph { return BinaryParagraph(raw_feature); });
return bcf;
}
return pghs.error();

View File

@ -152,18 +152,61 @@ namespace vcpkg
return std::move(control_file);
}
Features parse_feature_list(const std::string& name)
{
Features f;
int end = (int)name.find(']');
if (end != std::string::npos)
{
int start = (int)name.find('[');
auto feature_name_list = name.substr(start + 1, end - start - 1);
f.name = name.substr(0, start);
f.features = parse_comma_list(feature_name_list);
}
else
{
f.name = name;
}
return f;
}
Dependency Dependency::parse_dependency(std::string name, std::string qualifier)
{
Dependency dep;
dep.qualifier = qualifier;
dep.depend = parse_feature_list(name);
return dep;
}
std::string Dependency::name() const
{
std::string str = this->depend.name;
if (this->depend.features.empty()) return str;
str += "[";
for (auto&& s : this->depend.features)
{
str += s + ",";
}
str.pop_back();
str += "]";
return str;
}
std::vector<Dependency> vcpkg::expand_qualified_dependencies(const std::vector<std::string>& depends)
{
return Util::fmap(depends, [&](const std::string& depend_string) -> Dependency {
auto pos = depend_string.find(' ');
if (pos == std::string::npos) return {depend_string, ""};
if (pos == std::string::npos) return Dependency::parse_dependency(depend_string, "");
// expect of the form "\w+ \[\w+\]"
Dependency dep;
dep.name = depend_string.substr(0, pos);
dep.depend.name = depend_string.substr(0, pos);
if (depend_string.c_str()[pos + 1] != '(' || depend_string[depend_string.size() - 1] != ')')
{
// Error, but for now just slurp the entire string.
return {depend_string, ""};
return Dependency::parse_dependency(depend_string, "");
}
dep.qualifier = depend_string.substr(pos + 2, depend_string.size() - pos - 3);
return dep;
@ -210,13 +253,17 @@ namespace vcpkg
{
if (dep.qualifier.empty() || t.canonical_name().find(dep.qualifier) != std::string::npos)
{
ret.push_back(dep.name);
ret.emplace_back(dep.name());
}
}
return ret;
}
const std::string& to_string(const Dependency& dep) { return dep.name; }
const std::string to_string(const Dependency& dep)
{
std::string name = dep.name();
return name;
}
ExpectedT<Supports, std::vector<std::string>> Supports::parse(const std::vector<std::string>& strs)
{

View File

@ -27,6 +27,30 @@ namespace vcpkg
});
}
std::vector<std::unique_ptr<StatusParagraph>*> StatusParagraphs::find_all(const std::string& name,
const Triplet& triplet)
{
std::vector<std::unique_ptr<StatusParagraph>*> spghs;
for (auto&& p : *this)
{
if (p->package.spec.name() == name && p->package.spec.triplet() == triplet)
{
spghs.emplace_back(&p);
}
}
return spghs;
}
StatusParagraphs::iterator StatusParagraphs::find(const std::string& name,
const Triplet& triplet,
const std::string& feature)
{
return std::find_if(begin(), end(), [&](const std::unique_ptr<StatusParagraph>& pgh) {
const PackageSpec& spec = pgh->package.spec;
return spec.name() == name && spec.triplet() == triplet && pgh->package.feature == feature;
});
}
StatusParagraphs::const_iterator StatusParagraphs::find_installed(const std::string& name,
const Triplet& triplet) const
{
@ -43,7 +67,7 @@ namespace vcpkg
{
Checks::check_exit(VCPKG_LINE_INFO, pgh != nullptr, "Inserted null paragraph");
const PackageSpec& spec = pgh->package.spec;
auto ptr = find(spec.name(), spec.triplet());
auto ptr = find(spec.name(), spec.triplet(), pgh->package.feature);
if (ptr == end())
{
paragraphs.push_back(std::move(pgh));

View File

@ -46,7 +46,7 @@ namespace vcpkg::Commands::DependInfo
for (auto&& source_control_file : source_control_files)
{
const SourceParagraph& source_paragraph = *source_control_file->core_paragraph;
auto s = Strings::join(", ", source_paragraph.depends, [](const Dependency& d) { return d.name; });
auto s = Strings::join(", ", source_paragraph.depends, [](const Dependency& d) { return d.name(); });
System::println("%s: %s", source_paragraph.name, s);
}

View File

@ -211,10 +211,10 @@ namespace vcpkg::Commands::Install
}
}
void install_package(const VcpkgPaths& paths, const BinaryParagraph& binary_paragraph, StatusParagraphs* status_db)
void install_package(const VcpkgPaths& paths, const BinaryControlFile& bcf, StatusParagraphs* status_db)
{
const fs::path package_dir = paths.package_dir(binary_paragraph.spec);
const Triplet& triplet = binary_paragraph.spec.triplet();
const fs::path package_dir = paths.package_dir(bcf.core_paragraph.spec);
const Triplet& triplet = bcf.core_paragraph.spec.triplet();
const std::vector<StatusParagraphAndAssociatedFiles> pgh_and_files = get_installed_files(paths, *status_db);
const SortedVector<std::string> package_files =
@ -234,7 +234,7 @@ namespace vcpkg::Commands::Install
System::println(System::Color::error,
"The following files are already installed in %s and are in conflict with %s",
triplet_install_path.generic_string(),
binary_paragraph.spec);
bcf.core_paragraph.spec);
System::print("\n ");
System::println(Strings::join("\n ", intersection));
System::println("");
@ -242,27 +242,42 @@ namespace vcpkg::Commands::Install
}
StatusParagraph source_paragraph;
source_paragraph.package = binary_paragraph;
source_paragraph.package = bcf.core_paragraph;
source_paragraph.want = Want::INSTALL;
source_paragraph.state = InstallState::HALF_INSTALLED;
for (auto&& dep : source_paragraph.package.depends)
{
if (status_db->find_installed(dep, source_paragraph.package.spec.triplet()) == status_db->end())
{
Checks::unreachable(VCPKG_LINE_INFO);
}
}
write_update(paths, source_paragraph);
status_db->insert(std::make_unique<StatusParagraph>(source_paragraph));
std::vector<StatusParagraph> features_spghs;
for (auto&& feature : bcf.features)
{
features_spghs.emplace_back();
StatusParagraph& feature_paragraph = features_spghs.back();
feature_paragraph.package = feature;
feature_paragraph.want = Want::INSTALL;
feature_paragraph.state = InstallState::HALF_INSTALLED;
write_update(paths, feature_paragraph);
status_db->insert(std::make_unique<StatusParagraph>(feature_paragraph));
}
const InstallDir install_dir = InstallDir::from_destination_root(
paths.installed, triplet.to_string(), paths.listfile_path(binary_paragraph));
paths.installed, triplet.to_string(), paths.listfile_path(bcf.core_paragraph));
install_files_and_write_listfile(paths.get_filesystem(), package_dir, install_dir);
source_paragraph.state = InstallState::INSTALLED;
write_update(paths, source_paragraph);
status_db->insert(std::make_unique<StatusParagraph>(source_paragraph));
for (auto&& feature_paragraph : features_spghs)
{
feature_paragraph.state = InstallState::INSTALLED;
write_update(paths, feature_paragraph);
status_db->insert(std::make_unique<StatusParagraph>(feature_paragraph));
}
}
using Build::BuildResult;
@ -312,8 +327,8 @@ namespace vcpkg::Commands::Install
}
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);
const BinaryControlFile bpgh =
Paragraphs::try_load_cached_control_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);
@ -322,10 +337,11 @@ namespace vcpkg::Commands::Install
if (plan_type == InstallPlanType::BUILD_AND_INSTALL && g_feature_packages)
{
const std::string display_name_feature = action.displayname();
if (use_head_version)
System::println("Building package %s from HEAD... ", display_name);
System::println("Building package %s from HEAD... ", display_name_feature);
else
System::println("Building package %s... ", display_name);
System::println("Building package %s... ", display_name_feature);
const Build::BuildPackageConfig build_config{
*action.any_paragraph.source_control_file.value_or_exit(VCPKG_LINE_INFO),
@ -339,13 +355,13 @@ namespace vcpkg::Commands::Install
System::println(System::Color::error, Build::create_error_message(result.code, action.spec));
return result.code;
}
System::println("Building package %s... done", display_name);
System::println("Building package %s... done", display_name_feature);
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);
const BinaryControlFile bcf =
Paragraphs::try_load_cached_control_package(paths, action.spec).value_or_exit(VCPKG_LINE_INFO);
System::println("Installing package %s... ", display_name_feature);
install_package(paths, bcf, &status_db);
System::println(System::Color::success, "Installing package %s... done", display_name_feature);
return BuildResult::SUCCEEDED;
}
@ -357,7 +373,9 @@ namespace vcpkg::Commands::Install
System::Color::warning, "Package %s is already built -- not building from HEAD", display_name);
}
System::println("Installing package %s... ", display_name);
install_package(paths, action.any_paragraph.binary_paragraph.value_or_exit(VCPKG_LINE_INFO), &status_db);
install_package(paths,
BinaryControlFile{action.any_paragraph.binary_paragraph.value_or_exit(VCPKG_LINE_INFO)},
&status_db);
System::println(System::Color::success, "Installing package %s... done", display_name);
return BuildResult::SUCCEEDED;
}
@ -365,11 +383,27 @@ namespace vcpkg::Commands::Install
Checks::unreachable(VCPKG_LINE_INFO);
}
static void print_plan(const std::vector<const InstallPlanAction*> rebuilt_plans,
const std::vector<const InstallPlanAction*> new_plans)
{
const std::string rebuilt_string = Strings::join("\n", rebuilt_plans, [](const InstallPlanAction* p) {
return Dependencies::to_output_string(p->request_type, p->displayname());
});
const std::string new_string = Strings::join("\n", new_plans, [](const InstallPlanAction* p) {
return Dependencies::to_output_string(p->request_type, p->displayname());
});
if (rebuilt_plans.size() > 0) System::println("The following packages will be rebuilt:\n%s", rebuilt_string);
if (new_plans.size() > 0) System::println("The following packages will be installed:\n%s", new_string);
}
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths, const Triplet& default_triplet)
{
static const std::string OPTION_DRY_RUN = "--dry-run";
static const std::string OPTION_USE_HEAD_VERSION = "--head";
static const std::string OPTION_NO_DOWNLOADS = "--no-downloads";
static const std::string OPTION_RECURSE = "--recurse";
// input sanitization
static const std::string example =
@ -383,14 +417,130 @@ namespace vcpkg::Commands::Install
Input::check_triplet(spec.triplet(), paths);
const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments(
{OPTION_DRY_RUN, OPTION_USE_HEAD_VERSION, OPTION_NO_DOWNLOADS});
{OPTION_DRY_RUN, OPTION_USE_HEAD_VERSION, OPTION_NO_DOWNLOADS, OPTION_RECURSE});
const bool dryRun = options.find(OPTION_DRY_RUN) != options.cend();
const bool use_head_version = options.find(OPTION_USE_HEAD_VERSION) != options.cend();
const bool no_downloads = options.find(OPTION_NO_DOWNLOADS) != options.cend();
const bool isRecursive = options.find(OPTION_RECURSE) != options.cend();
// create the plan
StatusParagraphs status_db = database_load_check(paths);
if (g_feature_packages)
{
const std::vector<FullPackageSpec> full_specs = Util::fmap(args.command_arguments, [&](auto&& arg) {
return Input::check_and_get_full_package_spec(arg, default_triplet, example);
});
std::unordered_map<PackageSpec, SourceControlFile> scf_map;
auto all_ports = Paragraphs::try_load_all_ports(paths.get_filesystem(), paths.ports);
for (auto&& port : all_ports.paragraphs)
{
auto pkg_spec = PackageSpec::from_name_and_triplet(port->core_paragraph->name, default_triplet)
.value_or_exit(VCPKG_LINE_INFO);
scf_map[pkg_spec] = std::move(*port);
}
std::vector<Dependencies::AnyAction> action_plan =
Dependencies::create_feature_install_plan(scf_map, full_specs, status_db);
// install plan will be empty if it is already installed - need to change this at status paragraph part
Checks::check_exit(
VCPKG_LINE_INFO, !action_plan.empty(), "Install plan cannot be empty for feature packages");
const Build::BuildPackageOptions install_plan_options = {Build::to_use_head_version(use_head_version),
Build::to_allow_downloads(!no_downloads)};
std::vector<const RemovePlanAction*> remove_plans;
std::vector<const InstallPlanAction*> rebuilt_plans;
std::vector<const InstallPlanAction*> new_plans;
// removal will happen before install
for (auto&& action : action_plan)
{
if (auto install_action = action.install_plan.get())
{
auto it = Util::find_if(
remove_plans, [&](const RemovePlanAction* plan) { return plan->spec == install_action->spec; });
if (it != remove_plans.end())
{
rebuilt_plans.emplace_back(install_action);
}
else
{
new_plans.emplace_back(install_action);
}
}
else if (auto remove_action = action.remove_plan.get())
{
remove_plans.emplace_back(remove_action);
}
}
print_plan(rebuilt_plans, new_plans);
if (remove_plans.size() > 0 && !isRecursive)
{
System::println(System::Color::warning,
"If you are sure you want to rebuild the above packages, run the command with the "
"--recurse option");
Checks::exit_fail(VCPKG_LINE_INFO);
}
// execute the plan
for (const Dependencies::AnyAction& any_action : action_plan)
{
if (auto install_action = any_action.install_plan.get())
{
const BuildResult result =
perform_install_plan_action(paths, *install_action, install_plan_options, status_db);
if (result != BuildResult::SUCCEEDED)
{
System::println(Build::create_user_troubleshooting_message(install_action->spec));
Checks::exit_fail(VCPKG_LINE_INFO);
}
}
else if (auto remove_action = any_action.remove_plan.get())
{
static const std::string OPTION_PURGE = "--purge";
static const std::string OPTION_NO_PURGE = "--no-purge";
const bool alsoRemoveFolderFromPackages = options.find(OPTION_NO_PURGE) == options.end();
if (options.find(OPTION_PURGE) != options.end() && !alsoRemoveFolderFromPackages)
{
// User specified --purge and --no-purge
System::println(System::Color::error, "Error: cannot specify both --no-purge and --purge.");
System::print(example);
Checks::exit_fail(VCPKG_LINE_INFO);
}
const std::string display_name = remove_action->spec.to_string();
switch (remove_action->plan_type)
{
case RemovePlanType::NOT_INSTALLED:
System::println(System::Color::success, "Package %s is not installed", display_name);
break;
case RemovePlanType::REMOVE:
System::println("Removing package %s... ", display_name);
Commands::Remove::remove_package(paths, remove_action->spec, &status_db);
System::println(System::Color::success, "Removing package %s... done", display_name);
break;
case RemovePlanType::UNKNOWN:
default: Checks::unreachable(VCPKG_LINE_INFO);
}
if (alsoRemoveFolderFromPackages)
{
System::println("Purging package %s... ", display_name);
Files::Filesystem& fs = paths.get_filesystem();
std::error_code ec;
fs.remove_all(paths.packages / remove_action->spec.dir(), ec);
System::println(System::Color::success, "Purging package %s... done", display_name);
}
}
}
Checks::exit_success(VCPKG_LINE_INFO);
}
Dependencies::PathsPortFile paths_port_file(paths);
std::vector<InstallPlanAction> install_plan =
Dependencies::create_install_plan(paths_port_file, specs, status_db);

View File

@ -17,13 +17,19 @@ namespace vcpkg::Commands::Remove
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());
auto spghs = status_db->find_all(spec.name(), spec.triplet());
auto core_pkg = **status_db->find(spec.name(), spec.triplet(), "");
pkg.want = Want::PURGE;
pkg.state = InstallState::HALF_INSTALLED;
write_update(paths, pkg);
for (auto&& spgh : spghs)
{
StatusParagraph& pkg = **spgh;
if (pkg.state != InstallState::INSTALLED) continue;
pkg.want = Want::PURGE;
pkg.state = InstallState::HALF_INSTALLED;
write_update(paths, pkg);
}
auto maybe_lines = fs.read_lines(paths.listfile_path(pkg.package));
auto maybe_lines = fs.read_lines(paths.listfile_path(core_pkg.package));
if (auto lines = maybe_lines.get())
{
@ -80,11 +86,16 @@ namespace vcpkg::Commands::Remove
}
}
fs.remove(paths.listfile_path(pkg.package));
fs.remove(paths.listfile_path(core_pkg.package));
}
pkg.state = InstallState::NOT_INSTALLED;
write_update(paths, pkg);
for (auto&& spgh : spghs)
{
StatusParagraph& pkg = **spgh;
if (pkg.state != InstallState::HALF_INSTALLED) continue;
pkg.state = InstallState::NOT_INSTALLED;
write_update(paths, pkg);
}
}
static void print_plan(const std::map<RemovePlanType, std::vector<const RemovePlanAction*>>& group_by_plan_type)

View File

@ -39,7 +39,7 @@ namespace vcpkg::Commands::Search
s.append(Strings::format("%s;", name));
for (const Dependency& d : source_paragraph.depends)
{
const std::string dependency_name = replace_dashes_with_underscore(d.name);
const std::string dependency_name = replace_dashes_with_underscore(d.name());
s.append(Strings::format("%s -> %s;", name, dependency_name));
}
}

View File

@ -347,13 +347,13 @@ namespace UnitTest1
spec_map.get_package_spec(
{{{"Source", "a"}, {"Version", "1.3"}, {"Build-Depends", ""}},
{{"Feature", "1"}, {"Description", "the first feature for a"}, {"Build-Depends", "b[1]"}},
{{"Feature", "2"}, {"Description", "the first feature for a"}, {"Build-Depends", "b[2]"}},
{{"Feature", "3"}, {"Description", "the first feature for a"}, {"Build-Depends", "a[2]"}}}),
{{"Feature", "2"}, {"Description", "the second feature for a"}, {"Build-Depends", "b[2]"}},
{{"Feature", "3"}, {"Description", "the third feature for a"}, {"Build-Depends", "a[2]"}}}),
{"3"}};
auto spec_b = FullPackageSpec{spec_map.get_package_spec({
{{"Source", "b"}, {"Version", "1.3"}, {"Build-Depends", ""}},
{{"Feature", "1"}, {"Description", "the first feature for a"}, {"Build-Depends", ""}},
{{"Feature", "2"}, {"Description", "the first feature for a"}, {"Build-Depends", ""}},
{{"Feature", "1"}, {"Description", "the first feature for b"}, {"Build-Depends", ""}},
{{"Feature", "2"}, {"Description", "the second feature for b"}, {"Build-Depends", ""}},
})};
auto install_plan = Dependencies::create_feature_install_plan(
@ -434,7 +434,7 @@ namespace UnitTest1
{"1"}};
auto install_plan = Dependencies::create_feature_install_plan(
spec_map.map, {spec_b, spec_x}, StatusParagraphs(std::move(status_paragraphs)));
spec_map.map, {spec_b}, StatusParagraphs(std::move(status_paragraphs)));
Assert::AreEqual(size_t(5), install_plan.size());
remove_plan_check(&install_plan[0], "x");
@ -523,5 +523,45 @@ namespace UnitTest1
features_check(&install_plan[6], "a", {"one", "core"});
features_check(&install_plan[7], "c", {"core"});
}
TEST_METHOD(default_features_test)
{
using Pgh = std::unordered_map<std::string, std::string>;
std::vector<std::unique_ptr<StatusParagraph>> status_paragraphs;
PackageSpecMap spec_map(Triplet::X86_WINDOWS);
auto spec_a = FullPackageSpec{
spec_map.get_package_spec(
{{{"Source", "a"}, {"Version", "1.3"}, {"Default-Features", "1, 2"}, {"Build-Depends", ""}},
{{"Feature", "1"}, {"Description", "the first feature for a"}, {"Build-Depends", "b[2]"}},
{{"Feature", "2"}, {"Description", "the second feature for a"}, {"Build-Depends", ""}},
{{"Feature", "3"}, {"Description", "the third feature for a"}, {"Build-Depends", ""}}}),
{""}};
auto spec_b = FullPackageSpec{
spec_map.get_package_spec({
{{"Source", "b"}, {"Version", "1.3"}, {"Default-Features", "1, 2"}, {"Build-Depends", ""}},
{{"Feature", "1"}, {"Description", "the first feature for b"}, {"Build-Depends", "c[1]"}},
{{"Feature", "2"}, {"Description", "the second feature for b"}, {"Build-Depends", ""}},
}),
{""}};
auto spec_c = FullPackageSpec{
spec_map.get_package_spec({
{{"Source", "c"}, {"Version", "1.3"}, {"Default-Features", "2"}, {"Build-Depends", ""}},
{{"Feature", "1"}, {"Description", "the first feature for c"}, {"Build-Depends", ""}},
{{"Feature", "2"}, {"Description", "the second feature for c"}, {"Build-Depends", ""}},
}),
{""}};
auto install_plan = Dependencies::create_feature_install_plan(
spec_map.map, {spec_a}, StatusParagraphs(std::move(status_paragraphs)));
Assert::AreEqual(size_t(3), install_plan.size());
features_check(&install_plan[0], "c", {"core", "1", "2"});
features_check(&install_plan[1], "b", {"core", "1", "2"});
features_check(&install_plan[2], "a", {"core", "1", "2"});
}
};
}

View File

@ -17,7 +17,7 @@ namespace UnitTest1
{
auto v = expand_qualified_dependencies(parse_comma_list("libA (windows)"));
Assert::AreEqual(size_t(1), v.size());
Assert::AreEqual("libA", v[0].name.c_str());
Assert::AreEqual("libA", v[0].depend.name.c_str());
Assert::AreEqual("windows", v[0].qualifier.c_str());
}

View File

@ -60,7 +60,7 @@ namespace UnitTest1
Assert::AreEqual("m", pgh->core_paragraph->maintainer.c_str());
Assert::AreEqual("d", pgh->core_paragraph->description.c_str());
Assert::AreEqual(size_t(1), pgh->core_paragraph->depends.size());
Assert::AreEqual("bd", pgh->core_paragraph->depends[0].name.c_str());
Assert::AreEqual("bd", pgh->core_paragraph->depends[0].name().c_str());
Assert::AreEqual(size_t(1), pgh->core_paragraph->supports.size());
Assert::AreEqual("x64", pgh->core_paragraph->supports[0].c_str());
}
@ -77,8 +77,8 @@ namespace UnitTest1
auto& pgh = *m_pgh.get();
Assert::AreEqual(size_t(2), pgh->core_paragraph->depends.size());
Assert::AreEqual("z", pgh->core_paragraph->depends[0].name.c_str());
Assert::AreEqual("openssl", pgh->core_paragraph->depends[1].name.c_str());
Assert::AreEqual("z", pgh->core_paragraph->depends[0].name().c_str());
Assert::AreEqual("openssl", pgh->core_paragraph->depends[1].name().c_str());
}
TEST_METHOD(SourceParagraph_Three_Depends)
@ -93,9 +93,9 @@ namespace UnitTest1
auto& pgh = *m_pgh.get();
Assert::AreEqual(size_t(3), pgh->core_paragraph->depends.size());
Assert::AreEqual("z", pgh->core_paragraph->depends[0].name.c_str());
Assert::AreEqual("openssl", pgh->core_paragraph->depends[1].name.c_str());
Assert::AreEqual("xyz", pgh->core_paragraph->depends[2].name.c_str());
Assert::AreEqual("z", pgh->core_paragraph->depends[0].name().c_str());
Assert::AreEqual("openssl", pgh->core_paragraph->depends[1].name().c_str());
Assert::AreEqual("xyz", pgh->core_paragraph->depends[2].name().c_str());
}
TEST_METHOD(SourceParagraph_Three_Supports)
@ -131,9 +131,9 @@ namespace UnitTest1
Assert::AreEqual("", pgh->core_paragraph->maintainer.c_str());
Assert::AreEqual("", pgh->core_paragraph->description.c_str());
Assert::AreEqual(size_t(2), pgh->core_paragraph->depends.size());
Assert::AreEqual("libA", pgh->core_paragraph->depends[0].name.c_str());
Assert::AreEqual("libA", pgh->core_paragraph->depends[0].name().c_str());
Assert::AreEqual("windows", pgh->core_paragraph->depends[0].qualifier.c_str());
Assert::AreEqual("libB", pgh->core_paragraph->depends[1].name.c_str());
Assert::AreEqual("libB", pgh->core_paragraph->depends[1].name().c_str());
Assert::AreEqual("uwp", pgh->core_paragraph->depends[1].qualifier.c_str());
}
@ -411,6 +411,18 @@ namespace UnitTest1
Assert::AreEqual(vcpkg::PackageSpecParseResult::TOO_MANY_COLONS, ec);
}
TEST_METHOD(package_spec_feature_parse_with_arch)
{
vcpkg::ExpectedT<vcpkg::FullPackageSpec, vcpkg::PackageSpecParseResult> spec =
vcpkg::FullPackageSpec::from_string("zlib[feature]:x64-uwp", vcpkg::Triplet::X86_WINDOWS);
Assert::AreEqual(vcpkg::PackageSpecParseResult::SUCCESS, spec.error());
Assert::AreEqual("zlib", spec.get()->package_spec.name().c_str());
Assert::IsTrue(spec.get()->features.size() == 1);
Assert::AreEqual("feature", spec.get()->features.front().c_str());
Assert::AreEqual(vcpkg::Triplet::X64_UWP.canonical_name(),
spec.get()->package_spec.triplet().canonical_name());
}
TEST_METHOD(utf8_to_utf16)
{
auto str = vcpkg::Strings::to_utf16("abc");

View File

@ -88,29 +88,37 @@ namespace vcpkg::Build
return Strings::wformat(LR"("%s" %s %s %s 2>&1)", toolset.vcvarsall.native(), arch, target, tonull);
}
static void create_binary_control_file(const VcpkgPaths& paths,
const SourceParagraph& source_paragraph,
const Triplet& triplet,
const BuildInfo& build_info)
static void create_binary_feature_control_file(const SourceParagraph& source_paragraph,
const FeatureParagraph& feature_paragraph,
const Triplet& triplet,
BinaryControlFile& bcf)
{
BinaryParagraph bpgh = BinaryParagraph(source_paragraph, triplet);
BinaryParagraph bpgh(source_paragraph, feature_paragraph, triplet);
bcf.features.emplace_back(std::move(bpgh));
}
static void create_binary_control_file(const SourceParagraph& source_paragraph,
const Triplet& triplet,
const BuildInfo& build_info,
BinaryControlFile& bcf)
{
BinaryParagraph bpgh(source_paragraph, triplet);
if (auto p_ver = build_info.version.get())
{
bpgh.version = *p_ver;
}
const fs::path binary_control_file = paths.packages / bpgh.dir() / "CONTROL";
paths.get_filesystem().write_contents(binary_control_file, Strings::serialize(bpgh));
bcf.core_paragraph = std::move(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)
static void write_binary_control_file(const VcpkgPaths& paths, BinaryControlFile bcf)
{
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));
std::string start = Strings::serialize(bcf.core_paragraph);
for (auto&& feature : bcf.features)
{
start += "\n" + Strings::serialize(feature);
}
const fs::path binary_control_file = paths.packages / bcf.core_paragraph.dir() / "CONTROL";
paths.get_filesystem().write_contents(binary_control_file, start);
}
ExtendedBuildResult build_package(const VcpkgPaths& paths,
@ -196,6 +204,10 @@ namespace vcpkg::Build
auto build_info = read_build_info(paths.get_filesystem(), paths.build_info_file_path(spec));
const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info);
BinaryControlFile bcf;
create_binary_control_file(config.src, triplet, build_info, bcf);
if (error_count != 0)
{
return {BuildResult::POST_BUILD_CHECKS_FAILED, {}};
@ -209,13 +221,13 @@ namespace vcpkg::Build
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_feature_control_file(*config.scf->core_paragraph, *f_pgh, triplet, bcf);
}
}
}
}
create_binary_control_file(paths, config.src, triplet, build_info);
write_binary_control_file(paths, bcf);
// const fs::path port_buildtrees_dir = paths.buildtrees / spec.name;
// delete_directory(port_buildtrees_dir);

View File

@ -101,6 +101,25 @@ namespace vcpkg::Dependencies
this->plan_type = InstallPlanType::UNKNOWN;
}
std::string InstallPlanAction::displayname() const
{
if (this->feature_list.empty())
{
return this->spec.to_string();
}
else
{
std::string features;
for (auto&& feature : this->feature_list)
{
features += feature + ",";
}
features.pop_back();
return this->spec.name() + "[" + features + "]:" + this->spec.triplet().to_string();
}
}
bool InstallPlanAction::compare_by_name(const InstallPlanAction* left, const InstallPlanAction* right)
{
return left->spec.name() < right->spec.name();
@ -319,9 +338,9 @@ namespace vcpkg::Dependencies
? RequestType::USER_REQUESTED
: RequestType::AUTO_SELECTED;
Expected<BinaryParagraph> maybe_bpgh = Paragraphs::try_load_cached_package(paths, spec);
if (auto bpgh = maybe_bpgh.get())
return ExportPlanAction{spec, {nullopt, *bpgh, nullopt}, request_type};
Expected<BinaryControlFile> maybe_bpgh = Paragraphs::try_load_cached_control_package(paths, spec);
if (auto bcf = maybe_bpgh.get())
return ExportPlanAction{spec, {nullopt, bcf->core_paragraph, nullopt}, request_type};
auto maybe_scf = Paragraphs::try_load_port(paths.get_filesystem(), paths.port_dir(spec));
if (auto scf = maybe_scf.get())
@ -366,6 +385,20 @@ namespace vcpkg::Dependencies
return f_specs;
}
void mark_plus_default(Cluster& cluster,
std::unordered_map<PackageSpec, Cluster>& pkg_to_cluster,
GraphPlan& graph_plan)
{
mark_plus("core", cluster, pkg_to_cluster, graph_plan);
if (auto scf = cluster.source_control_file.get())
{
for (auto&& default_feature : (*scf)->core_paragraph->default_features)
{
mark_plus(default_feature, cluster, pkg_to_cluster, graph_plan);
}
}
}
bool mark_plus(const std::string& feature,
Cluster& cluster,
std::unordered_map<PackageSpec, Cluster>& pkg_to_cluster,
@ -404,21 +437,12 @@ namespace vcpkg::Dependencies
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())
{
cluster.to_install_features.insert("core");
for (auto&& depend : cluster.edges["core"].build_edges)
{
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});
}
}
for (auto&& depend : cluster.edges[updated_feature].build_edges)
{
auto& depend_cluster = pkg_to_cluster[depend.spec];
mark_plus(depend.feature_name, depend_cluster, pkg_to_cluster, graph_plan);
mark_plus_default(depend_cluster, pkg_to_cluster, graph_plan);
if (&depend_cluster == &cluster) continue;
graph_plan.install_graph.add_edge({&cluster}, {&depend_cluster});
}
@ -448,6 +472,7 @@ namespace vcpkg::Dependencies
mark_plus(original_feature, cluster, pkg_to_cluster, graph_plan);
}
}
std::vector<AnyAction> create_feature_install_plan(const std::unordered_map<PackageSpec, SourceControlFile>& map,
const std::vector<FullPackageSpec>& specs,
const StatusParagraphs& status_db)
@ -515,6 +540,7 @@ namespace vcpkg::Dependencies
for (auto&& spec : specs)
{
Cluster& spec_cluster = pkg_spec_to_package_node[spec.package_spec];
mark_plus_default(spec_cluster, pkg_spec_to_package_node, graph_plan);
for (auto&& feature : spec.features)
{
mark_plus(feature, spec_cluster, pkg_spec_to_package_node, graph_plan);

View File

@ -191,7 +191,7 @@ namespace vcpkg
for (const std::unique_ptr<StatusParagraph>& pgh : status_db)
{
if (pgh->state != InstallState::INSTALLED)
if (pgh->state != InstallState::INSTALLED || pgh->package.feature != "")
{
continue;
}