diff options
| author | Daniel Shaw <t-dansha@microsoft.com> | 2017-07-25 21:29:31 -0700 |
|---|---|---|
| committer | Robert Schumacher <roschuma@microsoft.com> | 2017-08-16 15:10:50 -0700 |
| commit | 307b761df4197bf9cf1b69652808530e6219a868 (patch) | |
| tree | 40dc026ac1522df8268865703e1182b9036a029b /toolsrc/src | |
| parent | bd7cd7f56d5d9fdfeb1f57810a2ea77bf4d7e31a (diff) | |
| download | vcpkg-307b761df4197bf9cf1b69652808530e6219a868.tar.gz vcpkg-307b761df4197bf9cf1b69652808530e6219a868.zip | |
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
Diffstat (limited to 'toolsrc/src')
| -rw-r--r-- | toolsrc/src/BinaryParagraph.cpp | 12 | ||||
| -rw-r--r-- | toolsrc/src/Paragraphs.cpp | 16 | ||||
| -rw-r--r-- | toolsrc/src/SourceParagraph.cpp | 57 | ||||
| -rw-r--r-- | toolsrc/src/StatusParagraphs.cpp | 26 | ||||
| -rw-r--r-- | toolsrc/src/commands_depends.cpp | 2 | ||||
| -rw-r--r-- | toolsrc/src/commands_install.cpp | 200 | ||||
| -rw-r--r-- | toolsrc/src/commands_remove.cpp | 27 | ||||
| -rw-r--r-- | toolsrc/src/commands_search.cpp | 2 | ||||
| -rw-r--r-- | toolsrc/src/test_install_plan.cpp | 50 | ||||
| -rw-r--r-- | toolsrc/src/tests_dependencies.cpp | 2 | ||||
| -rw-r--r-- | toolsrc/src/tests_paragraph.cpp | 28 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg_Build.cpp | 46 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg_Dependencies.cpp | 52 | ||||
| -rw-r--r-- | toolsrc/src/vcpkglib.cpp | 2 |
14 files changed, 431 insertions, 91 deletions
diff --git a/toolsrc/src/BinaryParagraph.cpp b/toolsrc/src/BinaryParagraph.cpp index 49e9d58e5..9abd388b9 100644 --- a/toolsrc/src/BinaryParagraph.cpp +++ b/toolsrc/src/BinaryParagraph.cpp @@ -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(); } diff --git a/toolsrc/src/Paragraphs.cpp b/toolsrc/src/Paragraphs.cpp index 3749e919e..3a30f66a3 100644 --- a/toolsrc/src/Paragraphs.cpp +++ b/toolsrc/src/Paragraphs.cpp @@ -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(); diff --git a/toolsrc/src/SourceParagraph.cpp b/toolsrc/src/SourceParagraph.cpp index a37567f3a..2aab7c572 100644 --- a/toolsrc/src/SourceParagraph.cpp +++ b/toolsrc/src/SourceParagraph.cpp @@ -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) { diff --git a/toolsrc/src/StatusParagraphs.cpp b/toolsrc/src/StatusParagraphs.cpp index 27f3c30a2..02ee61f75 100644 --- a/toolsrc/src/StatusParagraphs.cpp +++ b/toolsrc/src/StatusParagraphs.cpp @@ -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)); diff --git a/toolsrc/src/commands_depends.cpp b/toolsrc/src/commands_depends.cpp index 2d1fb658b..b04af5282 100644 --- a/toolsrc/src/commands_depends.cpp +++ b/toolsrc/src/commands_depends.cpp @@ -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); } diff --git a/toolsrc/src/commands_install.cpp b/toolsrc/src/commands_install.cpp index 2ce5b6c62..2965d9025 100644 --- a/toolsrc/src/commands_install.cpp +++ b/toolsrc/src/commands_install.cpp @@ -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); diff --git a/toolsrc/src/commands_remove.cpp b/toolsrc/src/commands_remove.cpp index eabf2b9ae..e480f02dd 100644 --- a/toolsrc/src/commands_remove.cpp +++ b/toolsrc/src/commands_remove.cpp @@ -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) diff --git a/toolsrc/src/commands_search.cpp b/toolsrc/src/commands_search.cpp index fee99a5db..f12c25fb6 100644 --- a/toolsrc/src/commands_search.cpp +++ b/toolsrc/src/commands_search.cpp @@ -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)); } } diff --git a/toolsrc/src/test_install_plan.cpp b/toolsrc/src/test_install_plan.cpp index d02af5662..347998723 100644 --- a/toolsrc/src/test_install_plan.cpp +++ b/toolsrc/src/test_install_plan.cpp @@ -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"}); + } }; }
\ No newline at end of file diff --git a/toolsrc/src/tests_dependencies.cpp b/toolsrc/src/tests_dependencies.cpp index 7a49bdbd0..26cc1e22c 100644 --- a/toolsrc/src/tests_dependencies.cpp +++ b/toolsrc/src/tests_dependencies.cpp @@ -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()); } diff --git a/toolsrc/src/tests_paragraph.cpp b/toolsrc/src/tests_paragraph.cpp index af4b55498..3f2760c22 100644 --- a/toolsrc/src/tests_paragraph.cpp +++ b/toolsrc/src/tests_paragraph.cpp @@ -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"); diff --git a/toolsrc/src/vcpkg_Build.cpp b/toolsrc/src/vcpkg_Build.cpp index a0d690f37..124efb7f2 100644 --- a/toolsrc/src/vcpkg_Build.cpp +++ b/toolsrc/src/vcpkg_Build.cpp @@ -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, + static void create_binary_feature_control_file(const SourceParagraph& source_paragraph, + const FeatureParagraph& feature_paragraph, + const Triplet& triplet, + BinaryControlFile& bcf) + { + 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) + const BuildInfo& build_info, + BinaryControlFile& bcf) { - BinaryParagraph bpgh = BinaryParagraph(source_paragraph, triplet); + 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); diff --git a/toolsrc/src/vcpkg_Dependencies.cpp b/toolsrc/src/vcpkg_Dependencies.cpp index 820e51b33..c84ca73f3 100644 --- a/toolsrc/src/vcpkg_Dependencies.cpp +++ b/toolsrc/src/vcpkg_Dependencies.cpp @@ -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); diff --git a/toolsrc/src/vcpkglib.cpp b/toolsrc/src/vcpkglib.cpp index 6b180b532..428ae090d 100644 --- a/toolsrc/src/vcpkglib.cpp +++ b/toolsrc/src/vcpkglib.cpp @@ -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; } |
