From 7f336c746776daf2af95914ed25ff3d50a96b387 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 5 Nov 2016 01:02:15 -0700 Subject: Enable qualified dependencies. Fix bug in internal 'build' command. Added capability for CONTROL files to specify qualified dependencies, which are substring searched inside triplet names. Fixed bug in internal 'build' command where if a package is already built, that built package's dependencies will be used to determine requirements for the build instead of the port directory's CONTROL file. --- toolsrc/include/SourceParagraph.h | 17 +- toolsrc/include/vcpkg.h | 1 + toolsrc/include/vcpkg_Dependencies.h | 2 +- toolsrc/include/vcpkglib_helpers.h | 2 - toolsrc/src/BinaryParagraph.cpp | 4 +- toolsrc/src/SourceParagraph.cpp | 83 ++++++- toolsrc/src/commands_installation.cpp | 11 +- toolsrc/src/lib.cpp | 40 +-- toolsrc/src/test.cpp | 347 -------------------------- toolsrc/src/tests_dependencies.cpp | 39 +++ toolsrc/src/tests_paragraph.cpp | 367 ++++++++++++++++++++++++++++ toolsrc/src/vcpkg_Checks.cpp | 3 + toolsrc/src/vcpkg_Dependencies.cpp | 8 +- toolsrc/src/vcpkglib_helpers.cpp | 33 --- toolsrc/vcpkgtest/vcpkgtest.vcxproj | 5 +- toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters | 5 +- 16 files changed, 553 insertions(+), 414 deletions(-) delete mode 100644 toolsrc/src/test.cpp create mode 100644 toolsrc/src/tests_dependencies.cpp create mode 100644 toolsrc/src/tests_paragraph.cpp diff --git a/toolsrc/include/SourceParagraph.h b/toolsrc/include/SourceParagraph.h index bac005144..5ae9b38b8 100644 --- a/toolsrc/include/SourceParagraph.h +++ b/toolsrc/include/SourceParagraph.h @@ -5,6 +5,16 @@ namespace vcpkg { + struct triplet; + + struct dependency + { + std::string name; + std::string qualifier; + }; + + std::ostream& operator<<(std::ostream& os, const dependency& p); + struct SourceParagraph { SourceParagraph(); @@ -15,6 +25,11 @@ namespace vcpkg std::string version; std::string description; std::string maintainer; - std::vector depends; + std::vector depends; }; + + std::vector filter_dependencies(const std::vector& deps, const triplet& t); + + std::vector expand_qualified_dependencies(const std::vector& depends); + std::vector parse_depends(const std::string& depends_string); } diff --git a/toolsrc/include/vcpkg.h b/toolsrc/include/vcpkg.h index a4a0682cf..dc5933f10 100644 --- a/toolsrc/include/vcpkg.h +++ b/toolsrc/include/vcpkg.h @@ -21,6 +21,7 @@ namespace vcpkg StatusParagraphs database_load_check(const vcpkg_paths& paths); std::vector get_unmet_package_dependencies(const vcpkg_paths& paths, const package_spec& spec, const StatusParagraphs& status_db); + std::vector get_unmet_package_build_dependencies(const vcpkg_paths& paths, const package_spec& spec, const StatusParagraphs& status_db); void install_package(const vcpkg_paths& paths, const BinaryParagraph& binary_paragraph, StatusParagraphs& status_db); void deinstall_package(const vcpkg_paths& paths, const package_spec& spec, StatusParagraphs& status_db); diff --git a/toolsrc/include/vcpkg_Dependencies.h b/toolsrc/include/vcpkg_Dependencies.h index 9dc32fc41..94aa51f99 100644 --- a/toolsrc/include/vcpkg_Dependencies.h +++ b/toolsrc/include/vcpkg_Dependencies.h @@ -9,5 +9,5 @@ namespace vcpkg {namespace Dependencies { std::vector create_dependency_ordered_install_plan(const vcpkg_paths& paths, const std::vector& specs, const StatusParagraphs& status_db); - std::unordered_set find_unmet_dependencies(const vcpkg_paths& paths, const package_spec& spec, const StatusParagraphs& status_db); + std::unordered_set find_unmet_dependencies(const vcpkg_paths& paths, const std::vector& specs, const StatusParagraphs& status_db); }} diff --git a/toolsrc/include/vcpkglib_helpers.h b/toolsrc/include/vcpkglib_helpers.h index 05c9e17df..640fab555 100644 --- a/toolsrc/include/vcpkglib_helpers.h +++ b/toolsrc/include/vcpkglib_helpers.h @@ -9,6 +9,4 @@ namespace vcpkg {namespace details std::string required_field(const std::unordered_map& fields, const std::string& fieldname); std::string remove_required_field(std::unordered_map* fields, const std::string& fieldname); - - std::vector parse_depends(const std::string& depends_string); }} diff --git a/toolsrc/src/BinaryParagraph.cpp b/toolsrc/src/BinaryParagraph.cpp index 6dceb66d9..ad85a1f8a 100644 --- a/toolsrc/src/BinaryParagraph.cpp +++ b/toolsrc/src/BinaryParagraph.cpp @@ -56,7 +56,7 @@ namespace vcpkg Checks::check_exit(multi_arch == "same", "Multi-Arch must be 'same' but was %s", multi_arch); std::string deps = details::remove_optional_field(&fields, BinaryParagraphOptionalField::DEPENDS); - this->depends = details::parse_depends(deps); + this->depends = parse_depends(deps); } BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const triplet& target_triplet) @@ -65,7 +65,7 @@ namespace vcpkg this->version = spgh.version; this->description = spgh.description; this->maintainer = spgh.maintainer; - this->depends = spgh.depends; + this->depends = filter_dependencies(spgh.depends, target_triplet); } std::string BinaryParagraph::displayname() const diff --git a/toolsrc/src/SourceParagraph.cpp b/toolsrc/src/SourceParagraph.cpp index 6f25dbded..bdf15a737 100644 --- a/toolsrc/src/SourceParagraph.cpp +++ b/toolsrc/src/SourceParagraph.cpp @@ -2,6 +2,7 @@ #include "vcpkglib_helpers.h" #include "vcpkg_System.h" #include "vcpkg_Maps.h" +#include "triplet.h" namespace vcpkg { @@ -44,7 +45,7 @@ namespace vcpkg this->maintainer = details::remove_optional_field(&fields, SourceParagraphOptionalField::MAINTAINER); std::string deps = details::remove_optional_field(&fields, SourceParagraphOptionalField::BUILD_DEPENDS); - this->depends = details::parse_depends(deps); + this->depends = expand_qualified_dependencies(parse_depends(deps)); if (!fields.empty()) { @@ -60,4 +61,84 @@ namespace vcpkg exit(EXIT_FAILURE); } } + + std::vector vcpkg::expand_qualified_dependencies(const std::vector& depends) + { + auto convert = [&](const std::string& depend_string) -> dependency { + auto pos = depend_string.find(' '); + if (pos == std::string::npos) + return{ depend_string, "" }; + // expect of the form "\w+ \[\w+\]" + dependency dep; + dep.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, "" }; + } + dep.qualifier = depend_string.substr(pos + 2, depend_string.size() - pos - 3); + return dep; + }; + + std::vector ret; + + for (auto&& depend_string : depends) + { + ret.push_back(convert(depend_string)); + } + + return ret; + } + + std::vector parse_depends(const std::string& depends_string) + { + if (depends_string.empty()) + { + return{}; + } + + std::vector out; + + size_t cur = 0; + do + { + auto pos = depends_string.find(',', cur); + if (pos == std::string::npos) + { + out.push_back(depends_string.substr(cur)); + break; + } + out.push_back(depends_string.substr(cur, pos - cur)); + + // skip comma and space + ++pos; + if (depends_string[pos] == ' ') + { + ++pos; + } + + cur = pos; + } while (cur != std::string::npos); + + return out; + } + + std::vector filter_dependencies(const std::vector& deps, const triplet& t) + { + std::vector ret; + for (auto&& dep : deps) + { + if (dep.qualifier.empty() || t.canonical_name().find(dep.qualifier) != std::string::npos) + { + ret.push_back(dep.name); + } + } + return ret; + } + + std::ostream & operator<<(std::ostream & os, const dependency & p) + { + os << p.name; + return os; + } } diff --git a/toolsrc/src/commands_installation.cpp b/toolsrc/src/commands_installation.cpp index 022b87139..f6aeafa02 100644 --- a/toolsrc/src/commands_installation.cpp +++ b/toolsrc/src/commands_installation.cpp @@ -138,7 +138,16 @@ namespace vcpkg const package_spec spec = Input::check_and_get_package_spec(args.command_arguments.at(0), default_target_triplet, example.c_str()); Input::check_triplet(spec.target_triplet(), paths); - std::unordered_set unmet_dependencies = Dependencies::find_unmet_dependencies(paths, spec, status_db); + + // Explicitly load and use the portfile's build dependencies when resolving the build command (instead of a cached package's dependencies). + auto first_level_deps = get_unmet_package_build_dependencies(paths, spec, status_db); + std::vector first_level_deps_specs; + for (auto&& dep : first_level_deps) + { + first_level_deps_specs.push_back(package_spec::from_name_and_triplet(dep, spec.target_triplet()).get_or_throw()); + } + + std::unordered_set unmet_dependencies = Dependencies::find_unmet_dependencies(paths, first_level_deps_specs, status_db); if (!unmet_dependencies.empty()) { System::println(System::color::error, "The build command requires all dependencies to be already installed."); diff --git a/toolsrc/src/lib.cpp b/toolsrc/src/lib.cpp index 45b73ee07..3c844ac3f 100644 --- a/toolsrc/src/lib.cpp +++ b/toolsrc/src/lib.cpp @@ -209,29 +209,33 @@ static void install_and_write_listfile(const vcpkg_paths& paths, const BinaryPar // TODO: Refactoring between this function and install_package std::vector vcpkg::get_unmet_package_dependencies(const vcpkg_paths& paths, const package_spec& spec, const StatusParagraphs& status_db) { - std::vector> pghs; - { - const fs::path packages_dir_control_file_path = paths.package_dir(spec) / "CONTROL"; + const fs::path packages_dir_control_file_path = paths.package_dir(spec) / "CONTROL"; - auto control_contents_maybe = Files::get_contents(packages_dir_control_file_path); - if (auto control_contents = control_contents_maybe.get()) + auto control_contents_maybe = Files::get_contents(packages_dir_control_file_path); + if (auto control_contents = control_contents_maybe.get()) + { + std::vector> pghs; + try + { + pghs = parse_paragraphs(*control_contents); + } + catch (std::runtime_error) { - try - { - pghs = parse_paragraphs(*control_contents); - } - catch (std::runtime_error) - { - } - Checks::check_exit(pghs.size() == 1, "Invalid control file at %s", packages_dir_control_file_path.string()); - return BinaryParagraph(pghs[0]).depends; } + Checks::check_exit(pghs.size() == 1, "Invalid control file at %s", packages_dir_control_file_path.string()); + return BinaryParagraph(pghs[0]).depends; } + return get_unmet_package_build_dependencies(paths, spec, status_db); +} + +std::vector vcpkg::get_unmet_package_build_dependencies(const vcpkg_paths& paths, const package_spec& spec, const StatusParagraphs& status_db) +{ const fs::path ports_dir_control_file_path = paths.port_dir(spec) / "CONTROL"; auto control_contents_maybe = Files::get_contents(ports_dir_control_file_path); if (auto control_contents = control_contents_maybe.get()) { + std::vector> pghs; try { pghs = parse_paragraphs(*control_contents); @@ -240,7 +244,7 @@ std::vector vcpkg::get_unmet_package_dependencies(const vcpkg_paths { } Checks::check_exit(pghs.size() == 1, "Invalid control file at %s", ports_dir_control_file_path.string()); - return SourceParagraph(pghs[0]).depends; + return filter_dependencies(SourceParagraph(pghs[0]).depends, spec.target_triplet()); } Checks::exit_with_message("Could not find package named %s", spec); @@ -252,11 +256,11 @@ void vcpkg::install_package(const vcpkg_paths& paths, const BinaryParagraph& bin spgh.package = binary_paragraph; spgh.want = want_t::install; spgh.state = install_state_t::half_installed; - for (const std::string& dependency : spgh.package.depends) + for (auto&& dep : spgh.package.depends) { - if (status_db.find_installed(dependency, spgh.package.spec.target_triplet()) == status_db.end()) + if (status_db.find_installed(dep, spgh.package.spec.target_triplet()) == status_db.end()) { - std::abort(); + Checks::unreachable(); } } write_update(paths, spgh); diff --git a/toolsrc/src/test.cpp b/toolsrc/src/test.cpp deleted file mode 100644 index fc49b362d..000000000 --- a/toolsrc/src/test.cpp +++ /dev/null @@ -1,347 +0,0 @@ -#include "CppUnitTest.h" -#include "vcpkg.h" - -#pragma comment(lib,"version") -#pragma comment(lib,"winhttp") - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; - -namespace Microsoft { namespace VisualStudio { namespace CppUnitTestFramework -{ - template <> - inline std::wstring ToString(const vcpkg::package_spec_parse_result& t) - { - return ToString(static_cast(t)); - } -}}} - -namespace UnitTest1 -{ - TEST_CLASS(ControlParsing) - { - public: - TEST_METHOD(SourceParagraph_Construct_Minimum) - { - vcpkg::SourceParagraph pgh({ - {"Source", "zlib"}, - {"Version", "1.2.8"} - }); - - 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()); - } - - TEST_METHOD(SourceParagraph_Construct_Maximum) - { - vcpkg::SourceParagraph pgh({ - {"Source", "s"}, - {"Version", "v"}, - {"Maintainer", "m"}, - {"Description", "d"}, - {"Build-Depends", "bd"} - }); - 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].c_str()); - } - - TEST_METHOD(SourceParagraph_Two_Depends) - { - vcpkg::SourceParagraph pgh({ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - {"Build-Depends", "z, openssl"} - }); - - Assert::AreEqual(size_t(2), pgh.depends.size()); - Assert::AreEqual("z", pgh.depends[0].c_str()); - Assert::AreEqual("openssl", pgh.depends[1].c_str()); - } - - TEST_METHOD(SourceParagraph_Three_Depends) - { - vcpkg::SourceParagraph pgh({ - {"Source", "zlib"}, - {"Version", "1.2.8"}, - {"Build-Depends", "z, openssl, xyz"} - }); - - Assert::AreEqual(size_t(3), pgh.depends.size()); - Assert::AreEqual("z", pgh.depends[0].c_str()); - Assert::AreEqual("openssl", pgh.depends[1].c_str()); - Assert::AreEqual("xyz", pgh.depends[2].c_str()); - } - - TEST_METHOD(BinaryParagraph_Construct_Minimum) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "a"}, - {"Multi-Arch", "same"}, - }); - - Assert::AreEqual("zlib", pgh.spec.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("a", pgh.spec.target_triplet().canonical_name().c_str()); - Assert::AreEqual(size_t(0), pgh.depends.size()); - } - - TEST_METHOD(BinaryParagraph_Construct_Maximum) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "s"}, - {"Version", "v"}, - {"Architecture", "a"}, - {"Multi-Arch", "same"}, - {"Maintainer", "m"}, - {"Description", "d"}, - {"Depends", "bd"} - }); - Assert::AreEqual("s", pgh.spec.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].c_str()); - } - - TEST_METHOD(BinaryParagraph_Three_Depends) - { - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "a"}, - {"Multi-Arch", "same"}, - {"Depends", "a, b, c"}, - }); - - Assert::AreEqual(size_t(3), pgh.depends.size()); - Assert::AreEqual("a", pgh.depends[0].c_str()); - Assert::AreEqual("b", pgh.depends[1].c_str()); - Assert::AreEqual("c", pgh.depends[2].c_str()); - } - - TEST_METHOD(parse_paragraphs_empty) - { - const char* str = ""; - auto pghs = vcpkg::parse_paragraphs(str); - Assert::IsTrue(pghs.empty()); - } - - TEST_METHOD(parse_paragraphs_one_field) - { - const char* str = "f1: v1"; - auto pghs = vcpkg::parse_paragraphs(str); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(1), pghs[0].size()); - Assert::AreEqual("v1", pghs[0]["f1"].c_str()); - } - - TEST_METHOD(parse_paragraphs_one_pgh) - { - const char* str = - "f1: v1\n" - "f2: v2"; - auto pghs = vcpkg::parse_paragraphs(str); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(2), pghs[0].size()); - Assert::AreEqual("v1", pghs[0]["f1"].c_str()); - Assert::AreEqual("v2", pghs[0]["f2"].c_str()); - } - - TEST_METHOD(parse_paragraphs_two_pgh) - { - const char* str = - "f1: v1\n" - "f2: v2\n" - "\n" - "f3: v3\n" - "f4: v4"; - auto pghs = vcpkg::parse_paragraphs(str); - Assert::AreEqual(size_t(2), pghs.size()); - Assert::AreEqual(size_t(2), pghs[0].size()); - Assert::AreEqual("v1", pghs[0]["f1"].c_str()); - Assert::AreEqual("v2", pghs[0]["f2"].c_str()); - Assert::AreEqual(size_t(2), pghs[1].size()); - Assert::AreEqual("v3", pghs[1]["f3"].c_str()); - Assert::AreEqual("v4", pghs[1]["f4"].c_str()); - } - - TEST_METHOD(parse_paragraphs_field_names) - { - const char* str = - "1:\n" - "f:\n" - "F:\n" - "0:\n" - "F-2:\n"; - auto pghs = vcpkg::parse_paragraphs(str); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(5), pghs[0].size()); - } - - TEST_METHOD(parse_paragraphs_multiple_blank_lines) - { - const char* str = - "f1: v1\n" - "f2: v2\n" - "\n" - "\n" - "f3: v3\n" - "f4: v4"; - auto pghs = vcpkg::parse_paragraphs(str); - Assert::AreEqual(size_t(2), pghs.size()); - } - - TEST_METHOD(parse_paragraphs_empty_fields) - { - const char* str = - "f1:\n" - "f2: "; - auto pghs = vcpkg::parse_paragraphs(str); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(2), pghs[0].size()); - Assert::AreEqual("", pghs[0]["f1"].c_str()); - Assert::AreEqual("", pghs[0]["f2"].c_str()); - Assert::AreEqual(size_t(2), pghs[0].size()); - } - - TEST_METHOD(parse_paragraphs_multiline_fields) - { - const char* str = - "f1: simple\n" - " f1\r\n" - "f2:\r\n" - " f2\r\n" - " continue\r\n"; - auto pghs = vcpkg::parse_paragraphs(str); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual("simple\n f1", pghs[0]["f1"].c_str()); - Assert::AreEqual("\n f2\n continue", pghs[0]["f2"].c_str()); - } - - TEST_METHOD(parse_paragraphs_crlfs) - { - const char* str = - "f1: v1\r\n" - "f2: v2\r\n" - "\r\n" - "f3: v3\r\n" - "f4: v4"; - auto pghs = vcpkg::parse_paragraphs(str); - Assert::AreEqual(size_t(2), pghs.size()); - Assert::AreEqual(size_t(2), pghs[0].size()); - Assert::AreEqual("v1", pghs[0]["f1"].c_str()); - Assert::AreEqual("v2", pghs[0]["f2"].c_str()); - Assert::AreEqual(size_t(2), pghs[1].size()); - Assert::AreEqual("v3", pghs[1]["f3"].c_str()); - Assert::AreEqual("v4", pghs[1]["f4"].c_str()); - } - - TEST_METHOD(BinaryParagraph_serialize_min) - { - std::stringstream ss; - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "a"}, - {"Multi-Arch", "same"}, - }); - ss << pgh; - auto pghs = vcpkg::parse_paragraphs(ss.str()); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(4), pghs[0].size()); - Assert::AreEqual("zlib", pghs[0]["Package"].c_str()); - Assert::AreEqual("1.2.8", pghs[0]["Version"].c_str()); - Assert::AreEqual("a", pghs[0]["Architecture"].c_str()); - Assert::AreEqual("same", pghs[0]["Multi-Arch"].c_str()); - } - - TEST_METHOD(BinaryParagraph_serialize_max) - { - std::stringstream ss; - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "a"}, - {"Description", "first line\n second line"}, - {"Maintainer", "abc "}, - {"Depends", "dep"}, - {"Multi-Arch", "same"}, - }); - ss << pgh; - auto pghs = vcpkg::parse_paragraphs(ss.str()); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual(size_t(7), pghs[0].size()); - Assert::AreEqual("zlib", pghs[0]["Package"].c_str()); - Assert::AreEqual("1.2.8", pghs[0]["Version"].c_str()); - Assert::AreEqual("a", pghs[0]["Architecture"].c_str()); - Assert::AreEqual("same", pghs[0]["Multi-Arch"].c_str()); - Assert::AreEqual("first line\n second line", pghs[0]["Description"].c_str()); - Assert::AreEqual("dep", pghs[0]["Depends"].c_str()); - } - - TEST_METHOD(BinaryParagraph_serialize_multiple_deps) - { - std::stringstream ss; - vcpkg::BinaryParagraph pgh({ - {"Package", "zlib"}, - {"Version", "1.2.8"}, - {"Architecture", "a"}, - {"Multi-Arch", "same"}, - {"Depends", "a, b, c"}, - }); - ss << pgh; - auto pghs = vcpkg::parse_paragraphs(ss.str()); - Assert::AreEqual(size_t(1), pghs.size()); - Assert::AreEqual("a, b, c", pghs[0]["Depends"].c_str()); - } - - TEST_METHOD(package_spec_parse) - { - vcpkg::expected spec = vcpkg::package_spec::from_string("zlib", vcpkg::triplet::X86_WINDOWS); - Assert::AreEqual(vcpkg::package_spec_parse_result::SUCCESS, vcpkg::to_package_spec_parse_result(spec.error_code())); - Assert::AreEqual("zlib", spec.get()->name().c_str()); - Assert::AreEqual(vcpkg::triplet::X86_WINDOWS.canonical_name(), spec.get()->target_triplet().canonical_name()); - } - - TEST_METHOD(package_spec_parse_with_arch) - { - vcpkg::expected spec = vcpkg::package_spec::from_string("zlib:x64-uwp", vcpkg::triplet::X86_WINDOWS); - Assert::AreEqual(vcpkg::package_spec_parse_result::SUCCESS, vcpkg::to_package_spec_parse_result(spec.error_code())); - Assert::AreEqual("zlib", spec.get()->name().c_str()); - Assert::AreEqual(vcpkg::triplet::X64_UWP.canonical_name(), spec.get()->target_triplet().canonical_name()); - } - - TEST_METHOD(package_spec_parse_with_multiple_colon) - { - auto ec = vcpkg::package_spec::from_string("zlib:x86-uwp:", vcpkg::triplet::X86_WINDOWS).error_code(); - Assert::AreEqual(vcpkg::package_spec_parse_result::TOO_MANY_COLONS, vcpkg::to_package_spec_parse_result(ec)); - } - - TEST_METHOD(utf8_to_utf16) - { - auto str = vcpkg::Strings::utf8_to_utf16("abc"); - Assert::AreEqual(L"abc", str.c_str()); - } - - TEST_METHOD(utf8_to_utf16_with_whitespace) - { - auto str = vcpkg::Strings::utf8_to_utf16("abc -x86-windows"); - Assert::AreEqual(L"abc -x86-windows", str.c_str()); - } - }; - - TEST_CLASS(Metrics) - { - }; -} diff --git a/toolsrc/src/tests_dependencies.cpp b/toolsrc/src/tests_dependencies.cpp new file mode 100644 index 000000000..bce1cab0e --- /dev/null +++ b/toolsrc/src/tests_dependencies.cpp @@ -0,0 +1,39 @@ +#include "CppUnitTest.h" +#include "SourceParagraph.h" +#include "triplet.h" + +#pragma comment(lib,"version") +#pragma comment(lib,"winhttp") + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +using namespace vcpkg; + +namespace UnitTest1 +{ + TEST_CLASS(DependencyTests) + { + public: + TEST_METHOD(parse_depends_one) + { + auto v = expand_qualified_dependencies(parse_depends("libA [windows]")); + Assert::AreEqual(size_t(1), v.size()); + Assert::AreEqual("libA", v[0].name.c_str()); + Assert::AreEqual("windows", v[0].qualifier.c_str()); + } + + TEST_METHOD(filter_depends) + { + auto deps = expand_qualified_dependencies(parse_depends("libA [windows], libB, libC [uwp]")); + auto v = filter_dependencies(deps, triplet::X64_WINDOWS); + Assert::AreEqual(size_t(2), v.size()); + Assert::AreEqual("libA", v[0].c_str()); + Assert::AreEqual("libB", v[1].c_str()); + + auto v2 = filter_dependencies(deps, triplet::ARM_UWP); + Assert::AreEqual(size_t(2), v.size()); + Assert::AreEqual("libB", v2[0].c_str()); + Assert::AreEqual("libC", v2[1].c_str()); + } + }; +} diff --git a/toolsrc/src/tests_paragraph.cpp b/toolsrc/src/tests_paragraph.cpp new file mode 100644 index 000000000..b06359b90 --- /dev/null +++ b/toolsrc/src/tests_paragraph.cpp @@ -0,0 +1,367 @@ +#include "CppUnitTest.h" +#include "vcpkg.h" + +#pragma comment(lib,"version") +#pragma comment(lib,"winhttp") + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace Microsoft { namespace VisualStudio { namespace CppUnitTestFramework +{ + template <> + inline std::wstring ToString(const vcpkg::package_spec_parse_result& t) + { + return ToString(static_cast(t)); + } +}}} + +namespace UnitTest1 +{ + TEST_CLASS(ControlParsing) + { + public: + TEST_METHOD(SourceParagraph_Construct_Minimum) + { + vcpkg::SourceParagraph pgh({ + {"Source", "zlib"}, + {"Version", "1.2.8"} + }); + + 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()); + } + + TEST_METHOD(SourceParagraph_Construct_Maximum) + { + vcpkg::SourceParagraph pgh({ + {"Source", "s"}, + {"Version", "v"}, + {"Maintainer", "m"}, + {"Description", "d"}, + {"Build-Depends", "bd"} + }); + 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()); + } + + TEST_METHOD(SourceParagraph_Two_Depends) + { + vcpkg::SourceParagraph pgh({ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + {"Build-Depends", "z, openssl"} + }); + + 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()); + } + + TEST_METHOD(SourceParagraph_Three_Depends) + { + vcpkg::SourceParagraph pgh({ + {"Source", "zlib"}, + {"Version", "1.2.8"}, + {"Build-Depends", "z, openssl, xyz"} + }); + + 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()); + } + + TEST_METHOD(SourceParagraph_Construct_Qualified_Depends) + { + vcpkg::SourceParagraph pgh({ + { "Source", "zlib" }, + { "Version", "1.2.8" }, + { "Build-Depends", "libA [windows], libB [uwp]" } + }); + + 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()); + } + + + TEST_METHOD(BinaryParagraph_Construct_Minimum) + { + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + }); + + Assert::AreEqual("zlib", pgh.spec.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("x86-windows", pgh.spec.target_triplet().canonical_name().c_str()); + Assert::AreEqual(size_t(0), pgh.depends.size()); + } + + TEST_METHOD(BinaryParagraph_Construct_Maximum) + { + vcpkg::BinaryParagraph pgh({ + {"Package", "s"}, + {"Version", "v"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Maintainer", "m"}, + {"Description", "d"}, + {"Depends", "bd"} + }); + Assert::AreEqual("s", pgh.spec.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].c_str()); + } + + TEST_METHOD(BinaryParagraph_Three_Depends) + { + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Depends", "a, b, c"}, + }); + + Assert::AreEqual(size_t(3), pgh.depends.size()); + Assert::AreEqual("a", pgh.depends[0].c_str()); + Assert::AreEqual("b", pgh.depends[1].c_str()); + Assert::AreEqual("c", pgh.depends[2].c_str()); + } + + TEST_METHOD(parse_paragraphs_empty) + { + const char* str = ""; + auto pghs = vcpkg::parse_paragraphs(str); + Assert::IsTrue(pghs.empty()); + } + + TEST_METHOD(parse_paragraphs_one_field) + { + const char* str = "f1: v1"; + auto pghs = vcpkg::parse_paragraphs(str); + Assert::AreEqual(size_t(1), pghs.size()); + Assert::AreEqual(size_t(1), pghs[0].size()); + Assert::AreEqual("v1", pghs[0]["f1"].c_str()); + } + + TEST_METHOD(parse_paragraphs_one_pgh) + { + const char* str = + "f1: v1\n" + "f2: v2"; + auto pghs = vcpkg::parse_paragraphs(str); + Assert::AreEqual(size_t(1), pghs.size()); + Assert::AreEqual(size_t(2), pghs[0].size()); + Assert::AreEqual("v1", pghs[0]["f1"].c_str()); + Assert::AreEqual("v2", pghs[0]["f2"].c_str()); + } + + TEST_METHOD(parse_paragraphs_two_pgh) + { + const char* str = + "f1: v1\n" + "f2: v2\n" + "\n" + "f3: v3\n" + "f4: v4"; + auto pghs = vcpkg::parse_paragraphs(str); + Assert::AreEqual(size_t(2), pghs.size()); + Assert::AreEqual(size_t(2), pghs[0].size()); + Assert::AreEqual("v1", pghs[0]["f1"].c_str()); + Assert::AreEqual("v2", pghs[0]["f2"].c_str()); + Assert::AreEqual(size_t(2), pghs[1].size()); + Assert::AreEqual("v3", pghs[1]["f3"].c_str()); + Assert::AreEqual("v4", pghs[1]["f4"].c_str()); + } + + TEST_METHOD(parse_paragraphs_field_names) + { + const char* str = + "1:\n" + "f:\n" + "F:\n" + "0:\n" + "F-2:\n"; + auto pghs = vcpkg::parse_paragraphs(str); + Assert::AreEqual(size_t(1), pghs.size()); + Assert::AreEqual(size_t(5), pghs[0].size()); + } + + TEST_METHOD(parse_paragraphs_multiple_blank_lines) + { + const char* str = + "f1: v1\n" + "f2: v2\n" + "\n" + "\n" + "f3: v3\n" + "f4: v4"; + auto pghs = vcpkg::parse_paragraphs(str); + Assert::AreEqual(size_t(2), pghs.size()); + } + + TEST_METHOD(parse_paragraphs_empty_fields) + { + const char* str = + "f1:\n" + "f2: "; + auto pghs = vcpkg::parse_paragraphs(str); + Assert::AreEqual(size_t(1), pghs.size()); + Assert::AreEqual(size_t(2), pghs[0].size()); + Assert::AreEqual("", pghs[0]["f1"].c_str()); + Assert::AreEqual("", pghs[0]["f2"].c_str()); + Assert::AreEqual(size_t(2), pghs[0].size()); + } + + TEST_METHOD(parse_paragraphs_multiline_fields) + { + const char* str = + "f1: simple\n" + " f1\r\n" + "f2:\r\n" + " f2\r\n" + " continue\r\n"; + auto pghs = vcpkg::parse_paragraphs(str); + Assert::AreEqual(size_t(1), pghs.size()); + Assert::AreEqual("simple\n f1", pghs[0]["f1"].c_str()); + Assert::AreEqual("\n f2\n continue", pghs[0]["f2"].c_str()); + } + + TEST_METHOD(parse_paragraphs_crlfs) + { + const char* str = + "f1: v1\r\n" + "f2: v2\r\n" + "\r\n" + "f3: v3\r\n" + "f4: v4"; + auto pghs = vcpkg::parse_paragraphs(str); + Assert::AreEqual(size_t(2), pghs.size()); + Assert::AreEqual(size_t(2), pghs[0].size()); + Assert::AreEqual("v1", pghs[0]["f1"].c_str()); + Assert::AreEqual("v2", pghs[0]["f2"].c_str()); + Assert::AreEqual(size_t(2), pghs[1].size()); + Assert::AreEqual("v3", pghs[1]["f3"].c_str()); + Assert::AreEqual("v4", pghs[1]["f4"].c_str()); + } + + TEST_METHOD(BinaryParagraph_serialize_min) + { + std::stringstream ss; + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + }); + ss << pgh; + auto pghs = vcpkg::parse_paragraphs(ss.str()); + Assert::AreEqual(size_t(1), pghs.size()); + Assert::AreEqual(size_t(4), pghs[0].size()); + Assert::AreEqual("zlib", pghs[0]["Package"].c_str()); + Assert::AreEqual("1.2.8", pghs[0]["Version"].c_str()); + Assert::AreEqual("x86-windows", pghs[0]["Architecture"].c_str()); + Assert::AreEqual("same", pghs[0]["Multi-Arch"].c_str()); + } + + TEST_METHOD(BinaryParagraph_serialize_max) + { + std::stringstream ss; + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Description", "first line\n second line"}, + {"Maintainer", "abc "}, + {"Depends", "dep"}, + {"Multi-Arch", "same"}, + }); + ss << pgh; + auto pghs = vcpkg::parse_paragraphs(ss.str()); + Assert::AreEqual(size_t(1), pghs.size()); + Assert::AreEqual(size_t(7), pghs[0].size()); + Assert::AreEqual("zlib", pghs[0]["Package"].c_str()); + Assert::AreEqual("1.2.8", pghs[0]["Version"].c_str()); + Assert::AreEqual("x86-windows", pghs[0]["Architecture"].c_str()); + Assert::AreEqual("same", pghs[0]["Multi-Arch"].c_str()); + Assert::AreEqual("first line\n second line", pghs[0]["Description"].c_str()); + Assert::AreEqual("dep", pghs[0]["Depends"].c_str()); + } + + TEST_METHOD(BinaryParagraph_serialize_multiple_deps) + { + std::stringstream ss; + vcpkg::BinaryParagraph pgh({ + {"Package", "zlib"}, + {"Version", "1.2.8"}, + {"Architecture", "x86-windows"}, + {"Multi-Arch", "same"}, + {"Depends", "a, b, c"}, + }); + ss << pgh; + auto pghs = vcpkg::parse_paragraphs(ss.str()); + Assert::AreEqual(size_t(1), pghs.size()); + Assert::AreEqual("a, b, c", pghs[0]["Depends"].c_str()); + } + + TEST_METHOD(package_spec_parse) + { + vcpkg::expected spec = vcpkg::package_spec::from_string("zlib", vcpkg::triplet::X86_WINDOWS); + Assert::AreEqual(vcpkg::package_spec_parse_result::SUCCESS, vcpkg::to_package_spec_parse_result(spec.error_code())); + Assert::AreEqual("zlib", spec.get()->name().c_str()); + Assert::AreEqual(vcpkg::triplet::X86_WINDOWS.canonical_name(), spec.get()->target_triplet().canonical_name()); + } + + TEST_METHOD(package_spec_parse_with_arch) + { + vcpkg::expected spec = vcpkg::package_spec::from_string("zlib:x64-uwp", vcpkg::triplet::X86_WINDOWS); + Assert::AreEqual(vcpkg::package_spec_parse_result::SUCCESS, vcpkg::to_package_spec_parse_result(spec.error_code())); + Assert::AreEqual("zlib", spec.get()->name().c_str()); + Assert::AreEqual(vcpkg::triplet::X64_UWP.canonical_name(), spec.get()->target_triplet().canonical_name()); + } + + TEST_METHOD(package_spec_parse_with_multiple_colon) + { + auto ec = vcpkg::package_spec::from_string("zlib:x86-uwp:", vcpkg::triplet::X86_WINDOWS).error_code(); + Assert::AreEqual(vcpkg::package_spec_parse_result::TOO_MANY_COLONS, vcpkg::to_package_spec_parse_result(ec)); + } + + TEST_METHOD(utf8_to_utf16) + { + auto str = vcpkg::Strings::utf8_to_utf16("abc"); + Assert::AreEqual(L"abc", str.c_str()); + } + + TEST_METHOD(utf8_to_utf16_with_whitespace) + { + auto str = vcpkg::Strings::utf8_to_utf16("abc -x86-windows"); + Assert::AreEqual(L"abc -x86-windows", str.c_str()); + } + }; + + TEST_CLASS(Metrics) + { + }; +} diff --git a/toolsrc/src/vcpkg_Checks.cpp b/toolsrc/src/vcpkg_Checks.cpp index db6c03480..453ba81fd 100644 --- a/toolsrc/src/vcpkg_Checks.cpp +++ b/toolsrc/src/vcpkg_Checks.cpp @@ -8,6 +8,9 @@ namespace vcpkg {namespace Checks void unreachable() { System::println(System::color::error, "Error: Unreachable code was reached"); +#ifndef NDEBUG + std::abort(); +#endif exit(EXIT_FAILURE); } diff --git a/toolsrc/src/vcpkg_Dependencies.cpp b/toolsrc/src/vcpkg_Dependencies.cpp index 54b37cd11..0e45b28dd 100644 --- a/toolsrc/src/vcpkg_Dependencies.cpp +++ b/toolsrc/src/vcpkg_Dependencies.cpp @@ -57,11 +57,9 @@ namespace vcpkg { namespace Dependencies return build_dependency_graph(paths, specs, status_db).find_topological_sort(); } - std::unordered_set find_unmet_dependencies(const vcpkg_paths& paths, const package_spec& spec, const StatusParagraphs& status_db) + std::unordered_set find_unmet_dependencies(const vcpkg_paths& paths, const std::vector& specs, const StatusParagraphs& status_db) { - const Graphs::Graph dependency_graph = build_dependency_graph(paths, {spec}, status_db); - std::unordered_set key_set = Maps::extract_key_set(dependency_graph.adjacency_list()); - key_set.erase(spec); - return key_set; + const Graphs::Graph dependency_graph = build_dependency_graph(paths, specs, status_db); + return Maps::extract_key_set(dependency_graph.adjacency_list()); } }} diff --git a/toolsrc/src/vcpkglib_helpers.cpp b/toolsrc/src/vcpkglib_helpers.cpp index 3d14d4b06..61dc4f4cc 100644 --- a/toolsrc/src/vcpkglib_helpers.cpp +++ b/toolsrc/src/vcpkglib_helpers.cpp @@ -45,37 +45,4 @@ namespace vcpkg {namespace details return value; } - std::vector parse_depends(const std::string& depends_string) - { - if (depends_string.empty()) - { - return {}; - } - - std::vector out; - - size_t cur = 0; - do - { - auto pos = depends_string.find(',', cur); - if (pos == std::string::npos) - { - out.push_back(depends_string.substr(cur)); - break; - } - out.push_back(depends_string.substr(cur, pos - cur)); - - // skip comma and space - ++pos; - if (depends_string[pos] == ' ') - { - ++pos; - } - - cur = pos; - } - while (cur != std::string::npos); - - return out; - } }} diff --git a/toolsrc/vcpkgtest/vcpkgtest.vcxproj b/toolsrc/vcpkgtest/vcpkgtest.vcxproj index 3d9503374..d14f86745 100644 --- a/toolsrc/vcpkgtest/vcpkgtest.vcxproj +++ b/toolsrc/vcpkgtest/vcpkgtest.vcxproj @@ -19,7 +19,8 @@ - + + @@ -116,7 +117,7 @@ NotUsing Level3 Disabled - ..\include;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories) + ..\include;$(VCInstallDir)UnitTest\include;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\UnitTest\include;%(AdditionalIncludeDirectories) _DEBUG;%(PreprocessorDefinitions) true diff --git a/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters b/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters index 9db7e6ef8..bbbc6bd40 100644 --- a/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters +++ b/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters @@ -15,7 +15,10 @@ - + + Source Files + + Source Files -- cgit v1.2.3