diff options
| author | Robert Schumacher <roschuma@microsoft.com> | 2017-06-19 15:09:54 -0700 |
|---|---|---|
| committer | Robert Schumacher <roschuma@microsoft.com> | 2017-06-19 15:09:54 -0700 |
| commit | 34c08e2b15777c86c5aaacfee5f04eed986c62da (patch) | |
| tree | 5a65eed065343bcb2f999da6937d423fff00c93e | |
| parent | 8d955c83b53d42983ebd9a046a0a0a5ade08537f (diff) | |
| parent | bca0988023a8c7bfc896d0f5787eb02e74c6fb59 (diff) | |
| download | vcpkg-34c08e2b15777c86c5aaacfee5f04eed986c62da.tar.gz vcpkg-34c08e2b15777c86c5aaacfee5f04eed986c62da.zip | |
Merge branch 'feature_package_implementation'
| -rw-r--r-- | toolsrc/include/PackageSpec.h | 6 | ||||
| -rw-r--r-- | toolsrc/include/Paragraphs.h | 8 | ||||
| -rw-r--r-- | toolsrc/include/SourceParagraph.h | 27 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg_Commands.h | 2 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg_Input.h | 3 | ||||
| -rw-r--r-- | toolsrc/include/vcpkg_Strings.h | 2 | ||||
| -rw-r--r-- | toolsrc/src/Paragraphs.cpp | 21 | ||||
| -rw-r--r-- | toolsrc/src/SourceParagraph.cpp | 62 | ||||
| -rw-r--r-- | toolsrc/src/VcpkgCmdArguments.cpp | 5 | ||||
| -rw-r--r-- | toolsrc/src/commands_build.cpp | 32 | ||||
| -rw-r--r-- | toolsrc/src/commands_build_external.cpp | 6 | ||||
| -rw-r--r-- | toolsrc/src/commands_ci.cpp | 6 | ||||
| -rw-r--r-- | toolsrc/src/commands_depends.cpp | 5 | ||||
| -rw-r--r-- | toolsrc/src/commands_portsdiff.cpp | 4 | ||||
| -rw-r--r-- | toolsrc/src/commands_search.cpp | 61 | ||||
| -rw-r--r-- | toolsrc/src/commands_update.cpp | 4 | ||||
| -rw-r--r-- | toolsrc/src/tests_paragraph.cpp | 116 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg_Dependencies.cpp | 16 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg_Input.cpp | 34 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg_Strings.cpp | 5 |
20 files changed, 300 insertions, 125 deletions
diff --git a/toolsrc/include/PackageSpec.h b/toolsrc/include/PackageSpec.h index 58edb8274..62b6fc9de 100644 --- a/toolsrc/include/PackageSpec.h +++ b/toolsrc/include/PackageSpec.h @@ -26,6 +26,12 @@ namespace vcpkg Triplet m_triplet; }; + struct FullPackageSpec + { + PackageSpec package_spec; + std::vector<std::string> features; + }; + bool operator==(const PackageSpec& left, const PackageSpec& right); bool operator!=(const PackageSpec& left, const PackageSpec& right); } diff --git a/toolsrc/include/Paragraphs.h b/toolsrc/include/Paragraphs.h index 04f9fb879..83a32b2af 100644 --- a/toolsrc/include/Paragraphs.h +++ b/toolsrc/include/Paragraphs.h @@ -16,20 +16,20 @@ namespace vcpkg::Paragraphs Expected<ParagraphDataMap> parse_single_paragraph(const std::string& str); Expected<std::vector<ParagraphDataMap>> parse_paragraphs(const std::string& str); - ExpectedT<SourceParagraph, ParseControlErrorInfo> try_load_port(const Files::Filesystem& fs, - const fs::path& control_path); + ExpectedT<SourceControlFile, ParseControlErrorInfo> try_load_port(const Files::Filesystem& fs, + const fs::path& control_path); Expected<BinaryParagraph> try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec); struct LoadResults { - std::vector<SourceParagraph> paragraphs; + std::vector<SourceControlFile> paragraphs; std::vector<ParseControlErrorInfo> errors; }; LoadResults try_load_all_ports(const Files::Filesystem& fs, const fs::path& ports_dir); - std::vector<SourceParagraph> load_all_ports(const Files::Filesystem& fs, const fs::path& ports_dir); + std::vector<SourceControlFile> load_all_ports(const Files::Filesystem& fs, const fs::path& ports_dir); std::map<std::string, VersionT> extract_port_names_and_versions( const std::vector<SourceParagraph>& source_paragraphs); diff --git a/toolsrc/include/SourceParagraph.h b/toolsrc/include/SourceParagraph.h index 2f30e338e..31c9560cc 100644 --- a/toolsrc/include/SourceParagraph.h +++ b/toolsrc/include/SourceParagraph.h @@ -10,6 +10,8 @@ namespace vcpkg { + extern bool g_feature_packages; + struct Triplet; struct Dependency @@ -27,23 +29,38 @@ namespace vcpkg std::error_code error; }; + struct FeatureParagraph + { + std::string name; + std::string description; + std::vector<Dependency> depends; + }; + /// <summary> /// Port metadata (CONTROL file) /// </summary> struct SourceParagraph { - static ExpectedT<SourceParagraph, ParseControlErrorInfo> parse_control_file( - std::unordered_map<std::string, std::string> fields); - - SourceParagraph() = default; - std::string name; std::string version; std::string description; std::string maintainer; std::vector<std::string> supports; std::vector<Dependency> depends; + std::string default_features; }; + struct SourceControlFile + { + static ExpectedT<SourceControlFile, ParseControlErrorInfo> parse_control_file( + std::vector<std::unordered_map<std::string, std::string>>&& control_paragraphs); + + SourceParagraph core_paragraph; + std::vector<std::unique_ptr<FeatureParagraph>> feature_paragraphs; + + std::vector<ParseControlErrorInfo> errors; + }; + + std::vector<SourceParagraph> getSourceParagraphs(const std::vector<SourceControlFile>& control_files); void print_error_message(span<const ParseControlErrorInfo> error_info_list); inline void print_error_message(const ParseControlErrorInfo& error_info_list) diff --git a/toolsrc/include/vcpkg_Commands.h b/toolsrc/include/vcpkg_Commands.h index 006971e47..67319f240 100644 --- a/toolsrc/include/vcpkg_Commands.h +++ b/toolsrc/include/vcpkg_Commands.h @@ -18,7 +18,7 @@ namespace vcpkg::Commands namespace BuildCommand { - void perform_and_exit(const PackageSpec& spec, + void perform_and_exit(const FullPackageSpec& full_spec, const fs::path& port_dir, const std::unordered_set<std::string>& options, const VcpkgPaths& paths); diff --git a/toolsrc/include/vcpkg_Input.h b/toolsrc/include/vcpkg_Input.h index 77f7ecfb5..fa568207a 100644 --- a/toolsrc/include/vcpkg_Input.h +++ b/toolsrc/include/vcpkg_Input.h @@ -6,6 +6,9 @@ namespace vcpkg::Input PackageSpec check_and_get_package_spec(const std::string& package_spec_as_string, const Triplet& default_triplet, CStringView example_text); + FullPackageSpec check_and_get_full_package_spec(const std::string& full_package_spec_as_string, + const Triplet& default_triplet, + CStringView example_text); void check_triplet(const Triplet& t, const VcpkgPaths& paths); } diff --git a/toolsrc/include/vcpkg_Strings.h b/toolsrc/include/vcpkg_Strings.h index e95a0601a..325a2cb4c 100644 --- a/toolsrc/include/vcpkg_Strings.h +++ b/toolsrc/include/vcpkg_Strings.h @@ -54,6 +54,8 @@ namespace vcpkg::Strings std::string::const_iterator case_insensitive_ascii_find(const std::string& s, const std::string& pattern); + bool case_insensitive_ascii_contains(const std::string& s, const std::string& pattern); + int case_insensitive_ascii_compare(const CStringView left, const CStringView right); std::string ascii_to_lowercase(const std::string& input); diff --git a/toolsrc/src/Paragraphs.cpp b/toolsrc/src/Paragraphs.cpp index 31e8f1da3..440d04ce4 100644 --- a/toolsrc/src/Paragraphs.cpp +++ b/toolsrc/src/Paragraphs.cpp @@ -201,13 +201,22 @@ namespace vcpkg::Paragraphs return Parser(str.c_str(), str.c_str() + str.size()).get_paragraphs(); } - ExpectedT<SourceParagraph, ParseControlErrorInfo> try_load_port(const Files::Filesystem& fs, const fs::path& path) + ExpectedT<SourceControlFile, ParseControlErrorInfo> try_load_port(const Files::Filesystem& fs, const fs::path& path) { ParseControlErrorInfo error_info; - Expected<std::unordered_map<std::string, std::string>> pghs = get_single_paragraph(fs, path / "CONTROL"); - if (auto p = pghs.get()) + Expected<std::vector<std::unordered_map<std::string, std::string>>> pghs = get_paragraphs(fs, path / "CONTROL"); + if (auto vector_pghs = pghs.get()) { - return SourceParagraph::parse_control_file(*p); + auto csf = SourceControlFile::parse_control_file(std::move(*vector_pghs)); + if (!g_feature_packages) + { + if (auto ptr = csf.get()) + { + ptr->core_paragraph.default_features.clear(); + ptr->feature_paragraphs.clear(); + } + } + return csf; } error_info.name = path.filename().generic_u8string(); error_info.error = pghs.error(); @@ -232,7 +241,7 @@ namespace vcpkg::Paragraphs LoadResults ret; for (auto&& path : fs.get_files_non_recursive(ports_dir)) { - ExpectedT<SourceParagraph, ParseControlErrorInfo> source_paragraph = try_load_port(fs, path); + ExpectedT<SourceControlFile, ParseControlErrorInfo> source_paragraph = try_load_port(fs, path); if (auto srcpgh = source_paragraph.get()) { ret.paragraphs.emplace_back(std::move(*srcpgh)); @@ -245,7 +254,7 @@ namespace vcpkg::Paragraphs return ret; } - std::vector<SourceParagraph> load_all_ports(const Files::Filesystem& fs, const fs::path& ports_dir) + std::vector<SourceControlFile> load_all_ports(const Files::Filesystem& fs, const fs::path& ports_dir) { auto results = try_load_all_ports(fs, ports_dir); if (!results.errors.empty()) diff --git a/toolsrc/src/SourceParagraph.cpp b/toolsrc/src/SourceParagraph.cpp index 3b770a4b4..a938feb99 100644 --- a/toolsrc/src/SourceParagraph.cpp +++ b/toolsrc/src/SourceParagraph.cpp @@ -12,7 +12,7 @@ namespace vcpkg { - // + bool g_feature_packages = false; namespace SourceParagraphRequiredField { static const std::string SOURCE = "Source"; @@ -25,6 +25,7 @@ namespace vcpkg static const std::string MAINTAINER = "Maintainer"; static const std::string BUILD_DEPENDS = "Build-Depends"; static const std::string SUPPORTS = "Supports"; + static const std::string DEFAULTFEATURES = "Default-Features"; } static span<const std::string> get_list_of_valid_fields() @@ -40,6 +41,17 @@ namespace vcpkg return valid_fields; } + namespace FeatureParagraphRequiredField + { + static const std::string FEATURE = "Feature"; + } + + namespace FeatureParagraphOptionalField + { + static const std::string DESCRIPTION = "Description"; + static const std::string BUILD_DEPENDS = "Build-Depends"; + } + void print_error_message(span<const ParseControlErrorInfo> error_info_list) { Checks::check_exit(VCPKG_LINE_INFO, error_info_list.size() > 0); @@ -74,11 +86,22 @@ namespace vcpkg System::println("Different source may be available for vcpkg. Use .\\bootstrap-vcpkg.bat to update.\n"); } } + std::vector<SourceParagraph> getSourceParagraphs(const std::vector<SourceControlFile>& control_files) + { + return Util::fmap(control_files, [](const SourceControlFile& x) { return x.core_paragraph; }); + } - ExpectedT<SourceParagraph, ParseControlErrorInfo> SourceParagraph::parse_control_file( - std::unordered_map<std::string, std::string> fields) + ExpectedT<SourceControlFile, ParseControlErrorInfo> SourceControlFile::parse_control_file( + std::vector<std::unordered_map<std::string, std::string>>&& control_paragraphs) { - SourceParagraph sparagraph; + if (control_paragraphs.size() == 0) + { + return ExpectedT<SourceControlFile, ParseControlErrorInfo>(); + } + auto&& fields = control_paragraphs.front(); + + SourceControlFile control_file; + SourceParagraph& sparagraph = control_file.core_paragraph; sparagraph.name = details::remove_required_field(&fields, SourceParagraphRequiredField::SOURCE); sparagraph.version = details::remove_required_field(&fields, SourceParagraphRequiredField::VERSION); sparagraph.description = details::remove_optional_field(&fields, SourceParagraphOptionalField::DESCRIPTION); @@ -90,6 +113,9 @@ namespace vcpkg std::string sups = details::remove_optional_field(&fields, SourceParagraphOptionalField::SUPPORTS); sparagraph.supports = parse_comma_list(sups); + sparagraph.default_features = + details::remove_optional_field(&fields, SourceParagraphOptionalField::DEFAULTFEATURES); + if (!fields.empty()) { const std::vector<std::string> remaining_fields = Maps::extract_keys(fields); @@ -98,7 +124,33 @@ namespace vcpkg return ParseControlErrorInfo{sparagraph.name, remaining_fields_as_string}; } - return sparagraph; + + control_paragraphs.erase(control_paragraphs.begin()); + + for (auto&& feature_pgh : control_paragraphs) + { + control_file.feature_paragraphs.emplace_back(std::make_unique<FeatureParagraph>()); + + FeatureParagraph& fparagraph = *control_file.feature_paragraphs.back(); + + fparagraph.name = details::remove_required_field(&feature_pgh, FeatureParagraphRequiredField::FEATURE); + fparagraph.description = + details::remove_required_field(&feature_pgh, FeatureParagraphOptionalField::DESCRIPTION); + std::string feature_deps = + details::remove_optional_field(&feature_pgh, FeatureParagraphOptionalField::BUILD_DEPENDS); + fparagraph.depends = expand_qualified_dependencies(parse_comma_list(feature_deps)); + + if (!feature_pgh.empty()) + { + const std::vector<std::string> remaining_fields = Maps::extract_keys(feature_pgh); + + const std::string remaining_fields_as_string = Strings::join("\n ", remaining_fields); + + return ParseControlErrorInfo{sparagraph.name, remaining_fields_as_string}; + } + } + + return control_file; } std::vector<Dependency> vcpkg::expand_qualified_dependencies(const std::vector<std::string>& depends) diff --git a/toolsrc/src/VcpkgCmdArguments.cpp b/toolsrc/src/VcpkgCmdArguments.cpp index 733308cb0..62e0b114c 100644 --- a/toolsrc/src/VcpkgCmdArguments.cpp +++ b/toolsrc/src/VcpkgCmdArguments.cpp @@ -117,6 +117,11 @@ namespace vcpkg parse_switch(false, "printmetrics", args.printmetrics); continue; } + if (arg == "--featurepackages") + { + g_feature_packages = true; + continue; + } args.optional_command_arguments.insert(arg); continue; diff --git a/toolsrc/src/commands_build.cpp b/toolsrc/src/commands_build.cpp index 5a5cd462e..a9e4f574e 100644 --- a/toolsrc/src/commands_build.cpp +++ b/toolsrc/src/commands_build.cpp @@ -19,11 +19,12 @@ namespace vcpkg::Commands::BuildCommand static const std::string OPTION_CHECKS_ONLY = "--checks-only"; - void perform_and_exit(const PackageSpec& spec, + void perform_and_exit(const FullPackageSpec& full_spec, const fs::path& port_dir, const std::unordered_set<std::string>& options, const VcpkgPaths& paths) { + const PackageSpec& spec = full_spec.package_spec; if (options.find(OPTION_CHECKS_ONLY) != options.end()) { auto pre_build_info = Build::PreBuildInfo::from_triplet_file(paths, spec.triplet()); @@ -33,25 +34,32 @@ namespace vcpkg::Commands::BuildCommand Checks::exit_success(VCPKG_LINE_INFO); } - const ExpectedT<SourceParagraph, ParseControlErrorInfo> maybe_spgh = + const ExpectedT<SourceControlFile, ParseControlErrorInfo> source_control_file = Paragraphs::try_load_port(paths.get_filesystem(), port_dir); - if (!maybe_spgh) + if (!source_control_file.has_value()) { - print_error_message(maybe_spgh.error()); + print_error_message(source_control_file.error()); Checks::exit_fail(VCPKG_LINE_INFO); } - const SourceParagraph& spgh = maybe_spgh.value_or_exit(VCPKG_LINE_INFO); + for (std::string str : full_spec.features) + { + System::println("%s \n", str); + } + const SourceControlFile& scf = source_control_file.value_or_exit(VCPKG_LINE_INFO); Checks::check_exit(VCPKG_LINE_INFO, - spec.name() == spgh.name, + spec.name() == scf.core_paragraph.name, "The Name: field inside the CONTROL does not match the port directory: '%s' != '%s'", - spgh.name, + scf.core_paragraph.name, spec.name()); StatusParagraphs status_db = database_load_check(paths); Build::BuildPackageOptions build_package_options{Build::UseHeadVersion::NO, Build::AllowDownloads::YES}; - const Build::BuildPackageConfig build_config{spgh, spec.triplet(), paths.port_dir(spec), build_package_options}; + + const Build::BuildPackageConfig build_config{ + scf.core_paragraph, spec.triplet(), paths.port_dir(spec), build_package_options}; + const auto result = Build::build_package(paths, build_config, status_db); if (result.code == BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES) { @@ -82,11 +90,11 @@ namespace vcpkg::Commands::BuildCommand static const std::string example = Commands::Help::create_example_string("build zlib:x64-windows"); args.check_exact_arg_count( 1, example); // Build only takes a single package and all dependencies must already be installed - const PackageSpec spec = - Input::check_and_get_package_spec(args.command_arguments.at(0), default_triplet, example); - Input::check_triplet(spec.triplet(), paths); + std::string command_argument = args.command_arguments.at(0); + const FullPackageSpec spec = Input::check_and_get_full_package_spec(command_argument, default_triplet, example); + Input::check_triplet(spec.package_spec.triplet(), paths); const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments({OPTION_CHECKS_ONLY}); - perform_and_exit(spec, paths.port_dir(spec), options, paths); + perform_and_exit(spec, paths.port_dir(spec.package_spec), options, paths); } } diff --git a/toolsrc/src/commands_build_external.cpp b/toolsrc/src/commands_build_external.cpp index 2712ba0cf..ff70e9cf2 100644 --- a/toolsrc/src/commands_build_external.cpp +++ b/toolsrc/src/commands_build_external.cpp @@ -11,9 +11,9 @@ namespace vcpkg::Commands::BuildExternal static const std::string example = Commands::Help::create_example_string(R"(build_external zlib2 C:\path\to\dir\with\controlfile\)"); args.check_exact_arg_count(2, example); - const PackageSpec spec = - Input::check_and_get_package_spec(args.command_arguments.at(0), default_triplet, example); - Input::check_triplet(spec.triplet(), paths); + const FullPackageSpec spec = + Input::check_and_get_full_package_spec(args.command_arguments.at(0), default_triplet, example); + Input::check_triplet(spec.package_spec.triplet(), paths); const std::unordered_set<std::string> options = args.check_and_get_optional_command_arguments({}); const fs::path port_dir = args.command_arguments.at(1); diff --git a/toolsrc/src/commands_ci.cpp b/toolsrc/src/commands_ci.cpp index 7e724f3ee..65e44e847 100644 --- a/toolsrc/src/commands_ci.cpp +++ b/toolsrc/src/commands_ci.cpp @@ -20,11 +20,11 @@ namespace vcpkg::Commands::CI const fs::path& ports_directory, const Triplet& triplet) { - auto sources = Paragraphs::load_all_ports(fs, ports_directory); - + auto ports = Paragraphs::load_all_ports(fs, ports_directory); std::vector<PackageSpec> specs; - for (const SourceParagraph& p : sources) + for (const SourceControlFile& control_file : ports) { + const SourceParagraph& p = control_file.core_paragraph; specs.push_back(PackageSpec::from_name_and_triplet(p.name, triplet).value_or_exit(VCPKG_LINE_INFO)); } diff --git a/toolsrc/src/commands_depends.cpp b/toolsrc/src/commands_depends.cpp index 9db4b7bb1..468bf5d72 100644 --- a/toolsrc/src/commands_depends.cpp +++ b/toolsrc/src/commands_depends.cpp @@ -13,10 +13,11 @@ namespace vcpkg::Commands::DependInfo args.check_exact_arg_count(0, example); args.check_and_get_optional_command_arguments({}); - auto sources = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports); + const auto source_control_files = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports); - for (const SourceParagraph& source_paragraph : sources) + for (const SourceControlFile& 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; }); System::println("%s: %s", source_paragraph.name, s); } diff --git a/toolsrc/src/commands_portsdiff.cpp b/toolsrc/src/commands_portsdiff.cpp index a614d654e..e872c394d 100644 --- a/toolsrc/src/commands_portsdiff.cpp +++ b/toolsrc/src/commands_portsdiff.cpp @@ -97,10 +97,10 @@ namespace vcpkg::Commands::PortsDiff L".vcpkg-root", git_exe.native()); System::cmd_execute_clean(cmd); - const std::vector<SourceParagraph> source_paragraphs = + const std::vector<SourceControlFile> source_control_files = Paragraphs::load_all_ports(paths.get_filesystem(), temp_checkout_path / ports_dir_name_as_string); const std::map<std::string, VersionT> names_and_versions = - Paragraphs::extract_port_names_and_versions(source_paragraphs); + Paragraphs::extract_port_names_and_versions(getSourceParagraphs(source_control_files)); fs.remove_all(temp_checkout_path, ec); return names_and_versions; } diff --git a/toolsrc/src/commands_search.cpp b/toolsrc/src/commands_search.cpp index 0f8ebbb3b..b39d21887 100644 --- a/toolsrc/src/commands_search.cpp +++ b/toolsrc/src/commands_search.cpp @@ -19,15 +19,16 @@ namespace vcpkg::Commands::Search return output; } - static std::string create_graph_as_string(const std::vector<SourceParagraph>& source_paragraphs) + static std::string create_graph_as_string(const std::vector<SourceControlFile>& source_control_files) { int empty_node_count = 0; std::string s; s.append("digraph G{ rankdir=LR; edge [minlen=3]; overlap=false;"); - for (const SourceParagraph& source_paragraph : source_paragraphs) + for (const SourceControlFile& source_control_file : source_control_files) { + const SourceParagraph& source_paragraph = source_control_file.core_paragraph; if (source_paragraph.depends.empty()) { empty_node_count++; @@ -46,10 +47,9 @@ namespace vcpkg::Commands::Search s.append(Strings::format("empty [label=\"%d singletons...\"]; }", empty_node_count)); return s; } - - static void do_print(const SourceParagraph& source_paragraph, bool FullDesc) + static void do_print(const SourceParagraph& source_paragraph, bool full_desc) { - if (FullDesc) + if (full_desc) { System::println( "%-20s %-16s %s", source_paragraph.name, source_paragraph.version, source_paragraph.description); @@ -63,6 +63,20 @@ namespace vcpkg::Commands::Search } } + static void do_print(const std::string& name, const FeatureParagraph& feature_paragraph, bool full_desc) + { + if (full_desc) + { + System::println("%-37s %s", name + "[" + feature_paragraph.name + "]", feature_paragraph.description); + } + else + { + System::println("%-37s %s", + name + "[" + feature_paragraph.name + "]", + details::shorten_description(feature_paragraph.description)); + } + } + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) { static const std::string example = Strings::format( @@ -85,7 +99,7 @@ namespace vcpkg::Commands::Search for (auto&& error : sources_and_errors.errors) { System::println( - System::Color::warning, "Warning: an error occurred while parsing '%s'\n", error.name); + System::Color::warning, "Warning: an error occurred while parsing '%s'", error.name); } System::println(System::Color::warning, "Use '--debug' to get more information about the parse failures.\n"); @@ -93,7 +107,6 @@ namespace vcpkg::Commands::Search } auto& source_paragraphs = sources_and_errors.paragraphs; - if (options.find(OPTION_GRAPH) != options.cend()) { const std::string graph_as_string = create_graph_as_string(source_paragraphs); @@ -103,27 +116,41 @@ namespace vcpkg::Commands::Search if (args.command_arguments.empty()) { - for (const SourceParagraph& source_paragraph : source_paragraphs) + for (const SourceControlFile& source_control_file : source_paragraphs) { - do_print(source_paragraph, options.find(OPTION_FULLDESC) != options.cend()); + do_print(source_control_file.core_paragraph, options.find(OPTION_FULLDESC) != options.cend()); + for (auto&& feature_paragraph : source_control_file.feature_paragraphs) + { + do_print(source_control_file.core_paragraph.name, + *feature_paragraph, + options.find(OPTION_FULLDESC) != options.cend()); + } } } else { + const auto& icontains = Strings::case_insensitive_ascii_contains; + // At this point there is 1 argument - for (const SourceParagraph& source_paragraph : source_paragraphs) + auto&& args_zero = args.command_arguments[0]; + for (const SourceControlFile& source_control_file : source_paragraphs) { - if (Strings::case_insensitive_ascii_find(source_paragraph.name, args.command_arguments[0]) == - source_paragraph.name.end()) + auto&& sp = source_control_file.core_paragraph; + + bool contains_name = icontains(sp.name, args_zero); + if (contains_name || icontains(sp.description, args_zero)) { - if (Strings::case_insensitive_ascii_find(source_paragraph.description, args.command_arguments[0]) == - source_paragraph.description.end()) + do_print(sp, options.find(OPTION_FULLDESC) != options.cend()); + } + + for (auto&& feature_paragraph : source_control_file.feature_paragraphs) + { + if (contains_name || icontains(feature_paragraph->name, args_zero) || + icontains(feature_paragraph->description, args_zero)) { - continue; + do_print(sp.name, *feature_paragraph, options.find(OPTION_FULLDESC) != options.cend()); } } - - do_print(source_paragraph, options.find(OPTION_FULLDESC) != options.cend()); } } diff --git a/toolsrc/src/commands_update.cpp b/toolsrc/src/commands_update.cpp index f87ccfb06..f00a89da4 100644 --- a/toolsrc/src/commands_update.cpp +++ b/toolsrc/src/commands_update.cpp @@ -15,8 +15,8 @@ namespace vcpkg::Commands::Update std::vector<OutdatedPackage> find_outdated_packages(const VcpkgPaths& paths, const StatusParagraphs& status_db) { - const std::vector<SourceParagraph> source_paragraphs = - Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports); + auto source_control_files = Paragraphs::load_all_ports(paths.get_filesystem(), paths.ports); + const std::vector<SourceParagraph> source_paragraphs = getSourceParagraphs(source_control_files); const std::map<std::string, VersionT> src_names_to_versions = Paragraphs::extract_port_names_and_versions(source_paragraphs); const std::vector<StatusParagraph*> installed_packages = get_installed_ports(status_db); diff --git a/toolsrc/src/tests_paragraph.cpp b/toolsrc/src/tests_paragraph.cpp index 374e4ddd1..8dff520fb 100644 --- a/toolsrc/src/tests_paragraph.cpp +++ b/toolsrc/src/tests_paragraph.cpp @@ -25,99 +25,107 @@ namespace UnitTest1 { TEST_METHOD(SourceParagraph_Construct_Minimum) { - auto m_pgh = vcpkg::SourceParagraph::parse_control_file({{"Source", "zlib"}, {"Version", "1.2.8"}}); + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector<std::unordered_map<std::string, std::string>>{{ + {"Source", "zlib"}, {"Version", "1.2.8"}, + }}); Assert::IsTrue(m_pgh.has_value()); auto& pgh = *m_pgh.get(); - Assert::AreEqual("zlib", pgh.name.c_str()); - Assert::AreEqual("1.2.8", pgh.version.c_str()); - Assert::AreEqual("", pgh.maintainer.c_str()); - Assert::AreEqual("", pgh.description.c_str()); - Assert::AreEqual(size_t(0), pgh.depends.size()); + Assert::AreEqual("zlib", pgh.core_paragraph.name.c_str()); + Assert::AreEqual("1.2.8", pgh.core_paragraph.version.c_str()); + Assert::AreEqual("", pgh.core_paragraph.maintainer.c_str()); + Assert::AreEqual("", pgh.core_paragraph.description.c_str()); + Assert::AreEqual(size_t(0), pgh.core_paragraph.depends.size()); } TEST_METHOD(SourceParagraph_Construct_Maximum) { - auto m_pgh = vcpkg::SourceParagraph::parse_control_file({ - {"Source", "s"}, - {"Version", "v"}, - {"Maintainer", "m"}, - {"Description", "d"}, - {"Build-Depends", "bd"}, - {"Supports", "x64"}, - }); + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector<std::unordered_map<std::string, std::string>>{{ + {"Source", "s"}, + {"Version", "v"}, + {"Maintainer", "m"}, + {"Description", "d"}, + {"Build-Depends", "bd"}, + {"Supports", "x64"}, + }}); Assert::IsTrue(m_pgh.has_value()); auto& pgh = *m_pgh.get(); - Assert::AreEqual("s", pgh.name.c_str()); - Assert::AreEqual("v", pgh.version.c_str()); - Assert::AreEqual("m", pgh.maintainer.c_str()); - Assert::AreEqual("d", pgh.description.c_str()); - Assert::AreEqual(size_t(1), pgh.depends.size()); - Assert::AreEqual("bd", pgh.depends[0].name.c_str()); - Assert::AreEqual(size_t(1), pgh.supports.size()); - Assert::AreEqual("x64", pgh.supports[0].c_str()); + Assert::AreEqual("s", pgh.core_paragraph.name.c_str()); + Assert::AreEqual("v", pgh.core_paragraph.version.c_str()); + 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(size_t(1), pgh.core_paragraph.supports.size()); + Assert::AreEqual("x64", pgh.core_paragraph.supports[0].c_str()); } TEST_METHOD(SourceParagraph_Two_Depends) { - auto m_pgh = vcpkg::SourceParagraph::parse_control_file({ - {"Source", "zlib"}, {"Version", "1.2.8"}, {"Build-Depends", "z, openssl"}, - }); + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector<std::unordered_map<std::string, std::string>>{{ + {"Source", "zlib"}, {"Version", "1.2.8"}, {"Build-Depends", "z, openssl"}, + }}); Assert::IsTrue(m_pgh.has_value()); auto& pgh = *m_pgh.get(); - Assert::AreEqual(size_t(2), pgh.depends.size()); - Assert::AreEqual("z", pgh.depends[0].name.c_str()); - Assert::AreEqual("openssl", pgh.depends[1].name.c_str()); + 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()); } TEST_METHOD(SourceParagraph_Three_Depends) { - auto m_pgh = vcpkg::SourceParagraph::parse_control_file({ - {"Source", "zlib"}, {"Version", "1.2.8"}, {"Build-Depends", "z, openssl, xyz"}, - }); + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector<std::unordered_map<std::string, std::string>>{{ + {"Source", "zlib"}, {"Version", "1.2.8"}, {"Build-Depends", "z, openssl, xyz"}, + }}); Assert::IsTrue(m_pgh.has_value()); auto& pgh = *m_pgh.get(); - Assert::AreEqual(size_t(3), pgh.depends.size()); - Assert::AreEqual("z", pgh.depends[0].name.c_str()); - Assert::AreEqual("openssl", pgh.depends[1].name.c_str()); - Assert::AreEqual("xyz", pgh.depends[2].name.c_str()); + 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()); } TEST_METHOD(SourceParagraph_Three_Supports) { - auto m_pgh = vcpkg::SourceParagraph::parse_control_file({ - {"Source", "zlib"}, {"Version", "1.2.8"}, {"Supports", "x64, windows, uwp"}, - }); + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector<std::unordered_map<std::string, std::string>>{{ + {"Source", "zlib"}, {"Version", "1.2.8"}, {"Supports", "x64, windows, uwp"}, + }}); Assert::IsTrue(m_pgh.has_value()); auto& pgh = *m_pgh.get(); - Assert::AreEqual(size_t(3), pgh.supports.size()); - Assert::AreEqual("x64", pgh.supports[0].c_str()); - Assert::AreEqual("windows", pgh.supports[1].c_str()); - Assert::AreEqual("uwp", pgh.supports[2].c_str()); + Assert::AreEqual(size_t(3), pgh.core_paragraph.supports.size()); + Assert::AreEqual("x64", pgh.core_paragraph.supports[0].c_str()); + Assert::AreEqual("windows", pgh.core_paragraph.supports[1].c_str()); + Assert::AreEqual("uwp", pgh.core_paragraph.supports[2].c_str()); } TEST_METHOD(SourceParagraph_Construct_Qualified_Depends) { - auto m_pgh = vcpkg::SourceParagraph::parse_control_file({ - {"Source", "zlib"}, {"Version", "1.2.8"}, {"Build-Depends", "libA [windows], libB [uwp]"}, - }); + auto m_pgh = + vcpkg::SourceControlFile::parse_control_file(std::vector<std::unordered_map<std::string, std::string>>{{ + {"Source", "zlib"}, {"Version", "1.2.8"}, {"Build-Depends", "libA [windows], libB [uwp]"}, + }}); Assert::IsTrue(m_pgh.has_value()); auto& pgh = *m_pgh.get(); - Assert::AreEqual("zlib", pgh.name.c_str()); - Assert::AreEqual("1.2.8", pgh.version.c_str()); - Assert::AreEqual("", pgh.maintainer.c_str()); - Assert::AreEqual("", pgh.description.c_str()); - Assert::AreEqual(size_t(2), pgh.depends.size()); - Assert::AreEqual("libA", pgh.depends[0].name.c_str()); - Assert::AreEqual("windows", pgh.depends[0].qualifier.c_str()); - Assert::AreEqual("libB", pgh.depends[1].name.c_str()); - Assert::AreEqual("uwp", pgh.depends[1].qualifier.c_str()); + Assert::AreEqual("zlib", pgh.core_paragraph.name.c_str()); + Assert::AreEqual("1.2.8", pgh.core_paragraph.version.c_str()); + 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("windows", pgh.core_paragraph.depends[0].qualifier.c_str()); + Assert::AreEqual("libB", pgh.core_paragraph.depends[1].name.c_str()); + Assert::AreEqual("uwp", pgh.core_paragraph.depends[1].qualifier.c_str()); } TEST_METHOD(BinaryParagraph_Construct_Minimum) diff --git a/toolsrc/src/vcpkg_Dependencies.cpp b/toolsrc/src/vcpkg_Dependencies.cpp index f32d92f4c..add8acb4d 100644 --- a/toolsrc/src/vcpkg_Dependencies.cpp +++ b/toolsrc/src/vcpkg_Dependencies.cpp @@ -174,12 +174,12 @@ namespace vcpkg::Dependencies if (auto bpgh = maybe_bpgh.get()) return InstallPlanAction{spec, {nullopt, *bpgh, nullopt}, request_type}; - ExpectedT<SourceParagraph, ParseControlErrorInfo> maybe_spgh = + ExpectedT<SourceControlFile, ParseControlErrorInfo> source_control_file = Paragraphs::try_load_port(paths.get_filesystem(), paths.port_dir(spec)); - if (auto spgh = maybe_spgh.get()) - return InstallPlanAction{spec, {nullopt, nullopt, *spgh}, request_type}; + if (auto scf = source_control_file.get()) + return InstallPlanAction{spec, {nullopt, nullopt, (*scf).core_paragraph}, request_type}; - print_error_message(maybe_spgh.error()); + print_error_message(source_control_file.error()); Checks::exit_fail(VCPKG_LINE_INFO); } }; @@ -284,13 +284,13 @@ namespace vcpkg::Dependencies if (auto bpgh = maybe_bpgh.get()) return ExportPlanAction{spec, {nullopt, *bpgh, nullopt}, request_type}; - ExpectedT<SourceParagraph, ParseControlErrorInfo> maybe_spgh = + ExpectedT<SourceControlFile, ParseControlErrorInfo> source_control_file = Paragraphs::try_load_port(paths.get_filesystem(), paths.port_dir(spec)); - if (auto spgh = maybe_spgh.get()) - return ExportPlanAction{spec, {nullopt, nullopt, *spgh}, request_type}; + if (auto scf = source_control_file.get()) + return ExportPlanAction{spec, {nullopt, nullopt, (*scf).core_paragraph}, request_type}; else - print_error_message(maybe_spgh.error()); + print_error_message(source_control_file.error()); Checks::exit_with_message(VCPKG_LINE_INFO, "Could not find package %s", spec); } diff --git a/toolsrc/src/vcpkg_Input.cpp b/toolsrc/src/vcpkg_Input.cpp index df738315b..fdedd5507 100644 --- a/toolsrc/src/vcpkg_Input.cpp +++ b/toolsrc/src/vcpkg_Input.cpp @@ -15,7 +15,7 @@ namespace vcpkg::Input auto expected_spec = PackageSpec::from_string(as_lowercase, default_triplet); if (auto spec = expected_spec.get()) { - return *spec; + return PackageSpec{*spec}; } // Intentionally show the lowercased string @@ -34,4 +34,36 @@ namespace vcpkg::Input Checks::exit_fail(VCPKG_LINE_INFO); } } + + FullPackageSpec check_and_get_full_package_spec(const std::string& full_package_spec_as_string, + 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()) + { + return {*spec, + parse_comma_list(full_package_spec_as_string.substr(left_pos + 1, right_pos - left_pos - 1))}; + } + + // Intentionally show the lowercased string + System::println(System::Color::error, "Error: %s: %s", vcpkg::to_string(expected_spec.error()), as_lowercase); + System::print(example_text); + Checks::exit_fail(VCPKG_LINE_INFO); + } } diff --git a/toolsrc/src/vcpkg_Strings.cpp b/toolsrc/src/vcpkg_Strings.cpp index 9ba9eb700..aafed5fd3 100644 --- a/toolsrc/src/vcpkg_Strings.cpp +++ b/toolsrc/src/vcpkg_Strings.cpp @@ -68,6 +68,11 @@ namespace vcpkg::Strings [](const char a, const char b) { return details::tolower_char(a) == b; }); } + bool case_insensitive_ascii_contains(const std::string& s, const std::string& pattern) + { + return case_insensitive_ascii_find(s, pattern) != s.end(); + } + int case_insensitive_ascii_compare(const CStringView left, const CStringView right) { return _stricmp(left, right); |
