From 8bff63850c34125912d5f2a26d12d3d191880bc6 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 20 Aug 2020 13:00:00 -0700 Subject: [PATCH 01/18] [vcpkg cmake] don't overflow command line length for format --- toolsrc/CMakeLists.txt | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/toolsrc/CMakeLists.txt b/toolsrc/CMakeLists.txt index 8b525c248a3fbe..a35d8a7c242bd7 100644 --- a/toolsrc/CMakeLists.txt +++ b/toolsrc/CMakeLists.txt @@ -154,19 +154,20 @@ endif() find_program(CLANG_FORMAT clang-format) if(CLANG_FORMAT) - add_custom_target(format COMMAND ${CLANG_FORMAT} -i -verbose - ${CMAKE_CURRENT_SOURCE_DIR}/src/pch.cpp - ${VCPKGLIB_BASE_SOURCES} - ${VCPKGLIB_SOURCES} - ${CMAKE_CURRENT_SOURCE_DIR}/include/pch.h - ${VCPKGLIB_BASE_INCLUDES} - ${VCPKGLIB_INCLUDES} - - ${VCPKG_SOURCES} - ${VCPKGMETRICSUPLOADER_SOURCES} - - ${VCPKG_TEST_SOURCES} - ${VCPKG_TEST_INCLUDES} - - ${VCPKG_FUZZ_SOURCES}) + # doing all of these formats in one line has a tendency to overflow the command line length + add_custom_target(format + COMMAND ${CLANG_FORMAT} -i -verbose ${CMAKE_CURRENT_SOURCE_DIR}/src/pch.cpp + COMMAND ${CLANG_FORMAT} -i -verbose ${VCPKGLIB_BASE_SOURCES} + COMMAND ${CLANG_FORMAT} -i -verbose ${VCPKGLIB_SOURCES} + COMMAND ${CLANG_FORMAT} -i -verbose ${CMAKE_CURRENT_SOURCE_DIR}/include/pch.h + COMMAND ${CLANG_FORMAT} -i -verbose ${VCPKGLIB_BASE_INCLUDES} + COMMAND ${CLANG_FORMAT} -i -verbose ${VCPKGLIB_INCLUDES} + + COMMAND ${CLANG_FORMAT} -i -verbose ${VCPKG_SOURCES} + COMMAND ${CLANG_FORMAT} -i -verbose ${VCPKGMETRICSUPLOADER_SOURCES} + + COMMAND ${CLANG_FORMAT} -i -verbose ${VCPKG_TEST_SOURCES} + COMMAND ${CLANG_FORMAT} -i -verbose ${VCPKG_TEST_INCLUDES} + + COMMAND ${CLANG_FORMAT} -i -verbose ${VCPKG_FUZZ_SOURCES}) endif() From 7b518277a47411354c5c5464248ebb2b14e6e86a Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 12 Aug 2020 13:26:24 -0700 Subject: [PATCH 02/18] [vcpkg] Enable Optional -> Optional conversion Also move common_projection() to Util:: to be with its friends --- toolsrc/include/vcpkg/base/optional.h | 49 +++++++++++++-------------- toolsrc/include/vcpkg/base/util.h | 29 +++++++++++++++- toolsrc/src/vcpkg-test/optional.cpp | 33 +++++++++++++++++- 3 files changed, 84 insertions(+), 27 deletions(-) diff --git a/toolsrc/include/vcpkg/base/optional.h b/toolsrc/include/vcpkg/base/optional.h index 091cd498ed9e3f..4279645b525511 100644 --- a/toolsrc/include/vcpkg/base/optional.h +++ b/toolsrc/include/vcpkg/base/optional.h @@ -15,6 +15,9 @@ namespace vcpkg const static constexpr NullOpt nullopt{0}; + template + struct Optional; + namespace details { template::value> @@ -162,11 +165,12 @@ namespace vcpkg }; }; - template - struct OptionalStorage + template + struct OptionalStorage { constexpr OptionalStorage() noexcept : m_t(nullptr) { } constexpr OptionalStorage(T& t) : m_t(&t) { } + constexpr OptionalStorage(Optional& t) : m_t(t.get()) { } constexpr bool has_value() const { return m_t != nullptr; } @@ -176,6 +180,24 @@ namespace vcpkg T* m_t; }; + template + struct OptionalStorage + { + constexpr OptionalStorage() noexcept : m_t(nullptr) { } + constexpr OptionalStorage(const T& t) : m_t(&t) { } + constexpr OptionalStorage(const Optional& t) : m_t(t.get()) { } + constexpr OptionalStorage(const Optional& t) : m_t(t.get()) { } + constexpr OptionalStorage(Optional&& t) = delete; + constexpr OptionalStorage(Optional&& t) = delete; + + constexpr bool has_value() const { return m_t != nullptr; } + + const T& value() const { return *this->m_t; } + + private: + const T* m_t; + }; + // Note: implemented in checks.cpp to cut the header dependency void exit_if_null(bool b, const LineInfo& line_info); } @@ -325,27 +347,4 @@ namespace vcpkg if (auto p = o.get()) return t != *p; return true; } - - template - auto common_projection(const Container& input, Projection proj) - -> Optional> - { - const auto last = input.end(); - auto first = input.begin(); - if (first == last) - { - return nullopt; - } - - const auto& prototype = proj(*first); - while (++first != last) - { - if (prototype != proj(*first)) - { - return nullopt; - } - } - - return prototype; - } } diff --git a/toolsrc/include/vcpkg/base/util.h b/toolsrc/include/vcpkg/base/util.h index 11807b249dfb5d..0453ac20a64b01 100644 --- a/toolsrc/include/vcpkg/base/util.h +++ b/toolsrc/include/vcpkg/base/util.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -63,7 +65,10 @@ namespace vcpkg::Util } template - using FmapOut = std::remove_reference_t()(*std::declval().begin()))>; + using FmapRefOut = decltype(std::declval()(*std::declval().begin())); + + template + using FmapOut = std::decay_t>; template> std::vector fmap(Range&& xs, Func&& f) @@ -77,6 +82,28 @@ namespace vcpkg::Util return ret; } + template> + Optional common_projection(Range&& input, Proj&& proj) + { + const auto last = input.end(); + auto first = input.begin(); + if (first == last) + { + return nullopt; + } + + Out prototype = proj(*first); + while (++first != last) + { + if (prototype != proj(*first)) + { + return nullopt; + } + } + + return prototype; + } + template using FmapFlattenOut = std::decay_t()(*begin(std::declval()))))>; diff --git a/toolsrc/src/vcpkg-test/optional.cpp b/toolsrc/src/vcpkg-test/optional.cpp index 929410eb305178..f3c61387fd894b 100644 --- a/toolsrc/src/vcpkg-test/optional.cpp +++ b/toolsrc/src/vcpkg-test/optional.cpp @@ -1,6 +1,7 @@ #include #include +#include #include @@ -27,9 +28,39 @@ TEST_CASE ("equal", "[optional]") CHECK(Optional{42} == Optional{42}); } +TEST_CASE ("ref conversion", "[optional]") +{ + using vcpkg::Optional; + + Optional i_empty; + Optional i_1 = 1; + const Optional ci_1 = 1; + + Optional ref_empty = i_empty; + Optional cref_empty = i_empty; + + Optional ref_1 = i_1; + Optional cref_1 = ci_1; + + REQUIRE(ref_empty.has_value() == false); + REQUIRE(cref_empty.has_value() == false); + + REQUIRE(ref_1.get() == i_1.get()); + REQUIRE(cref_1.get() == ci_1.get()); + + ref_empty = i_1; + cref_empty = ci_1; + REQUIRE(ref_empty.get() == i_1.get()); + REQUIRE(cref_empty.get() == ci_1.get()); + + const int x = 5; + cref_1 = x; + REQUIRE(cref_1.get() == &x); +} + TEST_CASE ("common_projection", "[optional]") { - using vcpkg::common_projection; + using vcpkg::Util::common_projection; std::vector input; CHECK(!common_projection(input, identity_projection{}).has_value()); input.push_back(42); From 7ea82b39e38a481b05272aa1ad3ad03b0e903cf2 Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Wed, 12 Aug 2020 13:29:41 -0700 Subject: [PATCH 03/18] [vcpkg] Load, parse, and extract configuration from manifests in VcpkgPaths This PR adds support for $.configuration in manifest files, which can either be an immediate object or the string "file" (which will search recursively up for a vcpkg-configuration.json). --- toolsrc/include/vcpkg/base/files.h | 2 +- toolsrc/include/vcpkg/base/json.h | 1 + toolsrc/include/vcpkg/paragraphs.h | 5 -- toolsrc/include/vcpkg/vcpkgpaths.h | 12 +++- toolsrc/src/vcpkg/base/files.cpp | 3 +- toolsrc/src/vcpkg/base/json.cpp | 20 ++++++ toolsrc/src/vcpkg/install.cpp | 15 ++--- toolsrc/src/vcpkg/paragraphs.cpp | 2 +- toolsrc/src/vcpkg/sourceparagraph.cpp | 2 + toolsrc/src/vcpkg/vcpkgpaths.cpp | 93 ++++++++++++++++++++++++++- 10 files changed, 133 insertions(+), 22 deletions(-) diff --git a/toolsrc/include/vcpkg/base/files.h b/toolsrc/include/vcpkg/base/files.h index e0a5550240dd25..08bbe790651463 100644 --- a/toolsrc/include/vcpkg/base/files.h +++ b/toolsrc/include/vcpkg/base/files.h @@ -157,7 +157,7 @@ namespace vcpkg::Files /// Read text lines from a file /// Lines will have up to one trailing carriage-return character stripped (CRLF) virtual Expected> read_lines(const fs::path& file_path) const = 0; - virtual fs::path find_file_recursively_up(const fs::path& starting_dir, const std::string& filename) const = 0; + virtual fs::path find_file_recursively_up(const fs::path& starting_dir, const fs::path& filename) const = 0; virtual std::vector get_files_recursive(const fs::path& dir) const = 0; virtual std::vector get_files_non_recursive(const fs::path& dir) const = 0; void write_lines(const fs::path& file_path, const std::vector& lines, LineInfo linfo); diff --git a/toolsrc/include/vcpkg/base/json.h b/toolsrc/include/vcpkg/base/json.h index a4ad44ebd07259..02d707c0ab623c 100644 --- a/toolsrc/include/vcpkg/base/json.h +++ b/toolsrc/include/vcpkg/base/json.h @@ -424,6 +424,7 @@ namespace vcpkg::Json const Files::Filesystem&, const fs::path&, std::error_code& ec) noexcept; ExpectedT, std::unique_ptr> parse( StringView text, const fs::path& filepath = {}) noexcept; + std::pair parse_file(vcpkg::LineInfo linfo, const Files::Filesystem&, const fs::path&) noexcept; std::string stringify(const Value&, JsonStyle style); std::string stringify(const Object&, JsonStyle style); diff --git a/toolsrc/include/vcpkg/paragraphs.h b/toolsrc/include/vcpkg/paragraphs.h index 25d037591bf062..7f6453c8f2af1e 100644 --- a/toolsrc/include/vcpkg/paragraphs.h +++ b/toolsrc/include/vcpkg/paragraphs.h @@ -17,11 +17,6 @@ namespace vcpkg::Paragraphs bool is_port_directory(const Files::Filesystem& fs, const fs::path& path); - Parse::ParseExpected try_load_manifest(const Files::Filesystem& fs, - const std::string& port_name, - const fs::path& path_to_manifest, - std::error_code& ec); - Parse::ParseExpected try_load_port(const Files::Filesystem& fs, const fs::path& path); ExpectedS try_load_cached_package(const VcpkgPaths& paths, const PackageSpec& spec); diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h index 2262543d9f4ef5..1e00fe017fd2a1 100644 --- a/toolsrc/include/vcpkg/vcpkgpaths.h +++ b/toolsrc/include/vcpkg/vcpkgpaths.h @@ -44,6 +44,12 @@ namespace vcpkg struct VcpkgPathsImpl; } + namespace Json + { + struct Object; + struct JsonStyle; + } + struct BinaryParagraph; struct VcpkgCmdArguments; struct PackageSpec; @@ -102,6 +108,10 @@ namespace vcpkg const fs::path& get_tool_exe(const std::string& tool) const; const std::string& get_tool_version(const std::string& tool) const; + Optional get_manifest() const; + Optional get_manifest_style() const; + Optional get_manifest_config() const; + /// Retrieve a toolset matching a VS version /// /// Valid version strings are "v120", "v140", "v141", and "". Empty string gets the latest. @@ -112,7 +122,7 @@ namespace vcpkg const System::Environment& get_action_env(const Build::AbiInfo& abi_info) const; const std::string& get_triplet_info(const Build::AbiInfo& abi_info) const; - bool manifest_mode_enabled() const { return !manifest_root_dir.empty(); } + bool manifest_mode_enabled() const { return get_manifest().has_value(); } void track_feature_flag_metrics() const; diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 15a37a8b4d80af..482d9aa3ef1e68 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -498,8 +498,7 @@ namespace vcpkg::Files return output; } - virtual fs::path find_file_recursively_up(const fs::path& starting_dir, - const std::string& filename) const override + virtual fs::path find_file_recursively_up(const fs::path& starting_dir, const fs::path& filename) const override { fs::path current_dir = starting_dir; if (exists(VCPKG_LINE_INFO, current_dir / filename)) diff --git a/toolsrc/src/vcpkg/base/json.cpp b/toolsrc/src/vcpkg/base/json.cpp index 62f50f9d03b042..f34f2927123342 100644 --- a/toolsrc/src/vcpkg/base/json.cpp +++ b/toolsrc/src/vcpkg/base/json.cpp @@ -1002,6 +1002,26 @@ namespace vcpkg::Json } } + std::pair parse_file(vcpkg::LineInfo linfo, + const Files::Filesystem& fs, + const fs::path& path) noexcept + { + std::error_code ec; + auto ret = parse_file(fs, path, ec); + if (ec) + { + System::print2(System::Color::error, "Failed to read ", path.u8string(), ": ", ec.message(), "\n"); + Checks::exit_fail(linfo); + } + else if (!ret) + { + System::print2(System::Color::error, "Failed to parse ", path.u8string(), ":\n"); + System::print2(ret.error()->format()); + Checks::exit_fail(linfo); + } + return ret.value_or_exit(linfo); + } + ExpectedT, std::unique_ptr> parse(StringView json, const fs::path& filepath) noexcept { diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 08c160f89cb0ba..6a66f4a89991bd 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -781,7 +781,7 @@ namespace vcpkg::Install auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths); auto& var_provider = *var_provider_storage; - if (paths.manifest_mode_enabled()) + if (auto manifest = paths.get_manifest().get()) { Optional pkgsconfig; auto it_pkgsconfig = options.settings.find(OPTION_WRITE_PACKAGES_CONFIG); @@ -790,18 +790,11 @@ namespace vcpkg::Install pkgsconfig = fs::u8path(it_pkgsconfig->second); } - std::error_code ec; - auto manifest_path = paths.manifest_root_dir / fs::u8path("vcpkg.json"); - auto maybe_manifest_scf = Paragraphs::try_load_manifest(fs, "manifest", manifest_path, ec); - if (ec) - { - Checks::exit_with_message( - VCPKG_LINE_INFO, "Failed to read manifest %s: %s", fs::u8string(manifest_path), ec.message()); - } - else if (!maybe_manifest_scf) + auto maybe_manifest_scf = SourceControlFile::parse_manifest_file("manifest", *manifest); + if (!maybe_manifest_scf) { print_error_message(maybe_manifest_scf.error()); - Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to read manifest %s.", fs::u8string(manifest_path)); + Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to read manifest %s/vcpkg.json.", fs::u8string(paths.manifest_root_dir)); } auto& manifest_scf = *maybe_manifest_scf.value_or_exit(VCPKG_LINE_INFO); diff --git a/toolsrc/src/vcpkg/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp index 37f919b6303b03..01af69a3e94861 100644 --- a/toolsrc/src/vcpkg/paragraphs.cpp +++ b/toolsrc/src/vcpkg/paragraphs.cpp @@ -259,7 +259,7 @@ namespace vcpkg::Paragraphs return fs.exists(path / fs::u8path("CONTROL")) || fs.exists(path / fs::u8path("vcpkg.json")); } - ParseExpected try_load_manifest(const Files::Filesystem& fs, + static ParseExpected try_load_manifest(const Files::Filesystem& fs, const std::string& port_name, const fs::path& path_to_manifest, std::error_code& ec) diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index ed26f4497e8957..ada57d7ef97fd2 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -96,6 +96,7 @@ namespace vcpkg constexpr static StringLiteral FEATURES = "features"; constexpr static StringLiteral DEFAULT_FEATURES = "default-features"; constexpr static StringLiteral SUPPORTS = "supports"; + constexpr static StringLiteral CONFIGURATION = "configuration"; } static Span get_list_of_valid_fields() @@ -133,6 +134,7 @@ namespace vcpkg ManifestFields::FEATURES, ManifestFields::DEFAULT_FEATURES, ManifestFields::SUPPORTS, + ManifestFields::CONFIGURATION, }; return valid_fields; diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 660c180e2c85d3..30da3736d4b530 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +82,75 @@ namespace namespace vcpkg { + static std::pair>, Optional> load_manifest_and_config( + const Files::Filesystem& fs, const fs::path& manifest_dir) + { + std::error_code ec; + auto manifest_path = manifest_dir / fs::u8path("vcpkg.json"); + auto manifest_opt = Json::parse_file(fs, manifest_path, ec); + if (ec) + { + Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to load manifest from directory %s: %s", manifest_dir.u8string(), ec.message()); + } + + if (!manifest_opt.has_value()) + { + Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to parse manifest at %s: %s", manifest_path.u8string(), manifest_opt.error()->format()); + } + auto manifest_value = std::move(manifest_opt).value_or_exit(VCPKG_LINE_INFO); + + if (!manifest_value.first.is_object()) + { + System::print2(System::Color::error, + "Failed to parse manifest at ", + manifest_path.u8string(), + ": Manifest files must have a top-level object\n"); + Checks::exit_fail(VCPKG_LINE_INFO); + } + std::pair manifest = {std::move(manifest_value.first.object()), std::move(manifest_value.second)}; + + if (auto p_manifest_config = manifest.first.get("configuration")) + { + if (p_manifest_config->is_object()) + { + return {std::move(manifest), std::move(p_manifest_config->object())}; + } + else if (p_manifest_config->is_string()) + { + auto config_name = fs::u8path("vcpkg-configuration.json"); + auto config_relative_path = p_manifest_config->string(); + auto config_path = manifest_dir / fs::u8path(config_relative_path.begin(), config_relative_path.end()) / config_name; + if (!fs.exists(config_path)) + { + System::printf(System::Color::error, + "Failed to find configuration file at %s\n", + config_path.u8string()); + Checks::exit_fail(VCPKG_LINE_INFO); + } + auto parsed_config = Json::parse_file(VCPKG_LINE_INFO, fs, config_path); + if (!parsed_config.first.is_object()) + { + System::print2(System::Color::error, + "Failed to parse ", + config_path.u8string(), + ": configuration files must have a top-level object\n"); + Checks::exit_fail(VCPKG_LINE_INFO); + } + return {std::move(manifest), std::move(parsed_config.first.object())}; + } + else + { + System::print2( + System::Color::error, + "Failed to parse manifest at ", + manifest_path.u8string(), + ": Manifest configuration ($.configuration) must be a string or an object.\n"); + Checks::exit_fail(VCPKG_LINE_INFO); + } + } + return {std::move(manifest), nullopt}; + } + namespace details { struct VcpkgPathsImpl @@ -104,6 +174,9 @@ namespace vcpkg Build::EnvCache m_env_cache; fs::SystemHandle file_lock_handle; + + Optional> m_manifest_doc; + Optional m_manifest_config; }; } @@ -136,7 +209,7 @@ namespace vcpkg } else { - manifest_root_dir = filesystem.find_file_recursively_up(original_cwd, "vcpkg.json"); + manifest_root_dir = filesystem.find_file_recursively_up(original_cwd, fs::u8path("vcpkg.json")); } uppercase_win32_drive_letter(manifest_root_dir); @@ -162,6 +235,10 @@ namespace vcpkg System::printf(System::Color::error, " %s\n", ec.message()); Checks::exit_fail(VCPKG_LINE_INFO); } + + auto manifest_and_config = load_manifest_and_config(filesystem, manifest_root_dir); + m_pimpl->m_manifest_doc = std::move(manifest_and_config.first); + m_pimpl->m_manifest_config = std::move(manifest_and_config.second); } else { @@ -336,6 +413,20 @@ If you wish to silence this error and use classic mode, you can: return m_pimpl->m_tool_cache->get_tool_version(*this, tool); } + Optional VcpkgPaths::get_manifest() const + { + if (auto p = m_pimpl->m_manifest_doc.get()) + { + return p->first; + } + else + { + return nullopt; + } + } + + Optional VcpkgPaths::get_manifest_config() const { return m_pimpl->m_manifest_config; } + const Toolset& VcpkgPaths::get_toolset(const Build::PreBuildInfo& prebuildinfo) const { if (!prebuildinfo.using_vcvars()) From 764a39d00eedde0cee1b482232230f8b7da2217c Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Tue, 18 Aug 2020 11:44:28 -0700 Subject: [PATCH 04/18] [vcpkg] virtualize VisitorCrtpBase This allows us to get better compiler errors when playing around with json parsing Additionally, move some stuff over to json.h, and some minor json reading changes Also rename *Field -> *Deserializer Additionally, move the valid fields check into the Reader --- toolsrc/include/vcpkg/base/json.h | 314 ++++++++++-- toolsrc/src/vcpkg/base/json.cpp | 29 ++ toolsrc/src/vcpkg/sourceparagraph.cpp | 674 +++++++++----------------- 3 files changed, 543 insertions(+), 474 deletions(-) diff --git a/toolsrc/include/vcpkg/base/json.h b/toolsrc/include/vcpkg/base/json.h index 02d707c0ab623c..83e377d4a1c8d0 100644 --- a/toolsrc/include/vcpkg/base/json.h +++ b/toolsrc/include/vcpkg/base/json.h @@ -289,6 +289,41 @@ namespace vcpkg::Json underlying_t underlying_; }; + struct Reader; + + template + struct IDeserializer + { + using type = Type; + virtual StringView type_name() const = 0; + + virtual Span valid_fields() const { return {}; } + + virtual Optional visit_null(Reader&, StringView) { return nullopt; } + virtual Optional visit_boolean(Reader&, StringView, bool) { return nullopt; } + virtual Optional visit_integer(Reader& r, StringView field_name, int64_t i) + { + return this->visit_number(r, field_name, static_cast(i)); + } + virtual Optional visit_number(Reader&, StringView, double) { return nullopt; } + virtual Optional visit_string(Reader&, StringView, StringView) { return nullopt; } + virtual Optional visit_array(Reader&, StringView, const Array&) + { + return nullopt; + } + virtual Optional visit_object(Reader&, StringView, const Object&) + { + return nullopt; + } + protected: + IDeserializer() = default; + IDeserializer(const IDeserializer&) = default; + IDeserializer& operator=(const IDeserializer&) = default; + IDeserializer(IDeserializer&&) = default; + IDeserializer& operator=(IDeserializer&&) = default; + virtual ~IDeserializer() = default; + }; + struct ReaderError { virtual void add_missing_field(std::string&& type, std::string&& key) = 0; @@ -308,30 +343,31 @@ namespace vcpkg::Json private: ReaderError* err; - template - using VisitorType = typename std::remove_reference_t::type; - - template - Optional> internal_visit(const Value& value, StringView key, Visitor& visitor) + template + Optional internal_visit(const Value& value, StringView key, IDeserializer& visitor) { switch (value.kind()) { - using VK = Json::ValueKind; - case VK::Null: return visitor.visit_null(*this, key); - case VK::Boolean: return visitor.visit_boolean(*this, key, value.boolean()); - case VK::Integer: return visitor.visit_integer(*this, key, value.integer()); - case VK::Number: return visitor.visit_number(*this, key, value.number()); - case VK::String: return visitor.visit_string(*this, key, value.string()); - case VK::Array: return visitor.visit_array(*this, key, value.array()); - case VK::Object: return visitor.visit_object(*this, key, value.object()); + case ValueKind::Null: return visitor.visit_null(*this, key); + case ValueKind::Boolean: return visitor.visit_boolean(*this, key, value.boolean()); + case ValueKind::Integer: return visitor.visit_integer(*this, key, value.integer()); + case ValueKind::Number: return visitor.visit_number(*this, key, value.number()); + case ValueKind::String: return visitor.visit_string(*this, key, value.string()); + case ValueKind::Array: return visitor.visit_array(*this, key, value.array()); + case ValueKind::Object: + { + const auto& obj = value.object(); + check_for_unexpected_fields(obj, visitor.valid_fields(), visitor.type_name()); + return visitor.visit_object(*this, key, value.object()); + } } vcpkg::Checks::exit_fail(VCPKG_LINE_INFO); } // returns whether the field was found, not whether it was valid - template - bool internal_field(const Object& obj, StringView key, VisitorType& place, Visitor& visitor) + template + bool internal_field(const Object& obj, StringView key, Type& place, IDeserializer& visitor) { auto value = obj.get(key); if (!value) @@ -339,7 +375,7 @@ namespace vcpkg::Json return false; } - Optional> opt = internal_visit(*value, key, visitor); + Optional opt = internal_visit(*value, key, visitor); if (auto val = opt.get()) { @@ -353,27 +389,113 @@ namespace vcpkg::Json return true; } + static std::vector invalid_json_fields(const Json::Object& obj, + Span known_fields) noexcept + { + const auto field_is_unknown = [known_fields](StringView sv) { + // allow directives + if (sv.size() != 0 && *sv.begin() == '$') + { + return false; + } + return std::find(known_fields.begin(), known_fields.end(), sv) == known_fields.end(); + }; + + std::vector res; + for (const auto& kv : obj) + { + if (field_is_unknown(kv.first)) + { + res.push_back(kv.first.to_string()); + } + } + + return res; + } + + // checks that an object doesn't contain any fields which both: + // * don't start with a `$` + // * are not in `valid_fields` + // if known_fields.empty(), then it's treated as if all field names are valid + void check_for_unexpected_fields(const Object& obj, Span valid_fields, StringView type_name) + { + if (valid_fields.size() == 0) + { + return; + } + + auto extra_fields = invalid_json_fields(obj, valid_fields); + if (!extra_fields.empty()) + { + error().add_extra_fields(type_name.to_string(), std::move(extra_fields)); + } + } + public: - template + template void required_object_field( - StringView type, const Object& obj, StringView key, VisitorType& place, Visitor&& visitor) + StringView type, const Object& obj, StringView key, Type& place, IDeserializer& visitor) { if (!internal_field(obj, key, place, visitor)) { err->add_missing_field(type.to_string(), key.to_string()); } } + template + void required_object_field( + StringView type, const Object& obj, StringView key, Type& place, IDeserializer&& visitor) + { + required_object_field(type, obj, key, place, visitor); + } - template - void optional_object_field(const Object& obj, StringView key, VisitorType& place, Visitor&& visitor) + template + void optional_object_field(const Object& obj, StringView key, Type& place, IDeserializer& visitor) { internal_field(obj, key, place, visitor); } + template + void optional_object_field(const Object& obj, StringView key, Type& place, IDeserializer&& visitor) + { + optional_object_field(obj, key, place, visitor); + } + + template + Optional visit_value(const Value& value, StringView key, IDeserializer& visitor) + { + return internal_visit(value, key, visitor); + } + template + Optional visit_value(const Value& value, StringView key, IDeserializer&& visitor) + { + return visit_value(value, key, visitor); + } + + template + Optional visit_value(const Array& value, StringView key, IDeserializer& visitor) + { + return visitor.visit_array(*this, key, value); + } + template + Optional visit_value(const Array& value, StringView key, IDeserializer&& visitor) + { + return visit_value(value, key, visitor); + } + + template + Optional visit_value(const Object& value, StringView key, IDeserializer& visitor) + { + return visitor.visit_object(*this, key, value); + } + template + Optional visit_value(const Object& value, StringView key, IDeserializer&& visitor) + { + return visit_value(value, key, visitor); + } - template - Optional>> array_elements(const Array& arr, StringView key, Visitor&& visitor) + template + Optional> array_elements(const Array& arr, StringView key, IDeserializer& visitor) { - std::vector> result; + std::vector result; for (const auto& el : arr) { auto opt = internal_visit(el, key, visitor); @@ -388,36 +510,144 @@ namespace vcpkg::Json } return std::move(result); } + template + Optional> array_elements(const Array& arr, StringView key, IDeserializer&& visitor) + { + return array_elements(arr, key, visitor); + } + }; + + struct StringDeserializer final : IDeserializer + { + virtual StringView type_name() const override { return type_name_; } + virtual Optional visit_string(Reader&, StringView, StringView sv) override { return sv.to_string(); } + + explicit StringDeserializer(StringView type_name_) : type_name_(type_name_) { } + private: + StringView type_name_; + }; + + struct NaturalNumberDeserializer final : IDeserializer + { + virtual StringView type_name() const override { return "a natural number"; } + + virtual Optional visit_integer(Reader&, StringView, int64_t value) override + { + if (value > std::numeric_limits::max() || value < 0) + { + return nullopt; + } + return static_cast(value); + } + }; + + struct BooleanDeserializer final : IDeserializer + { + virtual StringView type_name() const override { return "a boolean"; } + + virtual Optional visit_boolean(Reader&, StringView, bool b) override { return b; } + }; + + enum class AllowEmpty : bool + { + No, + Yes, }; - // Warning: NEVER use this type except as a CRTP base template - struct VisitorCrtpBase + struct ArrayDeserializer final : IDeserializer> { - // the following function must be defined by the Underlying class - // const char* type_name(); + using typename IDeserializer>::type; + + virtual StringView type_name() const override { return type_name_; } - // We do this auto dance since function bodies are checked _after_ typedefs in the superclass, - // but function declarations are checked beforehand. Therefore, we can get C++ to use this typedef - // only once the function bodies are checked by returning `auto` and specifying the - // return type in the function body. - auto visit_null(Reader&, StringView) { return Optional(nullopt); } - auto visit_boolean(Reader&, StringView, bool) { return Optional(nullopt); } - auto visit_integer(Reader& r, StringView field_name, int64_t i) + ArrayDeserializer(StringView type_name_, AllowEmpty allow_empty, Underlying&& t = {}) + : type_name_(type_name_), underlying_visitor_(static_cast(t)), allow_empty_(allow_empty) { - return static_cast(*this).visit_number(r, field_name, static_cast(i)); } - auto visit_number(Reader&, StringView, double) { return Optional(nullopt); } - auto visit_string(Reader&, StringView, StringView) { return Optional(nullopt); } - auto visit_array(Reader&, StringView, const Json::Array&) + + virtual Optional visit_array(Reader& r, StringView key, const Array& arr) override { - return Optional(nullopt); + if (allow_empty_ == AllowEmpty::No && arr.size() == 0) + { + return nullopt; + } + return r.array_elements(arr, key, underlying_visitor_); } - auto visit_object(Reader&, StringView, const Json::Object&) + + private: + StringView type_name_; + Underlying underlying_visitor_; + AllowEmpty allow_empty_; + }; + + struct ParagraphDeserializer final : IDeserializer> + { + virtual StringView type_name() const override { return "a string or array of strings"; } + + virtual Optional> visit_string(Reader&, StringView, StringView sv) override + { + std::vector out; + out.push_back(sv.to_string()); + return out; + } + + virtual Optional> visit_array(Reader& r, StringView key, const Array& arr) override { - return Optional(nullopt); + return r.array_elements(arr, key, StringDeserializer{"a string"}); + } + }; + + struct IdentifierDeserializer final : Json::IDeserializer + { + virtual StringView type_name() const override { return "an identifier"; } + + // [a-z0-9]+(-[a-z0-9]+)*, plus not any of {prn, aux, nul, con, lpt[1-9], com[1-9], core, default} + static bool is_ident(StringView sv); + + virtual Optional visit_string(Json::Reader&, StringView, StringView sv) override + { + if (is_ident(sv)) + { + return sv.to_string(); + } + else + { + return nullopt; + } + } + }; + + struct PackageNameDeserializer final : Json::IDeserializer + { + virtual StringView type_name() const override { return "a package name"; } + + static bool is_package_name(StringView sv) + { + if (sv.size() == 0) + { + return false; + } + + for (const auto& ident : Strings::split(sv, '.')) + { + if (!IdentifierDeserializer::is_ident(ident)) + { + return false; + } + } + + return true; + } + + virtual Optional visit_string(Json::Reader&, StringView, StringView sv) override + { + if (!is_package_name(sv)) + { + return nullopt; + } + return sv.to_string(); } - // we can't make the SMFs protected because of an issue with /permissive mode }; ExpectedT, std::unique_ptr> parse_file( diff --git a/toolsrc/src/vcpkg/base/json.cpp b/toolsrc/src/vcpkg/base/json.cpp index f34f2927123342..133e6bfdfb4ad5 100644 --- a/toolsrc/src/vcpkg/base/json.cpp +++ b/toolsrc/src/vcpkg/base/json.cpp @@ -5,6 +5,8 @@ #include +#include + namespace vcpkg::Json { using VK = ValueKind; @@ -986,6 +988,33 @@ namespace vcpkg::Json }; } + bool IdentifierDeserializer::is_ident(StringView sv) + { + static const std::regex BASIC_IDENTIFIER = std::regex(R"([a-z0-9]+(-[a-z0-9]+)*)"); + + // we only check for lowercase in RESERVED since we already remove all + // strings with uppercase letters from the basic check + static const std::regex RESERVED = std::regex(R"(prn|aux|nul|con|(lpt|com)[1-9]|core|default)"); + + // back-compat + if (sv == "all_modules") + { + return true; + } + + if (!std::regex_match(sv.begin(), sv.end(), BASIC_IDENTIFIER)) + { + return false; // we're not even in the shape of an identifier + } + + if (std::regex_match(sv.begin(), sv.end(), RESERVED)) + { + return false; // we're a reserved identifier + } + + return true; + } + ExpectedT, std::unique_ptr> parse_file(const Files::Filesystem& fs, const fs::path& path, std::error_code& ec) noexcept diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index ada57d7ef97fd2..841cdad21a9c0b 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -80,25 +80,6 @@ namespace vcpkg static const std::string SUPPORTS = "Supports"; } - namespace ManifestFields - { - constexpr static StringLiteral NAME = "name"; - constexpr static StringLiteral VERSION = "version-string"; - - constexpr static StringLiteral PORT_VERSION = "port-version"; - constexpr static StringLiteral MAINTAINERS = "maintainers"; - constexpr static StringLiteral DESCRIPTION = "description"; - constexpr static StringLiteral HOMEPAGE = "homepage"; - constexpr static StringLiteral DOCUMENTATION = "documentation"; - constexpr static StringLiteral LICENSE = "license"; - constexpr static StringLiteral DEPENDENCIES = "dependencies"; - constexpr static StringLiteral DEV_DEPENDENCIES = "dev-dependencies"; - constexpr static StringLiteral FEATURES = "features"; - constexpr static StringLiteral DEFAULT_FEATURES = "default-features"; - constexpr static StringLiteral SUPPORTS = "supports"; - constexpr static StringLiteral CONFIGURATION = "configuration"; - } - static Span get_list_of_valid_fields() { static const StringView valid_fields[] = { @@ -117,112 +98,7 @@ namespace vcpkg return valid_fields; } - static Span get_list_of_manifest_fields() - { - constexpr static StringView valid_fields[] = { - ManifestFields::NAME, - ManifestFields::VERSION, - - ManifestFields::PORT_VERSION, - ManifestFields::MAINTAINERS, - ManifestFields::DESCRIPTION, - ManifestFields::HOMEPAGE, - ManifestFields::DOCUMENTATION, - ManifestFields::LICENSE, - ManifestFields::DEPENDENCIES, - ManifestFields::DEV_DEPENDENCIES, - ManifestFields::FEATURES, - ManifestFields::DEFAULT_FEATURES, - ManifestFields::SUPPORTS, - ManifestFields::CONFIGURATION, - }; - - return valid_fields; - } - - void print_error_message(Span> error_info_list) - { - Checks::check_exit(VCPKG_LINE_INFO, error_info_list.size() > 0); - - for (auto&& error_info : error_info_list) - { - Checks::check_exit(VCPKG_LINE_INFO, error_info != nullptr); - if (!error_info->error.empty()) - { - System::print2( - System::Color::error, "Error: while loading ", error_info->name, ":\n", error_info->error, '\n'); - } - } - - bool have_remaining_fields = false; - for (auto&& error_info : error_info_list) - { - if (!error_info->extra_fields.empty()) - { - System::print2(System::Color::error, - "Error: There are invalid fields in the control or manifest file of ", - error_info->name, - '\n'); - System::print2("The following fields were not expected:\n"); - - for (const auto& pr : error_info->extra_fields) - { - System::print2(" In ", pr.first, ": ", Strings::join(", ", pr.second), "\n"); - } - have_remaining_fields = true; - } - } - - if (have_remaining_fields) - { - System::print2("This is the list of valid fields for CONTROL files (case-sensitive): \n\n ", - Strings::join("\n ", get_list_of_valid_fields()), - "\n\n"); - System::print2("And this is the list of valid fields for manifest files: \n\n ", - Strings::join("\n ", get_list_of_manifest_fields()), - "\n\n"); -#if defined(_WIN32) - auto bootstrap = ".\\bootstrap-vcpkg.bat"; -#else - auto bootstrap = ".\/bootstrap-vcpkg.sh"; -#endif - System::print2("You may need to update the vcpkg binary; try running %s to update.\n\n", bootstrap); - } - - for (auto&& error_info : error_info_list) - { - if (!error_info->missing_fields.empty()) - { - System::print2(System::Color::error, - "Error: There are missing fields in the control file of ", - error_info->name, - '\n'); - System::print2("The following fields were missing:\n"); - for (const auto& pr : error_info->missing_fields) - { - System::print2(" In ", pr.first, ": ", Strings::join(", ", pr.second), "\n"); - } - } - } - - for (auto&& error_info : error_info_list) - { - if (!error_info->expected_types.empty()) - { - System::print2(System::Color::error, - "Error: There are invalid field types in the CONTROL or manifest file of ", - error_info->name, - '\n'); - System::print2("The following fields had the wrong types:\n\n"); - - for (const auto& pr : error_info->expected_types) - { - System::printf(" %s was expected to be %s\n", pr.first, pr.second); - } - System::print2("\n"); - } - } - } + void print_error_message(Span> error_info_list); std::string Type::to_string(const Type& t) { @@ -481,202 +357,130 @@ namespace vcpkg return control_file; } - static std::vector invalid_json_fields(const Json::Object& obj, - Span known_fields) noexcept + struct PlatformExprDeserializer : Json::IDeserializer { - const auto field_is_unknown = [known_fields](StringView sv) { - // allow directives - if (sv.size() != 0 && *sv.begin() == '$') - { - return false; - } - return std::find(known_fields.begin(), known_fields.end(), sv) == known_fields.end(); - }; + virtual StringView type_name() const override { return "a platform expression"; } - std::vector res; - for (const auto& kv : obj) + virtual Optional visit_string(Json::Reader&, StringView, StringView sv) override { - if (field_is_unknown(kv.first)) + auto opt = + PlatformExpression::parse_platform_expression(sv, PlatformExpression::MultipleBinaryOperators::Deny); + if (auto res = opt.get()) { - res.push_back(kv.first.to_string()); + return std::move(*res); } - } - - return res; - } - - struct StringField : Json::VisitorCrtpBase - { - using type = std::string; - StringView type_name() { return type_name_; } - - Optional visit_string(Json::Reader&, StringView, StringView sv) { return sv.to_string(); } - - explicit StringField(StringView type_name_) : type_name_(type_name_) { } - - private: - StringView type_name_; - }; - - struct NaturalNumberField : Json::VisitorCrtpBase - { - using type = int; - StringView type_name() { return "a natural number"; } - - Optional visit_integer(Json::Reader&, StringView, int64_t value) - { - if (value > std::numeric_limits::max() || value < 0) + else { + Debug::print("Failed to parse platform expression: ", opt.error(), "\n"); return nullopt; } - return static_cast(value); } }; - struct BooleanField : Json::VisitorCrtpBase - { - using type = bool; - StringView type_name() { return "a boolean"; } - - Optional visit_boolean(Json::Reader&, StringView, bool b) { return b; } - }; - - enum class AllowEmpty : bool - { - No, - Yes, - }; - - template - struct ArrayField : Json::VisitorCrtpBase> + struct DependencyDeserializer : Json::IDeserializer { - using type = std::vector; + virtual StringView type_name() const override { return "a dependency"; } - StringView type_name() { return type_name_; } + constexpr static StringLiteral NAME = "name"; + constexpr static StringLiteral FEATURES = "features"; + constexpr static StringLiteral DEFAULT_FEATURES = "default-features"; + constexpr static StringLiteral PLATFORM = "platform"; - ArrayField(StringView type_name_, AllowEmpty allow_empty, T&& t = {}) - : type_name_(type_name_), underlying_visitor_(static_cast(t)), allow_empty_(allow_empty) + virtual Span valid_fields() const override { + const static StringView t[] = { + NAME, + FEATURES, + DEFAULT_FEATURES, + PLATFORM, + }; + + return t; } - Optional visit_array(Json::Reader& r, StringView key, const Json::Array& arr) + virtual Optional visit_string(Json::Reader&, StringView, StringView sv) override { - if (allow_empty_ == AllowEmpty::No && arr.size() == 0) + if (!Json::PackageNameDeserializer::is_package_name(sv)) { return nullopt; } - return r.array_elements(arr, key, underlying_visitor_); - } - - private: - StringView type_name_; - T underlying_visitor_; - AllowEmpty allow_empty_; - }; - struct ParagraphField : Json::VisitorCrtpBase - { - using type = std::vector; - StringView type_name() { return "a string or array of strings"; } - - Optional> visit_string(Json::Reader&, StringView, StringView sv) - { - std::vector out; - out.push_back(sv.to_string()); - return out; - } - - Optional> visit_array(Json::Reader& r, StringView key, const Json::Array& arr) - { - return r.array_elements(arr, key, StringField{"a string"}); + Dependency dep; + dep.name = sv.to_string(); + return dep; } - }; - - struct IdentifierField : Json::VisitorCrtpBase - { - using type = std::string; - StringView type_name() { return "an identifier"; } - // [a-z0-9]+(-[a-z0-9]+)*, plus not any of {prn, aux, nul, con, lpt[1-9], com[1-9], core, default} - static bool is_ident(StringView sv) + virtual Optional visit_object(Json::Reader& r, StringView, const Json::Object& obj) override { - static const std::regex BASIC_IDENTIFIER = std::regex(R"([a-z0-9]+(-[a-z0-9]+)*)"); - - // we only check for lowercase in RESERVED since we already remove all - // strings with uppercase letters from the basic check - static const std::regex RESERVED = std::regex(R"(prn|aux|nul|con|(lpt|com)[1-9]|core|default)"); + Dependency dep; - // back-compat - if (sv == "all_modules") + for (const auto& el : obj) { - return true; + if (Strings::starts_with(el.first, "$")) + { + dep.extra_info.insert_or_replace(el.first.to_string(), el.second); + } } - if (!std::regex_match(sv.begin(), sv.end(), BASIC_IDENTIFIER)) - { - return false; // we're not even in the shape of an identifier - } + r.required_object_field(type_name(), obj, NAME, dep.name, Json::PackageNameDeserializer{}); + r.optional_object_field( + obj, FEATURES, dep.features, Json::ArrayDeserializer{"an array of identifiers", Json::AllowEmpty::Yes}); - if (std::regex_match(sv.begin(), sv.end(), RESERVED)) + bool default_features = true; + r.optional_object_field(obj, DEFAULT_FEATURES, default_features, Json::BooleanDeserializer{}); + if (!default_features) { - return false; // we're a reserved identifier + dep.features.push_back("core"); } - return true; - } + r.optional_object_field(obj, PLATFORM, dep.platform, PlatformExprDeserializer{}); - Optional visit_string(Json::Reader&, StringView, StringView sv) - { - if (is_ident(sv)) - { - return sv.to_string(); - } - else - { - return nullopt; - } + return dep; } }; - struct PackageNameField : Json::VisitorCrtpBase + struct FeatureDeserializer : Json::IDeserializer> { - using type = std::string; - StringView type_name() { return "a package name"; } + virtual StringView type_name() const override { return "a feature"; } - static bool is_package_name(StringView sv) + constexpr static StringLiteral NAME = "name"; + constexpr static StringLiteral DESCRIPTION = "description"; + constexpr static StringLiteral DEPENDENCIES = "dependencies"; + + virtual Span valid_fields() const override { - if (sv.size() == 0) - { - return false; - } + const static StringView t[] = {NAME, DESCRIPTION, DEPENDENCIES}; + return t; + } + + virtual Optional> visit_object(Json::Reader& r, StringView, const Json::Object& obj) override + { + auto feature = std::make_unique(); - for (const auto& ident : Strings::split(sv, '.')) + for (const auto& el : obj) { - if (!IdentifierField::is_ident(ident)) + if (Strings::starts_with(el.first, "$")) { - return false; + feature->extra_info.insert_or_replace(el.first.to_string(), el.second); } } - return true; - } + r.required_object_field(type_name(), obj, NAME, feature->name, Json::IdentifierDeserializer{}); + r.required_object_field(type_name(), obj, DESCRIPTION, feature->description, Json::ParagraphDeserializer{}); + r.optional_object_field(obj, + DEPENDENCIES, + feature->dependencies, + Json::ArrayDeserializer{"an array of dependencies", Json::AllowEmpty::Yes}); - Optional visit_string(Json::Reader&, StringView, StringView sv) - { - if (!is_package_name(sv)) - { - return nullopt; - } - return sv.to_string(); + return std::move(feature); } }; // We "parse" this so that we can add actual license parsing at some point in the future // without breaking anyone - struct LicenseExpressionField : Json::VisitorCrtpBase + struct LicenseExpressionDeserializer : Json::IDeserializer { - using type = std::string; - StringView type_name() { return "an SPDX license expression"; } + virtual StringView type_name() const override { return "an SPDX license expression"; } enum class Mode { @@ -691,14 +495,13 @@ namespace vcpkg "OR", }; constexpr static StringView VALID_LICENSES[] = -#include "spdx-licenses.inc" - ; - + #include "spdx-licenses.inc" + ; constexpr static StringView VALID_EXCEPTIONS[] = -#include "spdx-exceptions.inc" - ; + #include "spdx-licenses.inc" + ; - Optional visit_string(Json::Reader&, StringView, StringView sv) + virtual Optional visit_string(Json::Reader&, StringView, StringView sv) override { Mode mode = Mode::ExpectExpression; size_t open_parens = 0; @@ -813,129 +616,102 @@ namespace vcpkg } }; - struct PlatformExprField : Json::VisitorCrtpBase + struct ManifestDeserializer : Json::IDeserializer> { - using type = PlatformExpression::Expr; - StringView type_name() { return "a platform expression"; } - - Optional visit_string(Json::Reader&, StringView, StringView sv) - { - auto opt = - PlatformExpression::parse_platform_expression(sv, PlatformExpression::MultipleBinaryOperators::Deny); - if (auto res = opt.get()) - { - return std::move(*res); - } - else - { - Debug::print("Failed to parse platform expression: ", opt.error(), "\n"); - return nullopt; - } - } - }; - - struct DependencyField : Json::VisitorCrtpBase - { - using type = Dependency; - StringView type_name() { return "a dependency"; } + virtual StringView type_name() const override { return "a manifest"; } constexpr static StringLiteral NAME = "name"; + constexpr static StringLiteral VERSION = "version-string"; + + constexpr static StringLiteral PORT_VERSION = "port-version"; + constexpr static StringLiteral MAINTAINERS = "maintainers"; + constexpr static StringLiteral DESCRIPTION = "description"; + constexpr static StringLiteral HOMEPAGE = "homepage"; + constexpr static StringLiteral DOCUMENTATION = "documentation"; + constexpr static StringLiteral LICENSE = "license"; + constexpr static StringLiteral DEPENDENCIES = "dependencies"; + constexpr static StringLiteral DEV_DEPENDENCIES = "dev-dependencies"; constexpr static StringLiteral FEATURES = "features"; constexpr static StringLiteral DEFAULT_FEATURES = "default-features"; - constexpr static StringLiteral PLATFORM = "platform"; - const static StringView KNOWN_FIELDS[4]; // not constexpr in MSVC 2015 + constexpr static StringLiteral SUPPORTS = "supports"; + constexpr static StringLiteral CONFIGURATION = "configuration"; - Optional visit_string(Json::Reader&, StringView, StringView sv) + virtual Span valid_fields() const override { - if (!PackageNameField::is_package_name(sv)) - { - return nullopt; - } + const static StringView t[] = { + NAME, + VERSION, + + PORT_VERSION, + MAINTAINERS, + DESCRIPTION, + HOMEPAGE, + DOCUMENTATION, + LICENSE, + DEPENDENCIES, + DEV_DEPENDENCIES, + FEATURES, + DEFAULT_FEATURES, + SUPPORTS, + CONFIGURATION, + }; - Dependency dep; - dep.name = sv.to_string(); - return dep; + return t; } - Optional visit_object(Json::Reader& r, StringView, const Json::Object& obj) + virtual Optional> visit_object(Json::Reader& r, StringView, const Json::Object& obj) override { - { - auto extra_fields = invalid_json_fields(obj, KNOWN_FIELDS); - if (!extra_fields.empty()) - { - r.error().add_extra_fields(type_name().to_string(), std::move(extra_fields)); - } - } + auto control_file = std::make_unique(); + control_file->core_paragraph = std::make_unique(); - Dependency dep; + auto& spgh = control_file->core_paragraph; + spgh->type = Type{Type::PORT}; for (const auto& el : obj) { if (Strings::starts_with(el.first, "$")) { - dep.extra_info.insert_or_replace(el.first.to_string(), el.second); + spgh->extra_info.insert_or_replace(el.first.to_string(), el.second); } } - r.required_object_field(type_name(), obj, NAME, dep.name, PackageNameField{}); - r.optional_object_field( - obj, FEATURES, dep.features, ArrayField{"an array of identifiers", AllowEmpty::Yes}); - - bool default_features = true; - r.optional_object_field(obj, DEFAULT_FEATURES, default_features, BooleanField{}); - if (!default_features) - { - dep.features.push_back("core"); - } - - r.optional_object_field(obj, PLATFORM, dep.platform, PlatformExprField{}); - - return dep; - } - }; - const StringView DependencyField::KNOWN_FIELDS[] = {NAME, FEATURES, DEFAULT_FEATURES, PLATFORM}; - - struct FeatureField : Json::VisitorCrtpBase - { - using type = std::unique_ptr; - StringView type_name() { return "a feature"; } - - constexpr static StringLiteral NAME = "name"; - constexpr static StringLiteral DESCRIPTION = "description"; - constexpr static StringLiteral DEPENDENCIES = "dependencies"; - const static StringView KNOWN_FIELDS[3]; // Not constexpr in MSVC 2015 + constexpr static StringView type_name = "vcpkg.json"; + r.required_object_field(type_name, obj, NAME, spgh->name, Json::IdentifierDeserializer{}); + r.required_object_field( + type_name, obj, VERSION, spgh->version, Json::StringDeserializer{"a version"}); + r.optional_object_field(obj, PORT_VERSION, spgh->port_version, Json::NaturalNumberDeserializer{}); + r.optional_object_field(obj, MAINTAINERS, spgh->maintainers, Json::ParagraphDeserializer{}); + r.optional_object_field(obj, DESCRIPTION, spgh->description, Json::ParagraphDeserializer{}); + r.optional_object_field(obj, HOMEPAGE, spgh->homepage, Json::StringDeserializer{"a url"}); + r.optional_object_field(obj, DOCUMENTATION, spgh->documentation, Json::StringDeserializer{"a url"}); + r.optional_object_field(obj, LICENSE, spgh->license, LicenseExpressionDeserializer{}); + r.optional_object_field(obj, + DEPENDENCIES, + spgh->dependencies, + Json::ArrayDeserializer{"an array of dependencies", Json::AllowEmpty::Yes}); - Optional> visit_object(Json::Reader& r, StringView, const Json::Object& obj) - { + if (obj.contains(DEV_DEPENDENCIES)) { - auto extra_fields = invalid_json_fields(obj, KNOWN_FIELDS); - if (!extra_fields.empty()) - { - r.error().add_extra_fields(type_name().to_string(), std::move(extra_fields)); - } + System::print2(System::Color::error, "dev_dependencies are not yet supported"); + Checks::exit_fail(VCPKG_LINE_INFO); } - auto feature = std::make_unique(); + r.optional_object_field(obj, SUPPORTS, spgh->supports_expression, PlatformExprDeserializer{}); - for (const auto& el : obj) - { - if (Strings::starts_with(el.first, "$")) - { - feature->extra_info.insert_or_replace(el.first.to_string(), el.second); - } - } + r.optional_object_field(obj, + DEFAULT_FEATURES, + spgh->default_features, + Json::ArrayDeserializer{"an array of identifiers", Json::AllowEmpty::Yes}); - r.required_object_field(type_name(), obj, NAME, feature->name, IdentifierField{}); - r.required_object_field(type_name(), obj, DESCRIPTION, feature->description, ParagraphField{}); r.optional_object_field(obj, - DEPENDENCIES, - feature->dependencies, - ArrayField{"an array of dependencies", AllowEmpty::Yes}); + FEATURES, + control_file->feature_paragraphs, + Json::ArrayDeserializer{"an array of feature definitions", Json::AllowEmpty::Yes}); - return std::move(feature); + canonicalize(*control_file); + return std::move(control_file); } }; - const StringView FeatureField::KNOWN_FIELDS[] = {NAME, DESCRIPTION, DEPENDENCIES}; Parse::ParseExpected SourceControlFile::parse_manifest_file(const fs::path& path_to_manifest, const Json::Object& manifest) @@ -972,70 +748,104 @@ namespace vcpkg auto visit = Json::Reader{&err}; err.pcei.name = fs::u8string(path_to_manifest); + + auto res = visit.visit_value(manifest, "$", ManifestDeserializer{}); + + if (err.pcei.has_error()) { - auto extra_fields = invalid_json_fields(manifest, get_list_of_manifest_fields()); - if (!extra_fields.empty()) - { - err.pcei.extra_fields["manifest"] = std::move(extra_fields); - } + return std::make_unique(std::move(err.pcei)); } + else if (auto p = res.get()) + { + return std::move(*p); + } + else + { + Checks::unreachable(VCPKG_LINE_INFO); + } + } - auto control_file = std::make_unique(); - control_file->core_paragraph = std::make_unique(); - - auto& spgh = control_file->core_paragraph; - spgh->type = Type{Type::PORT}; + void print_error_message(Span> error_info_list) + { + Checks::check_exit(VCPKG_LINE_INFO, error_info_list.size() > 0); - for (const auto& el : manifest) + for (auto&& error_info : error_info_list) { - if (Strings::starts_with(el.first, "$")) + Checks::check_exit(VCPKG_LINE_INFO, error_info != nullptr); + if (!error_info->error.empty()) { - spgh->extra_info.insert_or_replace(el.first.to_string(), el.second); + System::print2( + System::Color::error, "Error: while loading ", error_info->name, ":\n", error_info->error, '\n'); } } - constexpr static StringView type_name = "vcpkg.json"; - visit.required_object_field(type_name, manifest, ManifestFields::NAME, spgh->name, IdentifierField{}); - visit.required_object_field( - type_name, manifest, ManifestFields::VERSION, spgh->version, StringField{"a version"}); - visit.optional_object_field(manifest, ManifestFields::PORT_VERSION, spgh->port_version, NaturalNumberField{}); - visit.optional_object_field(manifest, ManifestFields::MAINTAINERS, spgh->maintainers, ParagraphField{}); - visit.optional_object_field(manifest, ManifestFields::DESCRIPTION, spgh->description, ParagraphField{}); - visit.optional_object_field(manifest, ManifestFields::HOMEPAGE, spgh->homepage, StringField{"a url"}); - visit.optional_object_field(manifest, ManifestFields::DOCUMENTATION, spgh->documentation, StringField{"a url"}); - visit.optional_object_field(manifest, ManifestFields::LICENSE, spgh->license, LicenseExpressionField{}); - visit.optional_object_field(manifest, - ManifestFields::DEPENDENCIES, - spgh->dependencies, - ArrayField{"an array of dependencies", AllowEmpty::Yes}); - - if (manifest.contains(ManifestFields::DEV_DEPENDENCIES)) + bool have_remaining_fields = false; + for (auto&& error_info : error_info_list) { - System::print2(System::Color::error, "dev_dependencies are not yet supported"); - Checks::exit_fail(VCPKG_LINE_INFO); - } - - visit.optional_object_field(manifest, ManifestFields::SUPPORTS, spgh->supports_expression, PlatformExprField{}); + if (!error_info->extra_fields.empty()) + { + System::print2(System::Color::error, + "Error: There are invalid fields in the control or manifest file of ", + error_info->name, + '\n'); + System::print2("The following fields were not expected:\n"); - visit.optional_object_field(manifest, - ManifestFields::DEFAULT_FEATURES, - spgh->default_features, - ArrayField{"an array of identifiers", AllowEmpty::Yes}); + for (const auto& pr : error_info->extra_fields) + { + System::print2(" In ", pr.first, ": ", Strings::join(", ", pr.second), "\n"); + } + have_remaining_fields = true; + } + } - visit.optional_object_field(manifest, - ManifestFields::FEATURES, - control_file->feature_paragraphs, - ArrayField{"an array of feature definitions", AllowEmpty::Yes}); + if (have_remaining_fields) + { + System::print2("This is the list of valid fields for CONTROL files (case-sensitive): \n\n ", + Strings::join("\n ", get_list_of_valid_fields()), + "\n\n"); + System::print2("And this is the list of valid fields for manifest files: \n\n ", + Strings::join("\n ", ManifestDeserializer{}.valid_fields()), + "\n\n"); + System::print2("You may need to update the vcpkg binary; try running bootstrap-vcpkg.bat or " + "bootstrap-vcpkg.sh to update.\n\n"); + } - if (err.pcei.has_error()) + for (auto&& error_info : error_info_list) { - return std::make_unique(std::move(err.pcei)); + if (!error_info->missing_fields.empty()) + { + System::print2(System::Color::error, + "Error: There are missing fields in the control file of ", + error_info->name, + '\n'); + System::print2("The following fields were missing:\n"); + for (const auto& pr : error_info->missing_fields) + { + System::print2(" In ", pr.first, ": ", Strings::join(", ", pr.second), "\n"); + } + } } - canonicalize(*control_file); - return std::move(control_file); + for (auto&& error_info : error_info_list) + { + if (!error_info->expected_types.empty()) + { + System::print2(System::Color::error, + "Error: There are invalid field types in the CONTROL or manifest file of ", + error_info->name, + '\n'); + System::print2("The following fields had the wrong types:\n\n"); + + for (const auto& pr : error_info->expected_types) + { + System::printf(" %s was expected to be %s\n", pr.first, pr.second); + } + System::print2("\n"); + } + } } + Optional SourceControlFile::find_feature(const std::string& featurename) const { auto it = Util::find_if(feature_paragraphs, @@ -1129,18 +939,18 @@ namespace vcpkg dep_obj.insert(el.first.to_string(), el.second); } - dep_obj.insert(DependencyField::NAME, Json::Value::string(dep.name)); + dep_obj.insert(DependencyDeserializer::NAME, Json::Value::string(dep.name)); auto features_copy = dep.features; auto core_it = std::find(features_copy.begin(), features_copy.end(), "core"); if (core_it != features_copy.end()) { - dep_obj.insert(DependencyField::DEFAULT_FEATURES, Json::Value::boolean(false)); + dep_obj.insert(DependencyDeserializer::DEFAULT_FEATURES, Json::Value::boolean(false)); features_copy.erase(core_it); } - serialize_optional_array(dep_obj, DependencyField::FEATURES, features_copy); - serialize_optional_string(dep_obj, DependencyField::PLATFORM, to_string(dep.platform)); + serialize_optional_array(dep_obj, DependencyDeserializer::FEATURES, features_copy); + serialize_optional_string(dep_obj, DependencyDeserializer::PLATFORM, to_string(dep.platform)); } }; @@ -1151,25 +961,25 @@ namespace vcpkg obj.insert(el.first.to_string(), el.second); } - obj.insert(ManifestFields::NAME, Json::Value::string(scf.core_paragraph->name)); - obj.insert(ManifestFields::VERSION, Json::Value::string(scf.core_paragraph->version)); + obj.insert(ManifestDeserializer::NAME, Json::Value::string(scf.core_paragraph->name)); + obj.insert(ManifestDeserializer::VERSION, Json::Value::string(scf.core_paragraph->version)); if (scf.core_paragraph->port_version != 0 || debug) { - obj.insert(ManifestFields::PORT_VERSION, Json::Value::integer(scf.core_paragraph->port_version)); + obj.insert(ManifestDeserializer::PORT_VERSION, Json::Value::integer(scf.core_paragraph->port_version)); } - serialize_paragraph(obj, ManifestFields::MAINTAINERS, scf.core_paragraph->maintainers); - serialize_paragraph(obj, ManifestFields::DESCRIPTION, scf.core_paragraph->description); + serialize_paragraph(obj, ManifestDeserializer::MAINTAINERS, scf.core_paragraph->maintainers); + serialize_paragraph(obj, ManifestDeserializer::DESCRIPTION, scf.core_paragraph->description); - serialize_optional_string(obj, ManifestFields::HOMEPAGE, scf.core_paragraph->homepage); - serialize_optional_string(obj, ManifestFields::DOCUMENTATION, scf.core_paragraph->documentation); - serialize_optional_string(obj, ManifestFields::LICENSE, scf.core_paragraph->license); - serialize_optional_string(obj, ManifestFields::SUPPORTS, to_string(scf.core_paragraph->supports_expression)); + serialize_optional_string(obj, ManifestDeserializer::HOMEPAGE, scf.core_paragraph->homepage); + serialize_optional_string(obj, ManifestDeserializer::DOCUMENTATION, scf.core_paragraph->documentation); + serialize_optional_string(obj, ManifestDeserializer::LICENSE, scf.core_paragraph->license); + serialize_optional_string(obj, ManifestDeserializer::SUPPORTS, to_string(scf.core_paragraph->supports_expression)); if (!scf.core_paragraph->dependencies.empty() || debug) { - auto& deps = obj.insert(ManifestFields::DEPENDENCIES, Json::Array()); + auto& deps = obj.insert(ManifestDeserializer::DEPENDENCIES, Json::Array()); for (const auto& dep : scf.core_paragraph->dependencies) { @@ -1177,11 +987,11 @@ namespace vcpkg } } - serialize_optional_array(obj, ManifestFields::DEFAULT_FEATURES, scf.core_paragraph->default_features); + serialize_optional_array(obj, ManifestDeserializer::DEFAULT_FEATURES, scf.core_paragraph->default_features); if (!scf.feature_paragraphs.empty() || debug) { - auto& arr = obj.insert(ManifestFields::FEATURES, Json::Array()); + auto& arr = obj.insert(ManifestDeserializer::FEATURES, Json::Array()); for (const auto& feature : scf.feature_paragraphs) { auto& feature_obj = arr.push_back(Json::Object()); @@ -1190,12 +1000,12 @@ namespace vcpkg feature_obj.insert(el.first.to_string(), el.second); } - feature_obj.insert(FeatureField::NAME, Json::Value::string(feature->name)); - serialize_paragraph(feature_obj, FeatureField::DESCRIPTION, feature->description, true); + feature_obj.insert(FeatureDeserializer::NAME, Json::Value::string(feature->name)); + serialize_paragraph(feature_obj, FeatureDeserializer::DESCRIPTION, feature->description, true); if (!feature->dependencies.empty() || debug) { - auto& deps = feature_obj.insert(FeatureField::DEPENDENCIES, Json::Array()); + auto& deps = feature_obj.insert(FeatureDeserializer::DEPENDENCIES, Json::Array()); for (const auto& dep : feature->dependencies) { serialize_dependency(deps, dep); From 15a670f9392a1b6c913587c4d565bb7725450ef4 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 19 Aug 2020 13:19:42 -0700 Subject: [PATCH 05/18] [vcpkg] Add initial registries support Also add format_manifest support for configuration --- toolsrc/include/vcpkg/base/json.h | 11 +--- toolsrc/include/vcpkg/fwd/registries.h | 7 +++ toolsrc/include/vcpkg/registries.h | 60 +++++++++++++++++++ toolsrc/include/vcpkg/vcpkgpaths.h | 29 ++++++++- .../src/vcpkg/commands.format-manifest.cpp | 20 ++++++- toolsrc/src/vcpkg/vcpkgpaths.cpp | 27 +++++++-- 6 files changed, 138 insertions(+), 16 deletions(-) create mode 100644 toolsrc/include/vcpkg/fwd/registries.h create mode 100644 toolsrc/include/vcpkg/registries.h diff --git a/toolsrc/include/vcpkg/base/json.h b/toolsrc/include/vcpkg/base/json.h index 83e377d4a1c8d0..6b83682505dbee 100644 --- a/toolsrc/include/vcpkg/base/json.h +++ b/toolsrc/include/vcpkg/base/json.h @@ -307,14 +307,9 @@ namespace vcpkg::Json } virtual Optional visit_number(Reader&, StringView, double) { return nullopt; } virtual Optional visit_string(Reader&, StringView, StringView) { return nullopt; } - virtual Optional visit_array(Reader&, StringView, const Array&) - { - return nullopt; - } - virtual Optional visit_object(Reader&, StringView, const Object&) - { - return nullopt; - } + virtual Optional visit_array(Reader&, StringView, const Array&) { return nullopt; } + virtual Optional visit_object(Reader&, StringView, const Object&) { return nullopt; } + protected: IDeserializer() = default; IDeserializer(const IDeserializer&) = default; diff --git a/toolsrc/include/vcpkg/fwd/registries.h b/toolsrc/include/vcpkg/fwd/registries.h new file mode 100644 index 00000000000000..659314d7578f85 --- /dev/null +++ b/toolsrc/include/vcpkg/fwd/registries.h @@ -0,0 +1,7 @@ +#pragma once + +namespace vcpkg +{ + struct RegistryImpl; + struct Registry; +} diff --git a/toolsrc/include/vcpkg/registries.h b/toolsrc/include/vcpkg/registries.h new file mode 100644 index 00000000000000..ebede276e37c58 --- /dev/null +++ b/toolsrc/include/vcpkg/registries.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace vcpkg +{ + + struct RegistryImpl + { + virtual void update(VcpkgPaths& paths, std::error_code& ec) const = 0; + virtual fs::path get_registry_root(StringView port_name, const VcpkgPaths& paths) const = 0; + + virtual ~RegistryImpl() = default; + protected: + RegistryImpl() = default; + RegistryImpl(const RegistryImpl&) = default; + RegistryImpl& operator=(const RegistryImpl&) = default; + RegistryImpl(RegistryImpl&&) = default; + RegistryImpl& operator=(RegistryImpl&&) = default; + }; + + + struct Registry + { + // requires: static_cast(implementation) + Registry(std::vector&& packages, std::unique_ptr&& implementation); + + Registry(std::vector&&, std::nullptr_t) = delete; + + // always ordered lexicographically + Span packages() const { return packages_; } + const RegistryImpl& implementation() const { return *implementation_; } + private: + std::vector packages_; + std::unique_ptr implementation_; + }; + + struct RegistryImplDeserializer : Json::IDeserializer> + { + virtual StringView type_name() const override; + + virtual Optional> visit_object(Json::Reader&, StringView, const Json::Object&) override; + }; + + struct RegistryDeserializer final : Json::IDeserializer + { + virtual StringView type_name() const override; + + virtual Optional visit_object(Json::Reader&, StringView, const Json::Object&) override; + }; +} diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h index 1e00fe017fd2a1..b59bbbbed04716 100644 --- a/toolsrc/include/vcpkg/vcpkgpaths.h +++ b/toolsrc/include/vcpkg/vcpkgpaths.h @@ -9,6 +9,8 @@ #include #include +#include + namespace vcpkg { struct ToolsetArchOption @@ -55,6 +57,31 @@ namespace vcpkg struct PackageSpec; struct Triplet; + struct Registries + { + Registries(); + Registries(Registries&&); + Registries& operator=(Registries&&); + ~Registries(); + + // finds the correct registry for the port name + // Returns the null pointer if there is no registry set up for that name + const Registry* registry_for_port(StringView port_name) const; + + // TODO: figure out how to get this to return an error (or maybe it should be a warning?) + void add_registry(Registry&& r); + void set_default_registry(std::unique_ptr&& r); + void set_default_registry(std::nullptr_t r); + private: + std::unique_ptr default_registry; + std::vector set; + }; + + struct Configuration + { + Registries registries; + }; + struct VcpkgPaths : Util::MoveOnlyBase { struct TripletFile @@ -110,7 +137,7 @@ namespace vcpkg Optional get_manifest() const; Optional get_manifest_style() const; - Optional get_manifest_config() const; + Optional get_manifest_config() const; /// Retrieve a toolset matching a VS version /// diff --git a/toolsrc/src/vcpkg/commands.format-manifest.cpp b/toolsrc/src/vcpkg/commands.format-manifest.cpp index 72cac695856e6f..d72e1e46078668 100644 --- a/toolsrc/src/vcpkg/commands.format-manifest.cpp +++ b/toolsrc/src/vcpkg/commands.format-manifest.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace { @@ -16,6 +17,7 @@ namespace struct ToWrite { SourceControlFile scf; + Optional config; fs::path file_to_write; fs::path original_path; std::string original_source; @@ -41,7 +43,9 @@ namespace return nullopt; } - auto scf = SourceControlFile::parse_manifest_file(manifest_path, parsed_json.object()); + auto parsed_json_obj = parsed_json.object(); + + auto scf = SourceControlFile::parse_manifest_file(manifest_path, parsed_json_obj); if (!scf.has_value()) { System::printf(System::Color::error, "Failed to parse manifest file: %s\n", path_string); @@ -49,8 +53,15 @@ namespace return nullopt; } + Optional config; + if (auto conf = parsed_json_obj.get("configuration")) + { + config = std::move(*conf); + } + return ToWrite{ std::move(*scf.value_or_exit(VCPKG_LINE_INFO)), + std::move(config), manifest_path, manifest_path, std::move(contents), @@ -88,6 +99,7 @@ namespace return ToWrite{ std::move(*scf_res.value_or_exit(VCPKG_LINE_INFO)), + nullopt, manifest_path, control_path, std::move(contents), @@ -151,6 +163,12 @@ Please open an issue at https://github.com/microsoft/vcpkg, with the following o Json::stringify(serialize_debug_manifest(*check_scf), {})); } + if (auto conf = data.config.get()) + { + // note: we don't yet canonicalize config + res.insert("configuration", std::move(*conf)); + } + // the manifest scf is correct std::error_code ec; fs.write_contents(data.file_to_write, Json::stringify(res, {}), ec); diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 30da3736d4b530..72ccddbe84e2d5 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -82,7 +83,11 @@ namespace namespace vcpkg { - static std::pair>, Optional> load_manifest_and_config( + Registries::Registries(Registries&&) = default; + Registries& Registries::operator=(Registries&&) = default; + Registries::~Registries() = default; + + static std::pair>, Optional> load_manifest_and_config( const Files::Filesystem& fs, const fs::path& manifest_dir) { std::error_code ec; @@ -109,11 +114,13 @@ namespace vcpkg } std::pair manifest = {std::move(manifest_value.first.object()), std::move(manifest_value.second)}; + Optional config; + if (auto p_manifest_config = manifest.first.get("configuration")) { if (p_manifest_config->is_object()) { - return {std::move(manifest), std::move(p_manifest_config->object())}; + config = std::move(p_manifest_config->object()); } else if (p_manifest_config->is_string()) { @@ -136,7 +143,7 @@ namespace vcpkg ": configuration files must have a top-level object\n"); Checks::exit_fail(VCPKG_LINE_INFO); } - return {std::move(manifest), std::move(parsed_config.first.object())}; + config = std::move(parsed_config.first.object()); } else { @@ -148,7 +155,15 @@ namespace vcpkg Checks::exit_fail(VCPKG_LINE_INFO); } } - return {std::move(manifest), nullopt}; + + if (auto c = config.get()) + { + Checks::unreachable(VCPKG_LINE_INFO); + } + else + { + return {std::move(manifest), nullopt}; + } } namespace details @@ -176,7 +191,7 @@ namespace vcpkg fs::SystemHandle file_lock_handle; Optional> m_manifest_doc; - Optional m_manifest_config; + Optional m_manifest_config; }; } @@ -425,7 +440,7 @@ If you wish to silence this error and use classic mode, you can: } } - Optional VcpkgPaths::get_manifest_config() const { return m_pimpl->m_manifest_config; } + Optional VcpkgPaths::get_manifest_config() const { return m_pimpl->m_manifest_config; } const Toolset& VcpkgPaths::get_toolset(const Build::PreBuildInfo& prebuildinfo) const { From 997567ffd9aaddb464f60f0eeada2d759a511bd8 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 20 Aug 2020 15:30:27 -0700 Subject: [PATCH 06/18] [vcpkg] Move over to using registries for the builtin ports directory this still allows us to use overlay ports, but uses the registry set for everything else --- toolsrc/include/vcpkg/base/json.h | 40 +++++---- toolsrc/include/vcpkg/paragraphs.h | 8 +- toolsrc/include/vcpkg/portfileprovider.h | 6 +- toolsrc/include/vcpkg/registries.h | 23 ++++- toolsrc/include/vcpkg/vcpkgpaths.h | 16 ++-- toolsrc/src/vcpkg/commands.edit.cpp | 7 +- toolsrc/src/vcpkg/commands.portsdiff.cpp | 7 +- toolsrc/src/vcpkg/install.cpp | 10 ++- toolsrc/src/vcpkg/paragraphs.cpp | 102 +++++++++++++++++++---- toolsrc/src/vcpkg/portfileprovider.cpp | 97 ++++++++++++++------- toolsrc/src/vcpkg/registries.cpp | 82 ++++++++++++++++++ toolsrc/src/vcpkg/sourceparagraph.cpp | 63 ++++++++------ toolsrc/src/vcpkg/vcpkgpaths.cpp | 65 +++++++++++---- 13 files changed, 395 insertions(+), 131 deletions(-) create mode 100644 toolsrc/src/vcpkg/registries.cpp diff --git a/toolsrc/include/vcpkg/base/json.h b/toolsrc/include/vcpkg/base/json.h index 6b83682505dbee..c5850eb29ed785 100644 --- a/toolsrc/include/vcpkg/base/json.h +++ b/toolsrc/include/vcpkg/base/json.h @@ -408,24 +408,6 @@ namespace vcpkg::Json return res; } - // checks that an object doesn't contain any fields which both: - // * don't start with a `$` - // * are not in `valid_fields` - // if known_fields.empty(), then it's treated as if all field names are valid - void check_for_unexpected_fields(const Object& obj, Span valid_fields, StringView type_name) - { - if (valid_fields.size() == 0) - { - return; - } - - auto extra_fields = invalid_json_fields(obj, valid_fields); - if (!extra_fields.empty()) - { - error().add_extra_fields(type_name.to_string(), std::move(extra_fields)); - } - } - public: template void required_object_field( @@ -510,6 +492,28 @@ namespace vcpkg::Json { return array_elements(arr, key, visitor); } + + // checks that an object doesn't contain any fields which both: + // * don't start with a `$` + // * are not in `valid_fields` + // if known_fields.empty(), then it's treated as if all field names are valid + // this is automatically called before `visit_object`, so you _should not call this_ + // unless you have some sort of subtyping. (for example, something like: + // = { kind: "builtin" } | { kind: "directory", path: string } + // ) + void check_for_unexpected_fields(const Object& obj, Span valid_fields, StringView type_name) + { + if (valid_fields.size() == 0) + { + return; + } + + auto extra_fields = invalid_json_fields(obj, valid_fields); + if (!extra_fields.empty()) + { + error().add_extra_fields(type_name.to_string(), std::move(extra_fields)); + } + } }; struct StringDeserializer final : IDeserializer diff --git a/toolsrc/include/vcpkg/paragraphs.h b/toolsrc/include/vcpkg/paragraphs.h index 7f6453c8f2af1e..b9c905c8a140e5 100644 --- a/toolsrc/include/vcpkg/paragraphs.h +++ b/toolsrc/include/vcpkg/paragraphs.h @@ -23,12 +23,12 @@ namespace vcpkg::Paragraphs struct LoadResults { - std::vector> paragraphs; + std::vector paragraphs; std::vector> errors; }; - LoadResults try_load_all_ports(const Files::Filesystem& fs, const fs::path& ports_dir); + LoadResults try_load_all_ports(const VcpkgPaths& paths); - std::vector> load_all_ports(const Files::Filesystem& fs, - const fs::path& ports_dir); + std::vector load_all_ports(const VcpkgPaths& paths); + std::vector load_overlay_ports(const VcpkgPaths& paths, const fs::path& dir); } diff --git a/toolsrc/include/vcpkg/portfileprovider.h b/toolsrc/include/vcpkg/portfileprovider.h index e4b5d9cb5f6231..49a5b612f369ae 100644 --- a/toolsrc/include/vcpkg/portfileprovider.h +++ b/toolsrc/include/vcpkg/portfileprovider.h @@ -27,13 +27,13 @@ namespace vcpkg::PortFileProvider struct PathsPortFileProvider : Util::ResourceBase, PortFileProvider { explicit PathsPortFileProvider(const vcpkg::VcpkgPaths& paths, - const std::vector& ports_dirs_paths); + const std::vector& overlay_ports /*, int finder */); ExpectedS get_control_file(const std::string& src_name) const override; std::vector load_all_control_files() const override; private: - Files::Filesystem& filesystem; - std::vector ports_dirs; + const VcpkgPaths& paths; + std::vector overlay_ports; mutable std::unordered_map cache; }; } diff --git a/toolsrc/include/vcpkg/registries.h b/toolsrc/include/vcpkg/registries.h index ebede276e37c58..6ad027d16934d8 100644 --- a/toolsrc/include/vcpkg/registries.h +++ b/toolsrc/include/vcpkg/registries.h @@ -13,13 +13,13 @@ namespace vcpkg { - struct RegistryImpl { virtual void update(VcpkgPaths& paths, std::error_code& ec) const = 0; - virtual fs::path get_registry_root(StringView port_name, const VcpkgPaths& paths) const = 0; + virtual fs::path get_registry_root(const VcpkgPaths& paths) const = 0; virtual ~RegistryImpl() = default; + protected: RegistryImpl() = default; RegistryImpl(const RegistryImpl&) = default; @@ -28,7 +28,6 @@ namespace vcpkg RegistryImpl& operator=(RegistryImpl&&) = default; }; - struct Registry { // requires: static_cast(implementation) @@ -39,6 +38,9 @@ namespace vcpkg // always ordered lexicographically Span packages() const { return packages_; } const RegistryImpl& implementation() const { return *implementation_; } + + static std::unique_ptr builtin_registry(); + private: std::vector packages_; std::unique_ptr implementation_; @@ -46,14 +48,27 @@ namespace vcpkg struct RegistryImplDeserializer : Json::IDeserializer> { + constexpr static StringLiteral KIND = "kind"; + constexpr static StringLiteral PATH = "path"; + + constexpr static StringLiteral KIND_BUILTIN = "builtin"; + constexpr static StringLiteral KIND_DIRECTORY = "directory"; + virtual StringView type_name() const override; + virtual Span valid_fields() const override; - virtual Optional> visit_object(Json::Reader&, StringView, const Json::Object&) override; + virtual Optional> visit_object(Json::Reader&, + StringView, + const Json::Object&) override; }; struct RegistryDeserializer final : Json::IDeserializer { + // constexpr static StringLiteral SCOPES = "scopes"; + constexpr static StringLiteral PACKAGES = "packages"; + virtual StringView type_name() const override; + virtual Span valid_fields() const override; virtual Optional visit_object(Json::Reader&, StringView, const Json::Object&) override; }; diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h index b59bbbbed04716..5d8256adcf0912 100644 --- a/toolsrc/include/vcpkg/vcpkgpaths.h +++ b/toolsrc/include/vcpkg/vcpkgpaths.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -9,8 +10,6 @@ #include #include -#include - namespace vcpkg { struct ToolsetArchOption @@ -66,15 +65,20 @@ namespace vcpkg // finds the correct registry for the port name // Returns the null pointer if there is no registry set up for that name - const Registry* registry_for_port(StringView port_name) const; + const RegistryImpl* registry_for_port(StringView port_name) const; + + Span registries() const; + + const RegistryImpl* default_registry() const { return default_registry_.get(); } // TODO: figure out how to get this to return an error (or maybe it should be a warning?) void add_registry(Registry&& r); void set_default_registry(std::unique_ptr&& r); void set_default_registry(std::nullptr_t r); + private: - std::unique_ptr default_registry; - std::vector set; + std::unique_ptr default_registry_; + std::vector registries_; }; struct Configuration @@ -137,7 +141,7 @@ namespace vcpkg Optional get_manifest() const; Optional get_manifest_style() const; - Optional get_manifest_config() const; + const Configuration& get_configuration() const; /// Retrieve a toolset matching a VS version /// diff --git a/toolsrc/src/vcpkg/commands.edit.cpp b/toolsrc/src/vcpkg/commands.edit.cpp index 13091352e984f9..f520e3a8cc77b2 100644 --- a/toolsrc/src/vcpkg/commands.edit.cpp +++ b/toolsrc/src/vcpkg/commands.edit.cpp @@ -85,10 +85,11 @@ namespace vcpkg::Commands::Edit static std::vector valid_arguments(const VcpkgPaths& paths) { - auto sources_and_errors = Paragraphs::try_load_all_ports(paths.get_filesystem(), paths.ports); + auto sources_and_errors = Paragraphs::try_load_all_ports(paths); - return Util::fmap(sources_and_errors.paragraphs, - [](auto&& pgh) -> std::string { return pgh->core_paragraph->name; }); + return Util::fmap(sources_and_errors.paragraphs, [](const SourceControlFileLocation& pgh) -> std::string { + return pgh.source_control_file->core_paragraph->name; + }); } static constexpr std::array EDIT_SWITCHES = { diff --git a/toolsrc/src/vcpkg/commands.portsdiff.cpp b/toolsrc/src/vcpkg/commands.portsdiff.cpp index d470470cd790f8..bef2398feac531 100644 --- a/toolsrc/src/vcpkg/commands.portsdiff.cpp +++ b/toolsrc/src/vcpkg/commands.portsdiff.cpp @@ -100,13 +100,12 @@ namespace vcpkg::Commands::PortsDiff System::cmd_execute_and_capture_output(cmd, System::get_clean_environment()); System::cmd_execute_and_capture_output(Strings::format(R"("%s" reset)", fs::u8string(git_exe)), System::get_clean_environment()); - const auto all_ports = - Paragraphs::load_all_ports(paths.get_filesystem(), temp_checkout_path / ports_dir_name_as_string); + const auto all_ports = Paragraphs::load_overlay_ports(paths, temp_checkout_path / ports_dir_name_as_string); std::map names_and_versions; for (auto&& port : all_ports) { - const auto& core_pgh = *port->core_paragraph; - names_and_versions.emplace(port->core_paragraph->name, VersionT(core_pgh.version, core_pgh.port_version)); + const auto& core_pgh = *port.source_control_file->core_paragraph; + names_and_versions.emplace(core_pgh.name, VersionT(core_pgh.version, core_pgh.port_version)); } fs.remove_all(temp_checkout_path, VCPKG_LINE_INFO); return names_and_versions; diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 6a66f4a89991bd..4fe2d89750e76e 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -551,10 +551,11 @@ namespace vcpkg::Install std::vector get_all_port_names(const VcpkgPaths& paths) { - auto sources_and_errors = Paragraphs::try_load_all_ports(paths.get_filesystem(), paths.ports); + auto sources_and_errors = Paragraphs::try_load_all_ports(paths); - return Util::fmap(sources_and_errors.paragraphs, - [](auto&& pgh) -> std::string { return pgh->core_paragraph->name; }); + return Util::fmap(sources_and_errors.paragraphs, [](const SourceControlFileLocation& pgh) -> std::string { + return pgh.source_control_file->core_paragraph->name; + }); } const CommandStructure COMMAND_STRUCTURE = { @@ -794,7 +795,8 @@ namespace vcpkg::Install if (!maybe_manifest_scf) { print_error_message(maybe_manifest_scf.error()); - Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to read manifest %s/vcpkg.json.", fs::u8string(paths.manifest_root_dir)); + Checks::exit_with_message( + VCPKG_LINE_INFO, "Failed to read manifest %s/vcpkg.json.", fs::u8string(paths.manifest_root_dir)); } auto& manifest_scf = *maybe_manifest_scf.value_or_exit(VCPKG_LINE_INFO); diff --git a/toolsrc/src/vcpkg/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp index 01af69a3e94861..407771de45d965 100644 --- a/toolsrc/src/vcpkg/paragraphs.cpp +++ b/toolsrc/src/vcpkg/paragraphs.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using namespace vcpkg::Parse; using namespace vcpkg; @@ -260,9 +261,9 @@ namespace vcpkg::Paragraphs } static ParseExpected try_load_manifest(const Files::Filesystem& fs, - const std::string& port_name, - const fs::path& path_to_manifest, - std::error_code& ec) + const std::string& port_name, + const fs::path& path_to_manifest, + std::error_code& ec) { auto error_info = std::make_unique(); auto res = Json::parse_file(fs, path_to_manifest, ec); @@ -343,34 +344,71 @@ namespace vcpkg::Paragraphs return pghs.error(); } - LoadResults try_load_all_ports(const Files::Filesystem& fs, const fs::path& ports_dir) + LoadResults try_load_all_ports(const VcpkgPaths& paths) { LoadResults ret; - auto port_dirs = fs.get_files_non_recursive(ports_dir); - Util::sort(port_dirs); - Util::erase_remove_if(port_dirs, [&](auto&& port_dir_entry) { - return fs.is_regular_file(port_dir_entry) && port_dir_entry.filename() == ".DS_Store"; - }); + const auto& fs = paths.get_filesystem(); + + std::vector ports; + + auto load_port_names = [&](const RegistryImpl& r, Span packages) { + auto port_dirs = fs.get_files_non_recursive(r.get_registry_root(paths)); + Util::sort(port_dirs); + Util::erase_remove_if(port_dirs, [&](auto&& port_dir_entry) { + return fs.is_regular_file(port_dir_entry) && port_dir_entry.filename() == ".DS_Store"; + }); + + for (auto&& path : port_dirs) + { + auto port_name = fs::u8string(path.filename()); + if (packages.size() == 0 || std::find(packages.begin(), packages.end(), port_name) != packages.end()) + { + ports.push_back(std::move(port_name)); + } + } + }; + + const auto& registries = paths.get_configuration().registries; - for (auto&& path : port_dirs) + for (const auto& registry : registries.registries()) { - auto maybe_spgh = try_load_port(fs, path); + load_port_names(registry.implementation(), registry.packages()); + } + if (auto registry = registries.default_registry()) + { + load_port_names(*registry, {}); + } + + Util::sort_unique_erase(ports); + + for (const auto& port_name : ports) + { + auto impl = registries.registry_for_port(port_name); + if (!impl) + { + // registry for port must be broken + Checks::unreachable(VCPKG_LINE_INFO); + } + + auto root = impl->get_registry_root(paths); + + auto port_path = root / fs::u8path(port_name); + auto maybe_spgh = try_load_port(fs, port_path); if (const auto spgh = maybe_spgh.get()) { - ret.paragraphs.emplace_back(std::move(*spgh)); + ret.paragraphs.emplace_back(std::move(*spgh), std::move(port_path)); } else { ret.errors.emplace_back(std::move(maybe_spgh).error()); } } + return ret; } - std::vector> load_all_ports(const Files::Filesystem& fs, - const fs::path& ports_dir) + static void load_results_print_error(const LoadResults& results) { - auto results = try_load_all_ports(fs, ports_dir); if (!results.errors.empty()) { if (Debug::g_debugging) @@ -388,6 +426,40 @@ namespace vcpkg::Paragraphs "Use '--debug' to get more information about the parse failures.\n\n"); } } + } + + std::vector load_all_ports(const VcpkgPaths& paths) + { + auto results = try_load_all_ports(paths); + load_results_print_error(results); return std::move(results.paragraphs); } + + std::vector load_overlay_ports(const VcpkgPaths& paths, const fs::path& directory) + { + LoadResults ret; + + const auto& fs = paths.get_filesystem(); + auto port_dirs = fs.get_files_non_recursive(directory); + Util::sort(port_dirs); + Util::erase_remove_if(port_dirs, [&](auto&& port_dir_entry) { + return fs.is_regular_file(port_dir_entry) && port_dir_entry.filename() == ".DS_Store"; + }); + + for (const auto& path : port_dirs) + { + auto maybe_spgh = try_load_port(fs, path); + if (const auto spgh = maybe_spgh.get()) + { + ret.paragraphs.emplace_back(std::move(*spgh), path); + } + else + { + ret.errors.emplace_back(std::move(maybe_spgh).error()); + } + } + + load_results_print_error(ret); + return std::move(ret.paragraphs); + } } diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index 0e9b355de8aa2b..b96cc480b7c49f 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -2,6 +2,7 @@ #include #include +#include #include namespace vcpkg::PortFileProvider @@ -23,12 +24,12 @@ namespace vcpkg::PortFileProvider return Util::fmap(ports, [](auto&& kvpair) -> const SourceControlFileLocation* { return &kvpair.second; }); } - PathsPortFileProvider::PathsPortFileProvider(const vcpkg::VcpkgPaths& paths, - const std::vector& ports_dirs_paths) - : filesystem(paths.get_filesystem()) + PathsPortFileProvider::PathsPortFileProvider(const vcpkg::VcpkgPaths& paths_, + const std::vector& overlay_ports_) + : paths(paths_) { auto& fs = paths.get_filesystem(); - for (auto&& overlay_path : ports_dirs_paths) + for (auto&& overlay_path : overlay_ports_) { if (!overlay_path.empty()) { @@ -45,17 +46,16 @@ namespace vcpkg::PortFileProvider Debug::print("Using overlay: ", fs::u8string(overlay), "\n"); Checks::check_exit( - VCPKG_LINE_INFO, filesystem.exists(overlay), "Error: Path \"%s\" does not exist", overlay.string()); + VCPKG_LINE_INFO, fs.exists(overlay), "Error: Path \"%s\" does not exist", fs::u8string(overlay)); Checks::check_exit(VCPKG_LINE_INFO, fs::is_directory(fs.status(VCPKG_LINE_INFO, overlay)), "Error: Path \"%s\" must be a directory", overlay.string()); - ports_dirs.emplace_back(overlay); + overlay_ports.emplace_back(overlay); } } - ports_dirs.emplace_back(paths.ports); } ExpectedS PathsPortFileProvider::get_control_file(const std::string& spec) const @@ -66,12 +66,14 @@ namespace vcpkg::PortFileProvider return cache_it->second; } - for (auto&& ports_dir : ports_dirs) + const auto& fs = paths.get_filesystem(); + + for (auto&& ports_dir : overlay_ports) { // Try loading individual port - if (Paragraphs::is_port_directory(filesystem, ports_dir)) + if (Paragraphs::is_port_directory(fs, ports_dir)) { - auto maybe_scf = Paragraphs::try_load_port(filesystem, ports_dir); + auto maybe_scf = Paragraphs::try_load_port(fs, ports_dir); if (auto scf = maybe_scf.get()) { if (scf->get()->core_paragraph->name == spec) @@ -92,22 +94,22 @@ namespace vcpkg::PortFileProvider continue; } - auto ports_spec = ports_dir / spec; - if (Paragraphs::is_port_directory(filesystem, ports_spec)) + auto ports_spec = ports_dir / fs::u8path(spec); + if (Paragraphs::is_port_directory(fs, ports_spec)) { - auto found_scf = Paragraphs::try_load_port(filesystem, ports_spec); + auto found_scf = Paragraphs::try_load_port(fs, ports_spec); if (auto scf = found_scf.get()) { if (scf->get()->core_paragraph->name == spec) { auto it = cache.emplace(std::piecewise_construct, - std::forward_as_tuple(spec), - std::forward_as_tuple(std::move(*scf), ports_dir / spec)); + std::forward_as_tuple(std::move(spec)), + std::forward_as_tuple(std::move(*scf), std::move(ports_spec))); return it.first->second; } Checks::exit_with_message(VCPKG_LINE_INFO, "Error: Failed to load port from %s: names did not match: '%s' != '%s'", - fs::u8string(ports_dir / spec), + fs::u8string(ports_spec), spec, scf->get()->core_paragraph->name); } @@ -115,11 +117,41 @@ namespace vcpkg::PortFileProvider { vcpkg::print_error_message(found_scf.error()); Checks::exit_with_message( - VCPKG_LINE_INFO, "Error: Failed to load port from %s", spec, fs::u8string(ports_dir)); + VCPKG_LINE_INFO, "Error: Failed to load port %s from %s", spec, fs::u8string(ports_dir)); } } } + const RegistryImpl* registry = paths.get_configuration().registries.registry_for_port(spec); + auto registry_root = registry->get_registry_root(paths); + auto port_directory = registry_root / fs::u8path(spec); + + if (fs.exists(port_directory)) + { + auto found_scf = Paragraphs::try_load_port(fs, port_directory); + if (auto scf = found_scf.get()) + { + if (scf->get()->core_paragraph->name == spec) + { + auto it = cache.emplace(std::piecewise_construct, + std::forward_as_tuple(spec), + std::forward_as_tuple(std::move(*scf), std::move(port_directory))); + return it.first->second; + } + Checks::exit_with_message(VCPKG_LINE_INFO, + "Error: Failed to load port from %s: names did not match: '%s' != '%s'", + fs::u8string(port_directory), + spec, + scf->get()->core_paragraph->name); + } + else + { + vcpkg::print_error_message(found_scf.error()); + Checks::exit_with_message( + VCPKG_LINE_INFO, "Error: Failed to load port %s from %s", spec, fs::u8string(port_directory)); + } + } + return std::string("Port definition not found"); } @@ -129,20 +161,19 @@ namespace vcpkg::PortFileProvider cache.clear(); std::vector ret; - for (auto&& ports_dir : ports_dirs) + for (const fs::path& ports_dir : overlay_ports) { // Try loading individual port - if (Paragraphs::is_port_directory(filesystem, ports_dir)) + if (Paragraphs::is_port_directory(paths.get_filesystem(), ports_dir)) { - auto maybe_scf = Paragraphs::try_load_port(filesystem, ports_dir); + auto maybe_scf = Paragraphs::try_load_port(paths.get_filesystem(), ports_dir); if (auto scf = maybe_scf.get()) { auto port_name = scf->get()->core_paragraph->name; if (cache.find(port_name) == cache.end()) { - auto it = cache.emplace(std::piecewise_construct, - std::forward_as_tuple(port_name), - std::forward_as_tuple(std::move(*scf), ports_dir)); + auto scfl = SourceControlFileLocation{std::move(*scf), ports_dir}; + auto it = cache.emplace(std::move(port_name), std::move(scfl)); ret.emplace_back(&it.first->second); } } @@ -156,19 +187,29 @@ namespace vcpkg::PortFileProvider } // Try loading all ports inside ports_dir - auto found_scf = Paragraphs::load_all_ports(filesystem, ports_dir); + auto found_scf = Paragraphs::load_overlay_ports(paths, ports_dir); for (auto&& scf : found_scf) { - auto port_name = scf->core_paragraph->name; + auto port_name = scf.source_control_file->core_paragraph->name; if (cache.find(port_name) == cache.end()) { - auto it = cache.emplace(std::piecewise_construct, - std::forward_as_tuple(port_name), - std::forward_as_tuple(std::move(scf), ports_dir / port_name)); + auto it = cache.emplace(std::move(port_name), std::move(scf)); ret.emplace_back(&it.first->second); } } } + + auto all_ports = Paragraphs::load_all_ports(paths); + for (auto&& scf : all_ports) + { + auto port_name = scf.source_control_file->core_paragraph->name; + if (cache.find(port_name) == cache.end()) + { + auto it = cache.emplace(port_name, std::move(scf)); + ret.emplace_back(&it.first->second); + } + } + return ret; } } diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp new file mode 100644 index 00000000000000..772233b5b0179a --- /dev/null +++ b/toolsrc/src/vcpkg/registries.cpp @@ -0,0 +1,82 @@ +#include + +namespace +{ + struct BuiltinRegistry final : vcpkg::RegistryImpl + { + BuiltinRegistry() = default; + BuiltinRegistry(const BuiltinRegistry&) = default; + BuiltinRegistry& operator=(const BuiltinRegistry&) = default; + + virtual void update(vcpkg::VcpkgPaths&, std::error_code& ec) const override { ec.clear(); } + virtual fs::path get_registry_root(const vcpkg::VcpkgPaths& paths) const override { return paths.ports; } + }; +} + +namespace vcpkg +{ + std::unique_ptr Registry::builtin_registry() { return std::make_unique(); } + +#if 0 + struct RegistryImplDeserializer final : Json::IDeserializer> + { + virtual Optional> visit_object(Json::Reader&, StringView, const Json::Object&) override; + }; +#endif + + StringView RegistryImplDeserializer::type_name() const { return "a registry"; } + + Span RegistryImplDeserializer::valid_fields() const + { + static const StringView t[] = {KIND, PATH}; + return t; + } + + static Span builtin_valid_fields() + { + static const StringView t[] = {RegistryImplDeserializer::KIND}; + return t; + } + + Optional> RegistryImplDeserializer::visit_object(Json::Reader& r, + StringView, + const Json::Object& obj) + { + std::string kind; + r.required_object_field( + type_name(), obj, KIND, kind, Json::StringDeserializer{"a registry implementation kind"}); + + if (kind == KIND_BUILTIN) + { + r.check_for_unexpected_fields(obj, builtin_valid_fields(), type_name()); + return static_cast>(std::make_unique()); + } + else if (kind == KIND_DIRECTORY) + { + Checks::exit_with_message(VCPKG_LINE_INFO, "not yet implemented"); + } + else + { + return nullopt; + } + } + +#if 0 + struct RegistryDeserializer final : Json::IDeserializer + { + virtual Optional visit_object(Json::Reader&, StringView, const Json::Object&) override; + }; +#endif + + StringView RegistryDeserializer::type_name() const { return "a registry"; } + + Span RegistryDeserializer::valid_fields() const + { + static const StringView t[] = { + RegistryImplDeserializer::KIND, + RegistryImplDeserializer::PATH, + PACKAGES, + }; + return t; + } +} diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 841cdad21a9c0b..7f09269eab6134 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -423,8 +423,11 @@ namespace vcpkg } r.required_object_field(type_name(), obj, NAME, dep.name, Json::PackageNameDeserializer{}); - r.optional_object_field( - obj, FEATURES, dep.features, Json::ArrayDeserializer{"an array of identifiers", Json::AllowEmpty::Yes}); + r.optional_object_field(obj, + FEATURES, + dep.features, + Json::ArrayDeserializer{"an array of identifiers", + Json::AllowEmpty::Yes}); bool default_features = true; r.optional_object_field(obj, DEFAULT_FEATURES, default_features, Json::BooleanDeserializer{}); @@ -453,7 +456,9 @@ namespace vcpkg return t; } - virtual Optional> visit_object(Json::Reader& r, StringView, const Json::Object& obj) override + virtual Optional> visit_object(Json::Reader& r, + StringView, + const Json::Object& obj) override { auto feature = std::make_unique(); @@ -467,10 +472,11 @@ namespace vcpkg r.required_object_field(type_name(), obj, NAME, feature->name, Json::IdentifierDeserializer{}); r.required_object_field(type_name(), obj, DESCRIPTION, feature->description, Json::ParagraphDeserializer{}); - r.optional_object_field(obj, - DEPENDENCIES, - feature->dependencies, - Json::ArrayDeserializer{"an array of dependencies", Json::AllowEmpty::Yes}); + r.optional_object_field( + obj, + DEPENDENCIES, + feature->dependencies, + Json::ArrayDeserializer{"an array of dependencies", Json::AllowEmpty::Yes}); return std::move(feature); } @@ -495,11 +501,11 @@ namespace vcpkg "OR", }; constexpr static StringView VALID_LICENSES[] = - #include "spdx-licenses.inc" - ; +#include "spdx-licenses.inc" + ; constexpr static StringView VALID_EXCEPTIONS[] = - #include "spdx-licenses.inc" - ; +#include "spdx-licenses.inc" + ; virtual Optional visit_string(Json::Reader&, StringView, StringView sv) override { @@ -659,7 +665,9 @@ namespace vcpkg return t; } - virtual Optional> visit_object(Json::Reader& r, StringView, const Json::Object& obj) override + virtual Optional> visit_object(Json::Reader& r, + StringView, + const Json::Object& obj) override { auto control_file = std::make_unique(); control_file->core_paragraph = std::make_unique(); @@ -677,18 +685,18 @@ namespace vcpkg constexpr static StringView type_name = "vcpkg.json"; r.required_object_field(type_name, obj, NAME, spgh->name, Json::IdentifierDeserializer{}); - r.required_object_field( - type_name, obj, VERSION, spgh->version, Json::StringDeserializer{"a version"}); + r.required_object_field(type_name, obj, VERSION, spgh->version, Json::StringDeserializer{"a version"}); r.optional_object_field(obj, PORT_VERSION, spgh->port_version, Json::NaturalNumberDeserializer{}); r.optional_object_field(obj, MAINTAINERS, spgh->maintainers, Json::ParagraphDeserializer{}); r.optional_object_field(obj, DESCRIPTION, spgh->description, Json::ParagraphDeserializer{}); r.optional_object_field(obj, HOMEPAGE, spgh->homepage, Json::StringDeserializer{"a url"}); r.optional_object_field(obj, DOCUMENTATION, spgh->documentation, Json::StringDeserializer{"a url"}); r.optional_object_field(obj, LICENSE, spgh->license, LicenseExpressionDeserializer{}); - r.optional_object_field(obj, - DEPENDENCIES, - spgh->dependencies, - Json::ArrayDeserializer{"an array of dependencies", Json::AllowEmpty::Yes}); + r.optional_object_field( + obj, + DEPENDENCIES, + spgh->dependencies, + Json::ArrayDeserializer{"an array of dependencies", Json::AllowEmpty::Yes}); if (obj.contains(DEV_DEPENDENCIES)) { @@ -699,14 +707,16 @@ namespace vcpkg r.optional_object_field(obj, SUPPORTS, spgh->supports_expression, PlatformExprDeserializer{}); r.optional_object_field(obj, - DEFAULT_FEATURES, - spgh->default_features, - Json::ArrayDeserializer{"an array of identifiers", Json::AllowEmpty::Yes}); + DEFAULT_FEATURES, + spgh->default_features, + Json::ArrayDeserializer{"an array of identifiers", + Json::AllowEmpty::Yes}); - r.optional_object_field(obj, - FEATURES, - control_file->feature_paragraphs, - Json::ArrayDeserializer{"an array of feature definitions", Json::AllowEmpty::Yes}); + r.optional_object_field( + obj, + FEATURES, + control_file->feature_paragraphs, + Json::ArrayDeserializer{"an array of feature definitions", Json::AllowEmpty::Yes}); canonicalize(*control_file); return std::move(control_file); @@ -975,7 +985,8 @@ namespace vcpkg serialize_optional_string(obj, ManifestDeserializer::HOMEPAGE, scf.core_paragraph->homepage); serialize_optional_string(obj, ManifestDeserializer::DOCUMENTATION, scf.core_paragraph->documentation); serialize_optional_string(obj, ManifestDeserializer::LICENSE, scf.core_paragraph->license); - serialize_optional_string(obj, ManifestDeserializer::SUPPORTS, to_string(scf.core_paragraph->supports_expression)); + serialize_optional_string( + obj, ManifestDeserializer::SUPPORTS, to_string(scf.core_paragraph->supports_expression)); if (!scf.core_paragraph->dependencies.empty() || debug) { diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 72ccddbe84e2d5..4447e4bd90232b 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -83,11 +83,38 @@ namespace namespace vcpkg { + Registries::Registries() : default_registry_(Registry::builtin_registry()), registries_() { } + Registries::Registries(Registries&&) = default; Registries& Registries::operator=(Registries&&) = default; Registries::~Registries() = default; - static std::pair>, Optional> load_manifest_and_config( + const RegistryImpl* Registries::registry_for_port(StringView name) const + { + for (const auto& registry : registries()) + { + const auto& packages = registry.packages(); + if (std::find(packages.begin(), packages.end(), name) != packages.end()) + { + return ®istry.implementation(); + } + } + return default_registry(); + } + + // this is defined here so that we can see the definition of `Registry` + Span Registries::registries() const { return registries_; } + + struct ConfigurationDeserializer final : Json::IDeserializer + { + virtual StringView type_name() const override { return "a configuration object"; } + + constexpr static StringLiteral DEFAULT_REGISTRY = "default-registry"; + constexpr static StringLiteral REGISTRIES = "registries"; + virtual Span valid_fields() const override; + }; + + static std::pair>, Configuration> load_manifest_and_config( const Files::Filesystem& fs, const fs::path& manifest_dir) { std::error_code ec; @@ -95,12 +122,18 @@ namespace vcpkg auto manifest_opt = Json::parse_file(fs, manifest_path, ec); if (ec) { - Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to load manifest from directory %s: %s", manifest_dir.u8string(), ec.message()); + Checks::exit_with_message(VCPKG_LINE_INFO, + "Failed to load manifest from directory %s: %s", + manifest_dir.u8string(), + ec.message()); } if (!manifest_opt.has_value()) { - Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to parse manifest at %s: %s", manifest_path.u8string(), manifest_opt.error()->format()); + Checks::exit_with_message(VCPKG_LINE_INFO, + "Failed to parse manifest at %s: %s", + manifest_path.u8string(), + manifest_opt.error()->format()); } auto manifest_value = std::move(manifest_opt).value_or_exit(VCPKG_LINE_INFO); @@ -112,7 +145,8 @@ namespace vcpkg ": Manifest files must have a top-level object\n"); Checks::exit_fail(VCPKG_LINE_INFO); } - std::pair manifest = {std::move(manifest_value.first.object()), std::move(manifest_value.second)}; + std::pair manifest = {std::move(manifest_value.first.object()), + std::move(manifest_value.second)}; Optional config; @@ -126,12 +160,12 @@ namespace vcpkg { auto config_name = fs::u8path("vcpkg-configuration.json"); auto config_relative_path = p_manifest_config->string(); - auto config_path = manifest_dir / fs::u8path(config_relative_path.begin(), config_relative_path.end()) / config_name; + auto config_path = + manifest_dir / fs::u8path(config_relative_path.begin(), config_relative_path.end()) / config_name; if (!fs.exists(config_path)) { - System::printf(System::Color::error, - "Failed to find configuration file at %s\n", - config_path.u8string()); + System::printf( + System::Color::error, "Failed to find configuration file at %s\n", config_path.u8string()); Checks::exit_fail(VCPKG_LINE_INFO); } auto parsed_config = Json::parse_file(VCPKG_LINE_INFO, fs, config_path); @@ -147,11 +181,10 @@ namespace vcpkg } else { - System::print2( - System::Color::error, - "Failed to parse manifest at ", - manifest_path.u8string(), - ": Manifest configuration ($.configuration) must be a string or an object.\n"); + System::print2(System::Color::error, + "Failed to parse manifest at ", + manifest_path.u8string(), + ": Manifest configuration ($.configuration) must be a string or an object.\n"); Checks::exit_fail(VCPKG_LINE_INFO); } } @@ -162,7 +195,7 @@ namespace vcpkg } else { - return {std::move(manifest), nullopt}; + return {std::move(manifest), Configuration{}}; } } @@ -191,7 +224,7 @@ namespace vcpkg fs::SystemHandle file_lock_handle; Optional> m_manifest_doc; - Optional m_manifest_config; + Configuration m_manifest_config; }; } @@ -440,7 +473,7 @@ If you wish to silence this error and use classic mode, you can: } } - Optional VcpkgPaths::get_manifest_config() const { return m_pimpl->m_manifest_config; } + const Configuration& VcpkgPaths::get_configuration() const { return m_pimpl->m_manifest_config; } const Toolset& VcpkgPaths::get_toolset(const Build::PreBuildInfo& prebuildinfo) const { From d16af392fcee6d028ce1db9d11f727464925b472 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 20 Aug 2020 15:19:06 -0700 Subject: [PATCH 07/18] [vcpkg] finish off initial registries support still to do: add other types of registries! --- toolsrc/include/vcpkg/base/json.h | 80 ++++++++++------ toolsrc/include/vcpkg/fwd/registries.h | 1 + toolsrc/include/vcpkg/registries.h | 1 + toolsrc/src/vcpkg/base/json.cpp | 4 +- toolsrc/src/vcpkg/portfileprovider.cpp | 48 +++++----- toolsrc/src/vcpkg/registries.cpp | 42 +++++---- toolsrc/src/vcpkg/sourceparagraph.cpp | 1 - toolsrc/src/vcpkg/vcpkgpaths.cpp | 92 +++++++++++++++++-- .../vcpkglib/vcpkglib.vcxproj | 2 + 9 files changed, 195 insertions(+), 76 deletions(-) diff --git a/toolsrc/include/vcpkg/base/json.h b/toolsrc/include/vcpkg/base/json.h index c5850eb29ed785..fba0f1f7b8b923 100644 --- a/toolsrc/include/vcpkg/base/json.h +++ b/toolsrc/include/vcpkg/base/json.h @@ -329,6 +329,37 @@ namespace vcpkg::Json virtual ~ReaderError() = default; }; + struct BasicReaderError : ReaderError + { + virtual void add_missing_field(std::string&& type, std::string&& key) override + { + missing_fields.emplace_back(std::move(type), std::move(key)); + } + virtual void add_expected_type(std::string&& key, std::string&& expected_type) override + { + expected_types.emplace_back(std::move(key), std::move(expected_type)); + } + virtual void add_extra_fields(std::string&& type, std::vector&& fields) override + { + extra_fields.emplace_back(std::move(type), std::move(fields)); + } + virtual void add_mutually_exclusive_fields(std::string&& type, std::vector&& fields) override + { + mutually_exclusive_fields.emplace_back(std::move(type), std::move(fields)); + } + + bool has_error() const + { + return !missing_fields.empty() || !expected_types.empty() || !extra_fields.empty() || + !mutually_exclusive_fields.empty(); + } + + std::vector> missing_fields; + std::vector> expected_types; + std::vector>> extra_fields; + std::vector>> mutually_exclusive_fields; + }; + struct Reader { explicit Reader(ReaderError* err) : err(err) { } @@ -408,6 +439,24 @@ namespace vcpkg::Json return res; } + // checks that an object doesn't contain any fields which both: + // * don't start with a `$` + // * are not in `valid_fields` + // if known_fields.empty(), then it's treated as if all field names are valid + void check_for_unexpected_fields(const Object& obj, Span valid_fields, StringView type_name) + { + if (valid_fields.size() == 0) + { + return; + } + + auto extra_fields = invalid_json_fields(obj, valid_fields); + if (!extra_fields.empty()) + { + error().add_extra_fields(type_name.to_string(), std::move(extra_fields)); + } + } + public: template void required_object_field( @@ -425,15 +474,16 @@ namespace vcpkg::Json required_object_field(type, obj, key, place, visitor); } + // returns whether key \in obj template - void optional_object_field(const Object& obj, StringView key, Type& place, IDeserializer& visitor) + bool optional_object_field(const Object& obj, StringView key, Type& place, IDeserializer& visitor) { - internal_field(obj, key, place, visitor); + return internal_field(obj, key, place, visitor); } template - void optional_object_field(const Object& obj, StringView key, Type& place, IDeserializer&& visitor) + bool optional_object_field(const Object& obj, StringView key, Type& place, IDeserializer&& visitor) { - optional_object_field(obj, key, place, visitor); + return optional_object_field(obj, key, place, visitor); } template @@ -492,28 +542,6 @@ namespace vcpkg::Json { return array_elements(arr, key, visitor); } - - // checks that an object doesn't contain any fields which both: - // * don't start with a `$` - // * are not in `valid_fields` - // if known_fields.empty(), then it's treated as if all field names are valid - // this is automatically called before `visit_object`, so you _should not call this_ - // unless you have some sort of subtyping. (for example, something like: - // = { kind: "builtin" } | { kind: "directory", path: string } - // ) - void check_for_unexpected_fields(const Object& obj, Span valid_fields, StringView type_name) - { - if (valid_fields.size() == 0) - { - return; - } - - auto extra_fields = invalid_json_fields(obj, valid_fields); - if (!extra_fields.empty()) - { - error().add_extra_fields(type_name.to_string(), std::move(extra_fields)); - } - } }; struct StringDeserializer final : IDeserializer diff --git a/toolsrc/include/vcpkg/fwd/registries.h b/toolsrc/include/vcpkg/fwd/registries.h index 659314d7578f85..052b764f17024e 100644 --- a/toolsrc/include/vcpkg/fwd/registries.h +++ b/toolsrc/include/vcpkg/fwd/registries.h @@ -4,4 +4,5 @@ namespace vcpkg { struct RegistryImpl; struct Registry; + struct RegistryImpl; } diff --git a/toolsrc/include/vcpkg/registries.h b/toolsrc/include/vcpkg/registries.h index 6ad027d16934d8..1acd495b38f380 100644 --- a/toolsrc/include/vcpkg/registries.h +++ b/toolsrc/include/vcpkg/registries.h @@ -57,6 +57,7 @@ namespace vcpkg virtual StringView type_name() const override; virtual Span valid_fields() const override; + virtual Optional> visit_null(Json::Reader&, StringView) override; virtual Optional> visit_object(Json::Reader&, StringView, const Json::Object&) override; diff --git a/toolsrc/src/vcpkg/base/json.cpp b/toolsrc/src/vcpkg/base/json.cpp index 133e6bfdfb4ad5..58121ac8e81277 100644 --- a/toolsrc/src/vcpkg/base/json.cpp +++ b/toolsrc/src/vcpkg/base/json.cpp @@ -1039,12 +1039,12 @@ namespace vcpkg::Json auto ret = parse_file(fs, path, ec); if (ec) { - System::print2(System::Color::error, "Failed to read ", path.u8string(), ": ", ec.message(), "\n"); + System::print2(System::Color::error, "Failed to read ", fs::u8string(path), ": ", ec.message(), "\n"); Checks::exit_fail(linfo); } else if (!ret) { - System::print2(System::Color::error, "Failed to parse ", path.u8string(), ":\n"); + System::print2(System::Color::error, "Failed to parse ", fs::u8string(path), ":\n"); System::print2(ret.error()->format()); Checks::exit_fail(linfo); } diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index b96cc480b7c49f..85ac4ff58bd071 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -122,33 +122,35 @@ namespace vcpkg::PortFileProvider } } - const RegistryImpl* registry = paths.get_configuration().registries.registry_for_port(spec); - auto registry_root = registry->get_registry_root(paths); - auto port_directory = registry_root / fs::u8path(spec); - - if (fs.exists(port_directory)) + if (auto registry = paths.get_configuration().registries.registry_for_port(spec)) { - auto found_scf = Paragraphs::try_load_port(fs, port_directory); - if (auto scf = found_scf.get()) + auto registry_root = registry->get_registry_root(paths); + auto port_directory = registry_root / fs::u8path(spec); + + if (fs.exists(port_directory)) { - if (scf->get()->core_paragraph->name == spec) + auto found_scf = Paragraphs::try_load_port(fs, port_directory); + if (auto scf = found_scf.get()) + { + if (scf->get()->core_paragraph->name == spec) + { + auto it = cache.emplace(std::piecewise_construct, + std::forward_as_tuple(spec), + std::forward_as_tuple(std::move(*scf), std::move(port_directory))); + return it.first->second; + } + Checks::exit_with_message(VCPKG_LINE_INFO, + "Error: Failed to load port from %s: names did not match: '%s' != '%s'", + fs::u8string(port_directory), + spec, + scf->get()->core_paragraph->name); + } + else { - auto it = cache.emplace(std::piecewise_construct, - std::forward_as_tuple(spec), - std::forward_as_tuple(std::move(*scf), std::move(port_directory))); - return it.first->second; + vcpkg::print_error_message(found_scf.error()); + Checks::exit_with_message( + VCPKG_LINE_INFO, "Error: Failed to load port %s from %s", spec, fs::u8string(port_directory)); } - Checks::exit_with_message(VCPKG_LINE_INFO, - "Error: Failed to load port from %s: names did not match: '%s' != '%s'", - fs::u8string(port_directory), - spec, - scf->get()->core_paragraph->name); - } - else - { - vcpkg::print_error_message(found_scf.error()); - Checks::exit_with_message( - VCPKG_LINE_INFO, "Error: Failed to load port %s from %s", spec, fs::u8string(port_directory)); } } diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index 772233b5b0179a..becd792f335002 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -17,12 +17,11 @@ namespace vcpkg { std::unique_ptr Registry::builtin_registry() { return std::make_unique(); } -#if 0 - struct RegistryImplDeserializer final : Json::IDeserializer> + Registry::Registry(std::vector&& packages, std::unique_ptr&& impl) + : packages_(std::move(packages)), implementation_(std::move(impl)) { - virtual Optional> visit_object(Json::Reader&, StringView, const Json::Object&) override; - }; -#endif + Checks::check_exit(VCPKG_LINE_INFO, implementation_ != nullptr); + } StringView RegistryImplDeserializer::type_name() const { return "a registry"; } @@ -32,10 +31,9 @@ namespace vcpkg return t; } - static Span builtin_valid_fields() + Optional> RegistryImplDeserializer::visit_null(Json::Reader&, StringView) { - static const StringView t[] = {RegistryImplDeserializer::KIND}; - return t; + return nullptr; } Optional> RegistryImplDeserializer::visit_object(Json::Reader& r, @@ -48,7 +46,6 @@ namespace vcpkg if (kind == KIND_BUILTIN) { - r.check_for_unexpected_fields(obj, builtin_valid_fields(), type_name()); return static_cast>(std::make_unique()); } else if (kind == KIND_DIRECTORY) @@ -61,13 +58,6 @@ namespace vcpkg } } -#if 0 - struct RegistryDeserializer final : Json::IDeserializer - { - virtual Optional visit_object(Json::Reader&, StringView, const Json::Object&) override; - }; -#endif - StringView RegistryDeserializer::type_name() const { return "a registry"; } Span RegistryDeserializer::valid_fields() const @@ -79,4 +69,24 @@ namespace vcpkg }; return t; } + + Optional RegistryDeserializer::visit_object(Json::Reader& r, StringView key, const Json::Object& obj) + { + auto impl = RegistryImplDeserializer{}.visit_object(r, key, obj); + + if (!impl.has_value()) + { + return nullopt; + } + + std::vector packages; + r.required_object_field( + type_name(), + obj, + PACKAGES, + packages, + Json::ArrayDeserializer{"an array of registries", Json::AllowEmpty::Yes}); + + return Registry{std::move(packages), std::move(impl).value_or_exit(VCPKG_LINE_INFO)}; + } } diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 7f09269eab6134..4ac37046a4460a 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -855,7 +855,6 @@ namespace vcpkg } } - Optional SourceControlFile::find_feature(const std::string& featurename) const { auto it = Util::find_if(feature_paragraphs, diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 4447e4bd90232b..9756a21bdd5a2d 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -102,6 +102,11 @@ namespace vcpkg return default_registry(); } + void Registries::add_registry(Registry&& r) { registries_.push_back(std::move(r)); } + + void Registries::set_default_registry(std::unique_ptr&& r) { default_registry_ = std::move(r); } + void Registries::set_default_registry(std::nullptr_t) { default_registry_.reset(); } + // this is defined here so that we can see the definition of `Registry` Span Registries::registries() const { return registries_; } @@ -111,7 +116,38 @@ namespace vcpkg constexpr static StringLiteral DEFAULT_REGISTRY = "default-registry"; constexpr static StringLiteral REGISTRIES = "registries"; - virtual Span valid_fields() const override; + virtual Span valid_fields() const override + { + constexpr static StringView t[] = {DEFAULT_REGISTRY, REGISTRIES}; + return t; + } + + virtual Optional visit_object(Json::Reader& r, StringView, const Json::Object& obj) override + { + Registries registries; + + { + std::unique_ptr default_registry; + if (r.optional_object_field(obj, DEFAULT_REGISTRY, default_registry, RegistryImplDeserializer{})) + { + registries.set_default_registry(std::move(default_registry)); + } + } + + std::vector regs; + r.optional_object_field( + obj, + REGISTRIES, + regs, + Json::ArrayDeserializer{"an array of registries", Json::AllowEmpty::Yes}); + + for (Registry& r : regs) + { + registries.add_registry(std::move(r)); + } + + return Configuration{std::move(registries)}; + } }; static std::pair>, Configuration> load_manifest_and_config( @@ -124,7 +160,7 @@ namespace vcpkg { Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to load manifest from directory %s: %s", - manifest_dir.u8string(), + fs::u8string(manifest_dir), ec.message()); } @@ -132,7 +168,7 @@ namespace vcpkg { Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to parse manifest at %s: %s", - manifest_path.u8string(), + fs::u8string(manifest_path), manifest_opt.error()->format()); } auto manifest_value = std::move(manifest_opt).value_or_exit(VCPKG_LINE_INFO); @@ -141,7 +177,7 @@ namespace vcpkg { System::print2(System::Color::error, "Failed to parse manifest at ", - manifest_path.u8string(), + fs::u8string(manifest_path), ": Manifest files must have a top-level object\n"); Checks::exit_fail(VCPKG_LINE_INFO); } @@ -165,7 +201,7 @@ namespace vcpkg if (!fs.exists(config_path)) { System::printf( - System::Color::error, "Failed to find configuration file at %s\n", config_path.u8string()); + System::Color::error, "Failed to find configuration file at %s\n", fs::u8string(config_path)); Checks::exit_fail(VCPKG_LINE_INFO); } auto parsed_config = Json::parse_file(VCPKG_LINE_INFO, fs, config_path); @@ -173,7 +209,7 @@ namespace vcpkg { System::print2(System::Color::error, "Failed to parse ", - config_path.u8string(), + fs::u8string(config_path), ": configuration files must have a top-level object\n"); Checks::exit_fail(VCPKG_LINE_INFO); } @@ -183,7 +219,7 @@ namespace vcpkg { System::print2(System::Color::error, "Failed to parse manifest at ", - manifest_path.u8string(), + fs::u8string(manifest_path), ": Manifest configuration ($.configuration) must be a string or an object.\n"); Checks::exit_fail(VCPKG_LINE_INFO); } @@ -191,7 +227,47 @@ namespace vcpkg if (auto c = config.get()) { - Checks::unreachable(VCPKG_LINE_INFO); + Json::BasicReaderError err; + Json::Reader reader{&err}; + + auto parsed_config_opt = reader.visit_value(*c, "$", ConfigurationDeserializer{}); + if (err.has_error()) + { + if (!err.missing_fields.empty()) + { + // this should never happen + Checks::unreachable(VCPKG_LINE_INFO); + } + if (!err.expected_types.empty()) + { + System::print2(System::Color::error, "Error: Invalid types in configuration:\n"); + for (const auto& expected : err.expected_types) + { + System::printf( + System::Color::error, " %s was expected to be %s\n", expected.first, expected.second); + } + } + if (!err.extra_fields.empty()) + { + System::print2(System::Color::error, "Error: Invalid fields in configuration:\n"); + for (const auto& extra : err.extra_fields) + { + System::printf(System::Color::error, + " %s had invalid fields: %s\n", + extra.first, + Strings::join(", ", extra.second)); + } + } + if (!err.mutually_exclusive_fields.empty()) + { + // this should never happen + Checks::unreachable(VCPKG_LINE_INFO); + } + + Checks::exit_fail(VCPKG_LINE_INFO); + } + + return {std::move(manifest), std::move(parsed_config_opt).value_or_exit(VCPKG_LINE_INFO)}; } else { diff --git a/toolsrc/windows-bootstrap/vcpkglib/vcpkglib.vcxproj b/toolsrc/windows-bootstrap/vcpkglib/vcpkglib.vcxproj index 334532a3637e43..ee276af03fa5e5 100644 --- a/toolsrc/windows-bootstrap/vcpkglib/vcpkglib.vcxproj +++ b/toolsrc/windows-bootstrap/vcpkglib/vcpkglib.vcxproj @@ -225,6 +225,7 @@ + @@ -310,6 +311,7 @@ + From 90b4defb30a25041fd1b04349be87d16b1e5e7b4 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 20 Aug 2020 20:57:48 -0700 Subject: [PATCH 08/18] [vcpkg] Add filesystem registries! --- toolsrc/include/vcpkg/base/json.h | 12 ++++++- toolsrc/include/vcpkg/registries.h | 7 ---- toolsrc/include/vcpkg/vcpkgpaths.h | 1 + toolsrc/src/vcpkg/base/files.cpp | 4 +++ toolsrc/src/vcpkg/registries.cpp | 26 +++++++++++--- toolsrc/src/vcpkg/vcpkgpaths.cpp | 58 +++++++++++++++++++++--------- 6 files changed, 79 insertions(+), 29 deletions(-) diff --git a/toolsrc/include/vcpkg/base/json.h b/toolsrc/include/vcpkg/base/json.h index fba0f1f7b8b923..a7c965f8ab459c 100644 --- a/toolsrc/include/vcpkg/base/json.h +++ b/toolsrc/include/vcpkg/base/json.h @@ -547,13 +547,23 @@ namespace vcpkg::Json struct StringDeserializer final : IDeserializer { virtual StringView type_name() const override { return type_name_; } - virtual Optional visit_string(Reader&, StringView, StringView sv) override { return sv.to_string(); } + virtual Optional visit_string(Reader&, StringView, StringView sv) override + { + return sv.to_string(); + } explicit StringDeserializer(StringView type_name_) : type_name_(type_name_) { } + private: StringView type_name_; }; + struct PathDeserializer final : IDeserializer + { + virtual StringView type_name() const override { return "a path"; } + virtual Optional visit_string(Reader&, StringView, StringView sv) override { return fs::u8path(sv); } + }; + struct NaturalNumberDeserializer final : IDeserializer { virtual StringView type_name() const override { return "a natural number"; } diff --git a/toolsrc/include/vcpkg/registries.h b/toolsrc/include/vcpkg/registries.h index 1acd495b38f380..c19c711758d056 100644 --- a/toolsrc/include/vcpkg/registries.h +++ b/toolsrc/include/vcpkg/registries.h @@ -19,13 +19,6 @@ namespace vcpkg virtual fs::path get_registry_root(const VcpkgPaths& paths) const = 0; virtual ~RegistryImpl() = default; - - protected: - RegistryImpl() = default; - RegistryImpl(const RegistryImpl&) = default; - RegistryImpl& operator=(const RegistryImpl&) = default; - RegistryImpl(RegistryImpl&&) = default; - RegistryImpl& operator=(RegistryImpl&&) = default; }; struct Registry diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h index 5d8256adcf0912..f4a477a5817059 100644 --- a/toolsrc/include/vcpkg/vcpkgpaths.h +++ b/toolsrc/include/vcpkg/vcpkgpaths.h @@ -114,6 +114,7 @@ namespace vcpkg fs::path original_cwd; fs::path root; fs::path manifest_root_dir; + fs::path manifest_config_root_dir; fs::path buildtrees; fs::path downloads; fs::path packages; diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 482d9aa3ef1e68..4ef69c2c4c9f71 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -1158,6 +1158,10 @@ namespace vcpkg::Files { return rhs; } + else if (!rhs.root_directory().empty()) + { + return lhs.root_name() / rhs; + } else { return lhs / rhs; diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index becd792f335002..0ce92235b6e27d 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -4,13 +4,22 @@ namespace { struct BuiltinRegistry final : vcpkg::RegistryImpl { - BuiltinRegistry() = default; - BuiltinRegistry(const BuiltinRegistry&) = default; - BuiltinRegistry& operator=(const BuiltinRegistry&) = default; - virtual void update(vcpkg::VcpkgPaths&, std::error_code& ec) const override { ec.clear(); } virtual fs::path get_registry_root(const vcpkg::VcpkgPaths& paths) const override { return paths.ports; } }; + + struct DirectoryRegistry final : vcpkg::RegistryImpl + { + virtual void update(vcpkg::VcpkgPaths&, std::error_code& ec) const override { ec.clear(); } + virtual fs::path get_registry_root(const vcpkg::VcpkgPaths& paths) const override + { + return vcpkg::Files::combine(paths.manifest_config_root_dir, path); + } + + DirectoryRegistry(fs::path&& path_) : path(path_) { } + + fs::path path; + }; } namespace vcpkg @@ -46,11 +55,18 @@ namespace vcpkg if (kind == KIND_BUILTIN) { + if (obj.contains(PATH)) + { + r.error().add_extra_fields(type_name().to_string(), {PATH}); + } return static_cast>(std::make_unique()); } else if (kind == KIND_DIRECTORY) { - Checks::exit_with_message(VCPKG_LINE_INFO, "not yet implemented"); + fs::path path; + r.required_object_field(type_name(), obj, PATH, path, Json::PathDeserializer{}); + + return static_cast>(std::make_unique(std::move(path))); } else { diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 9756a21bdd5a2d..60da75fde65952 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -141,17 +141,17 @@ namespace vcpkg regs, Json::ArrayDeserializer{"an array of registries", Json::AllowEmpty::Yes}); - for (Registry& r : regs) + for (Registry& reg : regs) { - registries.add_registry(std::move(r)); + registries.add_registry(std::move(reg)); } return Configuration{std::move(registries)}; } }; - static std::pair>, Configuration> load_manifest_and_config( - const Files::Filesystem& fs, const fs::path& manifest_dir) + static std::pair>, std::pair> + load_manifest_and_config(const Files::Filesystem& fs, const fs::path& manifest_dir) { std::error_code ec; auto manifest_path = manifest_dir / fs::u8path("vcpkg.json"); @@ -184,20 +184,36 @@ namespace vcpkg std::pair manifest = {std::move(manifest_value.first.object()), std::move(manifest_value.second)}; - Optional config; + Optional config_obj; + fs::path config_dir; if (auto p_manifest_config = manifest.first.get("configuration")) { if (p_manifest_config->is_object()) { - config = std::move(p_manifest_config->object()); + config_obj = std::move(p_manifest_config->object()); + config_dir = manifest_dir; } else if (p_manifest_config->is_string()) { auto config_name = fs::u8path("vcpkg-configuration.json"); - auto config_relative_path = p_manifest_config->string(); - auto config_path = - manifest_dir / fs::u8path(config_relative_path.begin(), config_relative_path.end()) / config_name; + auto config_relative_path = fs::u8path(p_manifest_config->string()); + if (config_relative_path.empty()) + { + System::print2(System::Color::error, "Invalid path to vcpkg-configuration: must not be empty.\n"); + Checks::exit_fail(VCPKG_LINE_INFO); + } + + if (!config_relative_path.root_path().empty()) + { + System::printf(System::Color::error, + "Invalid path to vcpkg-configuration '%s': must not be absolute.\n", + p_manifest_config->string()); + Checks::exit_fail(VCPKG_LINE_INFO); + } + + config_dir = manifest_dir / config_relative_path; + auto config_path = config_dir / config_name; if (!fs.exists(config_path)) { System::printf( @@ -213,7 +229,7 @@ namespace vcpkg ": configuration files must have a top-level object\n"); Checks::exit_fail(VCPKG_LINE_INFO); } - config = std::move(parsed_config.first.object()); + config_obj = std::move(parsed_config.first.object()); } else { @@ -225,7 +241,7 @@ namespace vcpkg } } - if (auto c = config.get()) + if (auto c = config_obj.get()) { Json::BasicReaderError err; Json::Reader reader{&err}; @@ -235,8 +251,12 @@ namespace vcpkg { if (!err.missing_fields.empty()) { - // this should never happen - Checks::unreachable(VCPKG_LINE_INFO); + System::print2(System::Color::error, "Error: missing fields in configuration:\n"); + for (const auto& missing : err.missing_fields) + { + System::printf( + System::Color::error, " %s was expected to have: %s\n", missing.first, missing.second); + } } if (!err.expected_types.empty()) { @@ -267,11 +287,16 @@ namespace vcpkg Checks::exit_fail(VCPKG_LINE_INFO); } - return {std::move(manifest), std::move(parsed_config_opt).value_or_exit(VCPKG_LINE_INFO)}; + std::pair config = { + std::move(config_dir), + std::move(parsed_config_opt).value_or_exit(VCPKG_LINE_INFO), + }; + + return {std::move(manifest), std::move(config)}; } else { - return {std::move(manifest), Configuration{}}; + return {std::move(manifest), std::pair{}}; } } @@ -362,7 +387,8 @@ namespace vcpkg auto manifest_and_config = load_manifest_and_config(filesystem, manifest_root_dir); m_pimpl->m_manifest_doc = std::move(manifest_and_config.first); - m_pimpl->m_manifest_config = std::move(manifest_and_config.second); + manifest_config_root_dir = std::move(manifest_and_config.second.first); + m_pimpl->m_manifest_config = std::move(manifest_and_config.second.second); } else { From 1b09dd45b8f3b2f2c8d28e718d909a582ad19c8d Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 21 Aug 2020 12:07:56 -0700 Subject: [PATCH 09/18] CRs --- toolsrc/.clang-format | 12 ++-- toolsrc/include/vcpkg/base/fwd/json.h | 44 +++++++++++++ toolsrc/include/vcpkg/base/fwd/optional.h | 7 ++ toolsrc/include/vcpkg/base/fwd/span.h | 7 ++ toolsrc/include/vcpkg/base/fwd/stringview.h | 6 ++ toolsrc/include/vcpkg/base/json.h | 72 ++++++++++++--------- toolsrc/include/vcpkg/base/optional.h | 10 +-- toolsrc/include/vcpkg/base/stringview.h | 2 + toolsrc/include/vcpkg/fwd/registries.h | 1 - toolsrc/include/vcpkg/paragraphs.h | 15 +++++ toolsrc/include/vcpkg/portfileprovider.h | 3 +- toolsrc/include/vcpkg/registries.h | 3 +- toolsrc/include/vcpkg/sourceparagraph.h | 3 +- toolsrc/include/vcpkg/vcpkgpaths.h | 24 ++++--- toolsrc/src/vcpkg/commands.ci.cpp | 5 +- toolsrc/src/vcpkg/commands.edit.cpp | 4 +- toolsrc/src/vcpkg/install.cpp | 4 +- toolsrc/src/vcpkg/paragraphs.cpp | 12 ++-- toolsrc/src/vcpkg/registries.cpp | 2 + toolsrc/src/vcpkg/sourceparagraph.cpp | 1 - toolsrc/src/vcpkg/vcpkgpaths.cpp | 26 +++++--- 21 files changed, 177 insertions(+), 86 deletions(-) create mode 100644 toolsrc/include/vcpkg/base/fwd/json.h create mode 100644 toolsrc/include/vcpkg/base/fwd/optional.h create mode 100644 toolsrc/include/vcpkg/base/fwd/span.h create mode 100644 toolsrc/include/vcpkg/base/fwd/stringview.h diff --git a/toolsrc/.clang-format b/toolsrc/.clang-format index cdaabb8c11b400..374a4233e6380a 100644 --- a/toolsrc/.clang-format +++ b/toolsrc/.clang-format @@ -40,13 +40,15 @@ IncludeCategories: Priority: -1 - Regex: '^$' Priority: 1 - - Regex: '^$' + - Regex: '^$' Priority: 2 - - Regex: '^$' + - Regex: '^$' Priority: 3 - - Regex: '^$' + - Regex: '^$' Priority: 4 - - Regex: '^<[a-z0-9_]*\.h>$' + - Regex: '^$' Priority: 5 - - Regex: '^<[a-z0-9_]*>$' # C++ standard library + - Regex: '^<[a-z0-9_]*\.h>$' Priority: 6 + - Regex: '^<[a-z0-9_]*>$' # C++ standard library + Priority: 7 diff --git a/toolsrc/include/vcpkg/base/fwd/json.h b/toolsrc/include/vcpkg/base/fwd/json.h new file mode 100644 index 00000000000000..40cbf696ca17f6 --- /dev/null +++ b/toolsrc/include/vcpkg/base/fwd/json.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include + +namespace vcpkg::Json +{ + struct JsonStyle; + enum class ValueKind : int; + struct Value; + struct Object; + struct Array; + + struct ReaderError; + struct BasicReaderError; + struct Reader; + + // This is written all the way out so that one can include a subclass in a header + template + struct IDeserializer + { + using type = Type; + virtual StringView type_name() const = 0; + + virtual Span valid_fields() const; + + virtual Optional visit_null(Reader&, StringView); + virtual Optional visit_boolean(Reader&, StringView, bool); + virtual Optional visit_integer(Reader& r, StringView field_name, int64_t i); + virtual Optional visit_number(Reader&, StringView, double); + virtual Optional visit_string(Reader&, StringView, StringView); + virtual Optional visit_array(Reader&, StringView, const Array&); + virtual Optional visit_object(Reader&, StringView, const Object&); + + protected: + IDeserializer() = default; + IDeserializer(const IDeserializer&) = default; + IDeserializer& operator=(const IDeserializer&) = default; + IDeserializer(IDeserializer&&) = default; + IDeserializer& operator=(IDeserializer&&) = default; + virtual ~IDeserializer() = default; + }; +} diff --git a/toolsrc/include/vcpkg/base/fwd/optional.h b/toolsrc/include/vcpkg/base/fwd/optional.h new file mode 100644 index 00000000000000..38de55d05e5b0e --- /dev/null +++ b/toolsrc/include/vcpkg/base/fwd/optional.h @@ -0,0 +1,7 @@ +#pragma once + +namespace vcpkg +{ + template + struct Optional; +} diff --git a/toolsrc/include/vcpkg/base/fwd/span.h b/toolsrc/include/vcpkg/base/fwd/span.h new file mode 100644 index 00000000000000..0e54225eac47b3 --- /dev/null +++ b/toolsrc/include/vcpkg/base/fwd/span.h @@ -0,0 +1,7 @@ +#pragma once + +namespace vcpkg +{ + template + struct Span; +} diff --git a/toolsrc/include/vcpkg/base/fwd/stringview.h b/toolsrc/include/vcpkg/base/fwd/stringview.h new file mode 100644 index 00000000000000..710c7e453224ed --- /dev/null +++ b/toolsrc/include/vcpkg/base/fwd/stringview.h @@ -0,0 +1,6 @@ +#pragma once + +namespace vcpkg +{ + struct StringView; +} diff --git a/toolsrc/include/vcpkg/base/json.h b/toolsrc/include/vcpkg/base/json.h index a7c965f8ab459c..5aaf2561e32ff2 100644 --- a/toolsrc/include/vcpkg/base/json.h +++ b/toolsrc/include/vcpkg/base/json.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -64,10 +66,7 @@ namespace vcpkg::Json int indent = 2; }; - struct Array; - struct Object; - - enum class ValueKind + enum class ValueKind : int { Null, Boolean, @@ -81,7 +80,6 @@ namespace vcpkg::Json namespace impl { struct ValueImpl; - struct SyntaxErrorImpl; } struct Value @@ -289,35 +287,47 @@ namespace vcpkg::Json underlying_t underlying_; }; - struct Reader; - template - struct IDeserializer + Span IDeserializer::valid_fields() const { - using type = Type; - virtual StringView type_name() const = 0; - - virtual Span valid_fields() const { return {}; } - - virtual Optional visit_null(Reader&, StringView) { return nullopt; } - virtual Optional visit_boolean(Reader&, StringView, bool) { return nullopt; } - virtual Optional visit_integer(Reader& r, StringView field_name, int64_t i) - { - return this->visit_number(r, field_name, static_cast(i)); - } - virtual Optional visit_number(Reader&, StringView, double) { return nullopt; } - virtual Optional visit_string(Reader&, StringView, StringView) { return nullopt; } - virtual Optional visit_array(Reader&, StringView, const Array&) { return nullopt; } - virtual Optional visit_object(Reader&, StringView, const Object&) { return nullopt; } + return {}; + } - protected: - IDeserializer() = default; - IDeserializer(const IDeserializer&) = default; - IDeserializer& operator=(const IDeserializer&) = default; - IDeserializer(IDeserializer&&) = default; - IDeserializer& operator=(IDeserializer&&) = default; - virtual ~IDeserializer() = default; - }; + template + Optional IDeserializer::visit_null(Reader&, StringView) + { + return nullopt; + } + template + Optional IDeserializer::visit_boolean(Reader&, StringView, bool) + { + return nullopt; + } + template + Optional IDeserializer::visit_integer(Reader& r, StringView field_name, int64_t i) + { + return this->visit_number(r, field_name, static_cast(i)); + } + template + Optional IDeserializer::visit_number(Reader&, StringView, double) + { + return nullopt; + } + template + Optional IDeserializer::visit_string(Reader&, StringView, StringView) + { + return nullopt; + } + template + Optional IDeserializer::visit_array(Reader&, StringView, const Array&) + { + return nullopt; + } + template + Optional IDeserializer::visit_object(Reader&, StringView, const Object&) + { + return nullopt; + } struct ReaderError { diff --git a/toolsrc/include/vcpkg/base/optional.h b/toolsrc/include/vcpkg/base/optional.h index 4279645b525511..54e370dff6eb8e 100644 --- a/toolsrc/include/vcpkg/base/optional.h +++ b/toolsrc/include/vcpkg/base/optional.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -165,8 +167,8 @@ namespace vcpkg }; }; - template - struct OptionalStorage + template + struct OptionalStorage { constexpr OptionalStorage() noexcept : m_t(nullptr) { } constexpr OptionalStorage(T& t) : m_t(&t) { } @@ -180,8 +182,8 @@ namespace vcpkg T* m_t; }; - template - struct OptionalStorage + template + struct OptionalStorage { constexpr OptionalStorage() noexcept : m_t(nullptr) { } constexpr OptionalStorage(const T& t) : m_t(&t) { } diff --git a/toolsrc/include/vcpkg/base/stringview.h b/toolsrc/include/vcpkg/base/stringview.h index 405142c3683f53..9238990fef737b 100644 --- a/toolsrc/include/vcpkg/base/stringview.h +++ b/toolsrc/include/vcpkg/base/stringview.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include diff --git a/toolsrc/include/vcpkg/fwd/registries.h b/toolsrc/include/vcpkg/fwd/registries.h index 052b764f17024e..659314d7578f85 100644 --- a/toolsrc/include/vcpkg/fwd/registries.h +++ b/toolsrc/include/vcpkg/fwd/registries.h @@ -4,5 +4,4 @@ namespace vcpkg { struct RegistryImpl; struct Registry; - struct RegistryImpl; } diff --git a/toolsrc/include/vcpkg/paragraphs.h b/toolsrc/include/vcpkg/paragraphs.h index b9c905c8a140e5..a276b391d906a7 100644 --- a/toolsrc/include/vcpkg/paragraphs.h +++ b/toolsrc/include/vcpkg/paragraphs.h @@ -27,6 +27,21 @@ namespace vcpkg::Paragraphs std::vector> errors; }; + // this allows one to pass this around as an overload set to stuff like `Util::fmap`, + // as opposed to making it a function + constexpr struct + { + const std::string& operator()(const SourceControlFileLocation* loc) const + { + return (*this)(*loc->source_control_file); + } + const std::string& operator()(const SourceControlFileLocation& loc) const + { + return (*this)(*loc.source_control_file); + } + const std::string& operator()(const SourceControlFile& scf) const { return scf.core_paragraph->name; } + } name_of_paragraph; + LoadResults try_load_all_ports(const VcpkgPaths& paths); std::vector load_all_ports(const VcpkgPaths& paths); diff --git a/toolsrc/include/vcpkg/portfileprovider.h b/toolsrc/include/vcpkg/portfileprovider.h index 49a5b612f369ae..d3fa0b51f1c93b 100644 --- a/toolsrc/include/vcpkg/portfileprovider.h +++ b/toolsrc/include/vcpkg/portfileprovider.h @@ -26,8 +26,7 @@ namespace vcpkg::PortFileProvider struct PathsPortFileProvider : Util::ResourceBase, PortFileProvider { - explicit PathsPortFileProvider(const vcpkg::VcpkgPaths& paths, - const std::vector& overlay_ports /*, int finder */); + explicit PathsPortFileProvider(const vcpkg::VcpkgPaths& paths, const std::vector& overlay_ports); ExpectedS get_control_file(const std::string& src_name) const override; std::vector load_all_control_files() const override; diff --git a/toolsrc/include/vcpkg/registries.h b/toolsrc/include/vcpkg/registries.h index c19c711758d056..6f5f33da0fa948 100644 --- a/toolsrc/include/vcpkg/registries.h +++ b/toolsrc/include/vcpkg/registries.h @@ -1,7 +1,8 @@ #pragma once +#include + #include -#include #include #include diff --git a/toolsrc/include/vcpkg/sourceparagraph.h b/toolsrc/include/vcpkg/sourceparagraph.h index ac3699ca983d63..d5069adde40bfa 100644 --- a/toolsrc/include/vcpkg/sourceparagraph.h +++ b/toolsrc/include/vcpkg/sourceparagraph.h @@ -1,7 +1,8 @@ #pragma once +#include + #include -#include #include #include #include diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h index f4a477a5817059..c2ac43e2439a20 100644 --- a/toolsrc/include/vcpkg/vcpkgpaths.h +++ b/toolsrc/include/vcpkg/vcpkgpaths.h @@ -1,6 +1,9 @@ #pragma once +#include + #include +#include #include #include @@ -45,23 +48,18 @@ namespace vcpkg struct VcpkgPathsImpl; } - namespace Json - { - struct Object; - struct JsonStyle; - } - struct BinaryParagraph; - struct VcpkgCmdArguments; struct PackageSpec; struct Triplet; - struct Registries + struct RegistrySet { - Registries(); - Registries(Registries&&); - Registries& operator=(Registries&&); - ~Registries(); + RegistrySet(); + RegistrySet(RegistrySet&&) noexcept; + RegistrySet& operator=(RegistrySet&&) noexcept; + ~RegistrySet(); + + friend void swap(RegistrySet& lhs, RegistrySet& rhs) noexcept; // finds the correct registry for the port name // Returns the null pointer if there is no registry set up for that name @@ -83,7 +81,7 @@ namespace vcpkg struct Configuration { - Registries registries; + RegistrySet registries; }; struct VcpkgPaths : Util::MoveOnlyBase diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index e9577e4adfc06d..568c086621049c 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -457,9 +458,7 @@ namespace vcpkg::Commands::CI XunitTestResults xunitTestResults; std::vector all_ports = - Util::fmap(provider.load_all_control_files(), [](const SourceControlFileLocation*& scfl) -> std::string { - return scfl->source_control_file.get()->core_paragraph->name; - }); + Util::fmap(provider.load_all_control_files(), Paragraphs::name_of_paragraph); std::vector results; auto timer = Chrono::ElapsedTimer::create_started(); for (Triplet triplet : triplets) diff --git a/toolsrc/src/vcpkg/commands.edit.cpp b/toolsrc/src/vcpkg/commands.edit.cpp index f520e3a8cc77b2..0be0c461ef2aac 100644 --- a/toolsrc/src/vcpkg/commands.edit.cpp +++ b/toolsrc/src/vcpkg/commands.edit.cpp @@ -87,9 +87,7 @@ namespace vcpkg::Commands::Edit { auto sources_and_errors = Paragraphs::try_load_all_ports(paths); - return Util::fmap(sources_and_errors.paragraphs, [](const SourceControlFileLocation& pgh) -> std::string { - return pgh.source_control_file->core_paragraph->name; - }); + return Util::fmap(sources_and_errors.paragraphs, Paragraphs::name_of_paragraph); } static constexpr std::array EDIT_SWITCHES = { diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 4fe2d89750e76e..925a722febef37 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -553,9 +553,7 @@ namespace vcpkg::Install { auto sources_and_errors = Paragraphs::try_load_all_ports(paths); - return Util::fmap(sources_and_errors.paragraphs, [](const SourceControlFileLocation& pgh) -> std::string { - return pgh.source_control_file->core_paragraph->name; - }); + return Util::fmap(sources_and_errors.paragraphs, Paragraphs::name_of_paragraph); } const CommandStructure COMMAND_STRUCTURE = { diff --git a/toolsrc/src/vcpkg/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp index 407771de45d965..8673da874be5f6 100644 --- a/toolsrc/src/vcpkg/paragraphs.cpp +++ b/toolsrc/src/vcpkg/paragraphs.cpp @@ -351,7 +351,7 @@ namespace vcpkg::Paragraphs std::vector ports; - auto load_port_names = [&](const RegistryImpl& r, Span packages) { + auto load_port_names = [&fs, &ports, &paths](const RegistryImpl& r) { auto port_dirs = fs.get_files_non_recursive(r.get_registry_root(paths)); Util::sort(port_dirs); Util::erase_remove_if(port_dirs, [&](auto&& port_dir_entry) { @@ -360,11 +360,7 @@ namespace vcpkg::Paragraphs for (auto&& path : port_dirs) { - auto port_name = fs::u8string(path.filename()); - if (packages.size() == 0 || std::find(packages.begin(), packages.end(), port_name) != packages.end()) - { - ports.push_back(std::move(port_name)); - } + ports.push_back(fs::u8string(path.filename())); } }; @@ -372,11 +368,11 @@ namespace vcpkg::Paragraphs for (const auto& registry : registries.registries()) { - load_port_names(registry.implementation(), registry.packages()); + load_port_names(registry.implementation()); } if (auto registry = registries.default_registry()) { - load_port_names(*registry, {}); + load_port_names(*registry); } Util::sort_unique_erase(ports); diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index 0ce92235b6e27d..0fd7c64d06a6ea 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -1,3 +1,5 @@ +#include + #include namespace diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 9b1ec35628bcff..7100571a973ea0 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -824,7 +824,6 @@ namespace vcpkg System::printf("You may need to update the vcpkg binary; try running %s to update.\n\n", bootstrap); } - for (auto&& error_info : error_info_list) { if (!error_info->missing_fields.empty()) diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 60da75fde65952..cdc24525631f3a 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -83,13 +83,19 @@ namespace namespace vcpkg { - Registries::Registries() : default_registry_(Registry::builtin_registry()), registries_() { } + RegistrySet::RegistrySet() : default_registry_(Registry::builtin_registry()), registries_() { } - Registries::Registries(Registries&&) = default; - Registries& Registries::operator=(Registries&&) = default; - Registries::~Registries() = default; + RegistrySet::RegistrySet(RegistrySet&&) noexcept = default; + RegistrySet& RegistrySet::operator=(RegistrySet&&) noexcept = default; + RegistrySet::~RegistrySet() = default; - const RegistryImpl* Registries::registry_for_port(StringView name) const + void swap(RegistrySet& lhs, RegistrySet& rhs) noexcept + { + swap(lhs.registries_, rhs.registries_); + swap(lhs.default_registry_, rhs.default_registry_); + } + + const RegistryImpl* RegistrySet::registry_for_port(StringView name) const { for (const auto& registry : registries()) { @@ -102,13 +108,13 @@ namespace vcpkg return default_registry(); } - void Registries::add_registry(Registry&& r) { registries_.push_back(std::move(r)); } + void RegistrySet::add_registry(Registry&& r) { registries_.push_back(std::move(r)); } - void Registries::set_default_registry(std::unique_ptr&& r) { default_registry_ = std::move(r); } - void Registries::set_default_registry(std::nullptr_t) { default_registry_.reset(); } + void RegistrySet::set_default_registry(std::unique_ptr&& r) { default_registry_ = std::move(r); } + void RegistrySet::set_default_registry(std::nullptr_t) { default_registry_.reset(); } // this is defined here so that we can see the definition of `Registry` - Span Registries::registries() const { return registries_; } + Span RegistrySet::registries() const { return registries_; } struct ConfigurationDeserializer final : Json::IDeserializer { @@ -124,7 +130,7 @@ namespace vcpkg virtual Optional visit_object(Json::Reader& r, StringView, const Json::Object& obj) override { - Registries registries; + RegistrySet registries; { std::unique_ptr default_registry; From 1da62fc1d43547bdfe443b2c094641ad35ef6cbb Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 21 Aug 2020 13:04:26 -0700 Subject: [PATCH 10/18] format --- toolsrc/CMakeLists.txt | 4 ++-- toolsrc/include/vcpkg/base/fwd/json.h | 2 +- toolsrc/include/vcpkg/base/fwd/optional.h | 4 ++-- toolsrc/include/vcpkg/base/fwd/span.h | 4 ++-- toolsrc/include/vcpkg/base/fwd/stringview.h | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/toolsrc/CMakeLists.txt b/toolsrc/CMakeLists.txt index a35d8a7c242bd7..aa54a791b56feb 100644 --- a/toolsrc/CMakeLists.txt +++ b/toolsrc/CMakeLists.txt @@ -33,8 +33,8 @@ endif() file(GLOB VCPKGLIB_SOURCES CONFIGURE_DEPENDS src/vcpkg/*.cpp) file(GLOB VCPKGLIB_BASE_SOURCES CONFIGURE_DEPENDS src/vcpkg/base/*.cpp) -file(GLOB VCPKGLIB_INCLUDES CONFIGURE_DEPENDS include/vcpkg/*.h) -file(GLOB VCPKGLIB_BASE_INCLUDES CONFIGURE_DEPENDS include/vcpkg/base/*.h) +file(GLOB VCPKGLIB_INCLUDES CONFIGURE_DEPENDS include/vcpkg/*.h include/vcpkg/fwd/*.h) +file(GLOB VCPKGLIB_BASE_INCLUDES CONFIGURE_DEPENDS include/vcpkg/base/*.h include/vcpkg/base/fwd/*.h) set(VCPKG_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/vcpkg.cpp) diff --git a/toolsrc/include/vcpkg/base/fwd/json.h b/toolsrc/include/vcpkg/base/fwd/json.h index 40cbf696ca17f6..7071103c135db2 100644 --- a/toolsrc/include/vcpkg/base/fwd/json.h +++ b/toolsrc/include/vcpkg/base/fwd/json.h @@ -17,7 +17,7 @@ namespace vcpkg::Json struct Reader; // This is written all the way out so that one can include a subclass in a header - template + template struct IDeserializer { using type = Type; diff --git a/toolsrc/include/vcpkg/base/fwd/optional.h b/toolsrc/include/vcpkg/base/fwd/optional.h index 38de55d05e5b0e..2c3a7ea6c70b07 100644 --- a/toolsrc/include/vcpkg/base/fwd/optional.h +++ b/toolsrc/include/vcpkg/base/fwd/optional.h @@ -2,6 +2,6 @@ namespace vcpkg { - template - struct Optional; + template + struct Optional; } diff --git a/toolsrc/include/vcpkg/base/fwd/span.h b/toolsrc/include/vcpkg/base/fwd/span.h index 0e54225eac47b3..af78aa642a9457 100644 --- a/toolsrc/include/vcpkg/base/fwd/span.h +++ b/toolsrc/include/vcpkg/base/fwd/span.h @@ -2,6 +2,6 @@ namespace vcpkg { - template - struct Span; + template + struct Span; } diff --git a/toolsrc/include/vcpkg/base/fwd/stringview.h b/toolsrc/include/vcpkg/base/fwd/stringview.h index 710c7e453224ed..e297fd43b4ba6f 100644 --- a/toolsrc/include/vcpkg/base/fwd/stringview.h +++ b/toolsrc/include/vcpkg/base/fwd/stringview.h @@ -2,5 +2,5 @@ namespace vcpkg { - struct StringView; + struct StringView; } From 1a475b449c4a01a2707c601d2036055dcdfc3253 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 21 Aug 2020 15:31:50 -0700 Subject: [PATCH 11/18] add support for classic mode --- toolsrc/include/vcpkg/vcpkgpaths.h | 2 +- toolsrc/src/vcpkg/registries.cpp | 2 +- toolsrc/src/vcpkg/vcpkgpaths.cpp | 135 ++++++++++++++++++----------- 3 files changed, 84 insertions(+), 55 deletions(-) diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h index c2ac43e2439a20..ec30b13d8cfc14 100644 --- a/toolsrc/include/vcpkg/vcpkgpaths.h +++ b/toolsrc/include/vcpkg/vcpkgpaths.h @@ -112,7 +112,7 @@ namespace vcpkg fs::path original_cwd; fs::path root; fs::path manifest_root_dir; - fs::path manifest_config_root_dir; + fs::path config_root_dir; fs::path buildtrees; fs::path downloads; fs::path packages; diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index 0fd7c64d06a6ea..77128115a9b2d9 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -15,7 +15,7 @@ namespace virtual void update(vcpkg::VcpkgPaths&, std::error_code& ec) const override { ec.clear(); } virtual fs::path get_registry_root(const vcpkg::VcpkgPaths& paths) const override { - return vcpkg::Files::combine(paths.manifest_config_root_dir, path); + return vcpkg::Files::combine(paths.config_root_dir, path); } DirectoryRegistry(fs::path&& path_) : path(path_) { } diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index cdc24525631f3a..307b12ba8037ae 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -156,6 +156,55 @@ namespace vcpkg } }; + static Configuration load_config(const Json::Object& obj) + { + Json::BasicReaderError err; + Json::Reader reader{&err}; + + auto parsed_config_opt = reader.visit_value(obj, "$", ConfigurationDeserializer{}); + if (err.has_error()) + { + if (!err.missing_fields.empty()) + { + System::print2(System::Color::error, "Error: missing fields in configuration:\n"); + for (const auto& missing : err.missing_fields) + { + System::printf( + System::Color::error, " %s was expected to have: %s\n", missing.first, missing.second); + } + } + if (!err.expected_types.empty()) + { + System::print2(System::Color::error, "Error: Invalid types in configuration:\n"); + for (const auto& expected : err.expected_types) + { + System::printf( + System::Color::error, " %s was expected to be %s\n", expected.first, expected.second); + } + } + if (!err.extra_fields.empty()) + { + System::print2(System::Color::error, "Error: Invalid fields in configuration:\n"); + for (const auto& extra : err.extra_fields) + { + System::printf(System::Color::error, + " %s had invalid fields: %s\n", + extra.first, + Strings::join(", ", extra.second)); + } + } + if (!err.mutually_exclusive_fields.empty()) + { + // this should never happen + Checks::unreachable(VCPKG_LINE_INFO); + } + + Checks::exit_fail(VCPKG_LINE_INFO); + } + + return std::move(parsed_config_opt).value_or_exit(VCPKG_LINE_INFO); + } + static std::pair>, std::pair> load_manifest_and_config(const Files::Filesystem& fs, const fs::path& manifest_dir) { @@ -249,55 +298,7 @@ namespace vcpkg if (auto c = config_obj.get()) { - Json::BasicReaderError err; - Json::Reader reader{&err}; - - auto parsed_config_opt = reader.visit_value(*c, "$", ConfigurationDeserializer{}); - if (err.has_error()) - { - if (!err.missing_fields.empty()) - { - System::print2(System::Color::error, "Error: missing fields in configuration:\n"); - for (const auto& missing : err.missing_fields) - { - System::printf( - System::Color::error, " %s was expected to have: %s\n", missing.first, missing.second); - } - } - if (!err.expected_types.empty()) - { - System::print2(System::Color::error, "Error: Invalid types in configuration:\n"); - for (const auto& expected : err.expected_types) - { - System::printf( - System::Color::error, " %s was expected to be %s\n", expected.first, expected.second); - } - } - if (!err.extra_fields.empty()) - { - System::print2(System::Color::error, "Error: Invalid fields in configuration:\n"); - for (const auto& extra : err.extra_fields) - { - System::printf(System::Color::error, - " %s had invalid fields: %s\n", - extra.first, - Strings::join(", ", extra.second)); - } - } - if (!err.mutually_exclusive_fields.empty()) - { - // this should never happen - Checks::unreachable(VCPKG_LINE_INFO); - } - - Checks::exit_fail(VCPKG_LINE_INFO); - } - - std::pair config = { - std::move(config_dir), - std::move(parsed_config_opt).value_or_exit(VCPKG_LINE_INFO), - }; - + std::pair config = {std::move(config_dir), load_config(*c)}; return {std::move(manifest), std::move(config)}; } else @@ -331,7 +332,7 @@ namespace vcpkg fs::SystemHandle file_lock_handle; Optional> m_manifest_doc; - Configuration m_manifest_config; + Configuration m_config; }; } @@ -393,8 +394,8 @@ namespace vcpkg auto manifest_and_config = load_manifest_and_config(filesystem, manifest_root_dir); m_pimpl->m_manifest_doc = std::move(manifest_and_config.first); - manifest_config_root_dir = std::move(manifest_and_config.second.first); - m_pimpl->m_manifest_config = std::move(manifest_and_config.second.second); + config_root_dir = std::move(manifest_and_config.second.first); + m_pimpl->m_config = std::move(manifest_and_config.second.second); } else { @@ -429,6 +430,34 @@ If you wish to silence this error and use classic mode, you can: manifest_root_dir.clear(); installed = process_output_directory(filesystem, root, args.install_root_dir.get(), "installed", VCPKG_LINE_INFO); + + fs::path config_path = root / fs::u8path("vcpkg-configuration.json"); + if (filesystem.exists(config_path)) + { + std::error_code ec; + auto config_object = Json::parse_file(filesystem, config_path, ec); + if (ec) + { + Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to load configuration file %s: %s", fs::u8string(config_path), ec.message()); + } + + if (auto c = config_object.get()) + { + if (c->first.is_object()) + { + m_pimpl->m_config = load_config(c->first.object()); + config_root_dir = root; + } + else + { + Checks::exit_with_message(VCPKG_LINE_INFO, "Error: failed to parse configuration file %s: configuration must have top-level object.", fs::u8string(config_path)); + } + } + else + { + Checks::exit_with_message(VCPKG_LINE_INFO, "Error: failed to parse configuration file %s: %s", fs::u8string(config_path), config_object.error()->format()); + } + } } buildtrees = @@ -581,7 +610,7 @@ If you wish to silence this error and use classic mode, you can: } } - const Configuration& VcpkgPaths::get_configuration() const { return m_pimpl->m_manifest_config; } + const Configuration& VcpkgPaths::get_configuration() const { return m_pimpl->m_config; } const Toolset& VcpkgPaths::get_toolset(const Build::PreBuildInfo& prebuildinfo) const { From b28f38ad09f7adfa640b68f9d170b6a66ca4ae25 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 21 Aug 2020 15:42:11 -0700 Subject: [PATCH 12/18] format --- toolsrc/src/vcpkg/vcpkgpaths.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 307b12ba8037ae..4f9e77e7e2f5d1 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -188,9 +188,9 @@ namespace vcpkg for (const auto& extra : err.extra_fields) { System::printf(System::Color::error, - " %s had invalid fields: %s\n", - extra.first, - Strings::join(", ", extra.second)); + " %s had invalid fields: %s\n", + extra.first, + Strings::join(", ", extra.second)); } } if (!err.mutually_exclusive_fields.empty()) @@ -430,7 +430,7 @@ If you wish to silence this error and use classic mode, you can: manifest_root_dir.clear(); installed = process_output_directory(filesystem, root, args.install_root_dir.get(), "installed", VCPKG_LINE_INFO); - + fs::path config_path = root / fs::u8path("vcpkg-configuration.json"); if (filesystem.exists(config_path)) { @@ -438,7 +438,10 @@ If you wish to silence this error and use classic mode, you can: auto config_object = Json::parse_file(filesystem, config_path, ec); if (ec) { - Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to load configuration file %s: %s", fs::u8string(config_path), ec.message()); + Checks::exit_with_message(VCPKG_LINE_INFO, + "Failed to load configuration file %s: %s", + fs::u8string(config_path), + ec.message()); } if (auto c = config_object.get()) @@ -450,12 +453,18 @@ If you wish to silence this error and use classic mode, you can: } else { - Checks::exit_with_message(VCPKG_LINE_INFO, "Error: failed to parse configuration file %s: configuration must have top-level object.", fs::u8string(config_path)); + Checks::exit_with_message( + VCPKG_LINE_INFO, + "Error: failed to parse configuration file %s: configuration must have top-level object.", + fs::u8string(config_path)); } } else { - Checks::exit_with_message(VCPKG_LINE_INFO, "Error: failed to parse configuration file %s: %s", fs::u8string(config_path), config_object.error()->format()); + Checks::exit_with_message(VCPKG_LINE_INFO, + "Error: failed to parse configuration file %s: %s", + fs::u8string(config_path), + config_object.error()->format()); } } } From e08b153acd518e8f2619f948f299fd700d1f0a07 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 28 Aug 2020 09:43:09 -0700 Subject: [PATCH 13/18] fix shadowing warning --- toolsrc/src/vcpkg/vcpkgpaths.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 4f9e77e7e2f5d1..e43673d3dc3d14 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -434,7 +434,6 @@ If you wish to silence this error and use classic mode, you can: fs::path config_path = root / fs::u8path("vcpkg-configuration.json"); if (filesystem.exists(config_path)) { - std::error_code ec; auto config_object = Json::parse_file(filesystem, config_path, ec); if (ec) { From 1730500f8e2759a9a56e82673de3a7f13985388c Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 31 Aug 2020 10:28:07 -0700 Subject: [PATCH 14/18] billy crs --- toolsrc/include/vcpkg/base/json.h | 5 ++ toolsrc/include/vcpkg/configuration.h | 16 ++++++ toolsrc/include/vcpkg/fwd/configuration.h | 6 ++ toolsrc/include/vcpkg/fwd/registries.h | 1 + toolsrc/include/vcpkg/registries.h | 35 ++++++++++++ toolsrc/include/vcpkg/vcpkgpaths.h | 33 +---------- toolsrc/src/vcpkg-test/files.cpp | 19 +++++++ toolsrc/src/vcpkg/base/files.cpp | 29 ++++++++-- toolsrc/src/vcpkg/paragraphs.cpp | 67 ++++++++++++++--------- toolsrc/src/vcpkg/portfileprovider.cpp | 3 +- toolsrc/src/vcpkg/registries.cpp | 20 +++++++ toolsrc/src/vcpkg/vcpkgpaths.cpp | 55 +++++-------------- 12 files changed, 184 insertions(+), 105 deletions(-) create mode 100644 toolsrc/include/vcpkg/configuration.h create mode 100644 toolsrc/include/vcpkg/fwd/configuration.h diff --git a/toolsrc/include/vcpkg/base/json.h b/toolsrc/include/vcpkg/base/json.h index 5aaf2561e32ff2..ef5bf34aab9025 100644 --- a/toolsrc/include/vcpkg/base/json.h +++ b/toolsrc/include/vcpkg/base/json.h @@ -287,6 +287,9 @@ namespace vcpkg::Json underlying_t underlying_; }; + VCPKG_MSVC_WARNING(push); + VCPKG_MSVC_WARNING(disable : 4505); + template Span IDeserializer::valid_fields() const { @@ -329,6 +332,8 @@ namespace vcpkg::Json return nullopt; } + VCPKG_MSVC_WARNING(pop); + struct ReaderError { virtual void add_missing_field(std::string&& type, std::string&& key) = 0; diff --git a/toolsrc/include/vcpkg/configuration.h b/toolsrc/include/vcpkg/configuration.h new file mode 100644 index 00000000000000..4cba88fe5e06e5 --- /dev/null +++ b/toolsrc/include/vcpkg/configuration.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include + +namespace vcpkg +{ + struct Configuration + { + // This member is set up via two different configuration options, + // `registries` and `default_registry`. The fall back logic is + // taken care of in RegistrySet. + RegistrySet registry_set; + }; +} diff --git a/toolsrc/include/vcpkg/fwd/configuration.h b/toolsrc/include/vcpkg/fwd/configuration.h new file mode 100644 index 00000000000000..5fa9cee343aa74 --- /dev/null +++ b/toolsrc/include/vcpkg/fwd/configuration.h @@ -0,0 +1,6 @@ +#pragma once + +namespace vcpkg +{ + struct Configuration; +} diff --git a/toolsrc/include/vcpkg/fwd/registries.h b/toolsrc/include/vcpkg/fwd/registries.h index 659314d7578f85..7352c429d175f4 100644 --- a/toolsrc/include/vcpkg/fwd/registries.h +++ b/toolsrc/include/vcpkg/fwd/registries.h @@ -4,4 +4,5 @@ namespace vcpkg { struct RegistryImpl; struct Registry; + struct RegistrySet; } diff --git a/toolsrc/include/vcpkg/registries.h b/toolsrc/include/vcpkg/registries.h index 6f5f33da0fa948..909d549ae85171 100644 --- a/toolsrc/include/vcpkg/registries.h +++ b/toolsrc/include/vcpkg/registries.h @@ -67,4 +67,39 @@ namespace vcpkg virtual Optional visit_object(Json::Reader&, StringView, const Json::Object&) override; }; + + // this type implements the registry fall back logic from the registries RFC: + // A port name maps to one of the non-default registries if that registry declares + // that it is the registry for that port name, else it maps to the default registry + // if that registry exists; else, there is no registry for a port. + // The way one sets this up is via the `"registries"` and `"default_registry"` + // configuration settings. + struct RegistrySet + { + RegistrySet(); + + friend void swap(RegistrySet& lhs, RegistrySet& rhs) noexcept + { + swap(lhs.registries_, rhs.registries_); + swap(lhs.default_registry_, rhs.default_registry_); + } + + // finds the correct registry for the port name + // Returns the null pointer if there is no registry set up for that name + const RegistryImpl* registry_for_port(StringView port_name) const; + + Span registries() const { return registries_; } + + const RegistryImpl* default_registry() const { return default_registry_.get(); } + + // TODO: figure out how to get this to return an error (or maybe it should be a warning?) + void add_registry(Registry&& r); + void set_default_registry(std::unique_ptr&& r); + void set_default_registry(std::nullptr_t r); + + private: + std::unique_ptr default_registry_; + std::vector registries_; + }; + } diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h index ec30b13d8cfc14..ae2ee38236fb96 100644 --- a/toolsrc/include/vcpkg/vcpkgpaths.h +++ b/toolsrc/include/vcpkg/vcpkgpaths.h @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -52,38 +53,6 @@ namespace vcpkg struct PackageSpec; struct Triplet; - struct RegistrySet - { - RegistrySet(); - RegistrySet(RegistrySet&&) noexcept; - RegistrySet& operator=(RegistrySet&&) noexcept; - ~RegistrySet(); - - friend void swap(RegistrySet& lhs, RegistrySet& rhs) noexcept; - - // finds the correct registry for the port name - // Returns the null pointer if there is no registry set up for that name - const RegistryImpl* registry_for_port(StringView port_name) const; - - Span registries() const; - - const RegistryImpl* default_registry() const { return default_registry_.get(); } - - // TODO: figure out how to get this to return an error (or maybe it should be a warning?) - void add_registry(Registry&& r); - void set_default_registry(std::unique_ptr&& r); - void set_default_registry(std::nullptr_t r); - - private: - std::unique_ptr default_registry_; - std::vector registries_; - }; - - struct Configuration - { - RegistrySet registries; - }; - struct VcpkgPaths : Util::MoveOnlyBase { struct TripletFile diff --git a/toolsrc/src/vcpkg-test/files.cpp b/toolsrc/src/vcpkg-test/files.cpp index 255c87d69a01a9..a8c7c2ba2ff4f0 100644 --- a/toolsrc/src/vcpkg-test/files.cpp +++ b/toolsrc/src/vcpkg-test/files.cpp @@ -155,6 +155,25 @@ namespace } } +TEST_CASE ("fs::combine works correctly", "[filesystem][files]") +{ + using namespace fs; + using namespace vcpkg::Files; + CHECK(combine(u8path("/a/b"), u8path("c/d")) == u8path("/a/b/c/d")); + CHECK(combine(u8path("a/b"), u8path("c/d")) == u8path("a/b/c/d")); + CHECK(combine(u8path("/a/b"), u8path("/c/d")) == u8path("/c/d")); + +#if defined(_WIN32) + CHECK(combine(u8path("C:/a/b"), u8path("c/d")) == u8path("C:/a/b/c/d")); + CHECK(combine(u8path("C:a/b"), u8path("c/d")) == u8path("C:a/b/c/d")); + CHECK(combine(u8path("C:a/b"), u8path("/c/d")) == u8path("C:/c/d")); + CHECK(combine(u8path("C:/a/b"), u8path("/c/d")) == u8path("C:/c/d")); + CHECK(combine(u8path("C:/a/b"), u8path("D:/c/d")) == u8path("D:/c/d")); + CHECK(combine(u8path("C:/a/b"), u8path("D:c/d")) == u8path("D:c/d")); + CHECK(combine(u8path("C:/a/b"), u8path("C:c/d")) == u8path("C:/a/b/c/d")); +#endif +} + TEST_CASE ("remove all", "[files]") { auto urbg = get_urbg(0); diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 70f1edf9a309eb..560de393275fff 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -1151,20 +1151,37 @@ namespace vcpkg::Files fs::path combine(const fs::path& lhs, const fs::path& rhs) { -#if VCPKG_USE_STD_FILESYSTEM +#if VCPKG_USE_STD_FILESYSTEM || !defined(_MSC_VER) return lhs / rhs; -#else // ^^^ VCPKG_USE_STD_FILESYSTEM // !VCPKG_USE_STD_FILESYSTEM vvv - if (rhs.is_absolute()) +#else // ^^^ VCPKG_USE_STD_FILESYSTEM || !windows // !VCPKG_USE_STD_FILESYSTEM && windows vvv + auto rhs_root_directory = rhs.root_directory(); + auto rhs_root_name = rhs.root_name(); + + if (rhs_root_directory.empty() && rhs_root_name.empty()) { - return rhs; + return lhs / rhs; } - else if (!rhs.root_directory().empty()) + else if (rhs_root_directory.empty()) { + // !rhs_root_name.empty() + if (rhs_root_name == lhs.root_name()) + { + return lhs / rhs.relative_path(); + } + else + { + return rhs; + } + } + else if (rhs_root_name.empty()) + { + // !rhs_root_directory.empty() return lhs.root_name() / rhs; } else { - return lhs / rhs; + // rhs.absolute() + return rhs; } #endif } diff --git a/toolsrc/src/vcpkg/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp index 8673da874be5f6..63cb57a1586a03 100644 --- a/toolsrc/src/vcpkg/paragraphs.cpp +++ b/toolsrc/src/vcpkg/paragraphs.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -344,6 +345,25 @@ namespace vcpkg::Paragraphs return pghs.error(); } + static void load_port_names_from_root(std::vector& ports, + const VcpkgPaths& paths, + const fs::path& registry_root) + { + const auto& fs = paths.get_filesystem(); + auto port_dirs = fs.get_files_non_recursive(registry_root); + Util::sort(port_dirs); + + // TODO: search in `b-` for ports starting with `b` + Util::erase_remove_if(port_dirs, [&](auto&& port_dir_entry) { + return fs.is_regular_file(port_dir_entry) && port_dir_entry.filename() == ".DS_Store"; + }); + + for (auto&& path : port_dirs) + { + ports.push_back(fs::u8string(path.filename())); + } + } + LoadResults try_load_all_ports(const VcpkgPaths& paths) { LoadResults ret; @@ -351,28 +371,15 @@ namespace vcpkg::Paragraphs std::vector ports; - auto load_port_names = [&fs, &ports, &paths](const RegistryImpl& r) { - auto port_dirs = fs.get_files_non_recursive(r.get_registry_root(paths)); - Util::sort(port_dirs); - Util::erase_remove_if(port_dirs, [&](auto&& port_dir_entry) { - return fs.is_regular_file(port_dir_entry) && port_dir_entry.filename() == ".DS_Store"; - }); - - for (auto&& path : port_dirs) - { - ports.push_back(fs::u8string(path.filename())); - } - }; - - const auto& registries = paths.get_configuration().registries; + const auto& registries = paths.get_configuration().registry_set; for (const auto& registry : registries.registries()) { - load_port_names(registry.implementation()); + load_port_names_from_root(ports, paths, registry.implementation().get_registry_root(paths)); } if (auto registry = registries.default_registry()) { - load_port_names(*registry); + load_port_names_from_root(ports, paths, registry->get_registry_root(paths)); } Util::sort_unique_erase(ports); @@ -382,13 +389,24 @@ namespace vcpkg::Paragraphs auto impl = registries.registry_for_port(port_name); if (!impl) { - // registry for port must be broken - Checks::unreachable(VCPKG_LINE_INFO); + // this is a port for which no registry is set + // this can happen when there's no default registry, + // and a registry has a port definition which it doesn't own the name of. + continue; } auto root = impl->get_registry_root(paths); auto port_path = root / fs::u8path(port_name); + + if (!fs.exists(port_path)) + { + // the registry that owns the name of this port does not actually contain the port + // this can happen if R1 contains the port definition for , but doesn't + // declare it owns . + continue; + } + auto maybe_spgh = try_load_port(fs, port_path); if (const auto spgh = maybe_spgh.get()) { @@ -435,19 +453,18 @@ namespace vcpkg::Paragraphs { LoadResults ret; + std::vector port_names; + load_port_names_from_root(port_names, paths, directory); + const auto& fs = paths.get_filesystem(); - auto port_dirs = fs.get_files_non_recursive(directory); - Util::sort(port_dirs); - Util::erase_remove_if(port_dirs, [&](auto&& port_dir_entry) { - return fs.is_regular_file(port_dir_entry) && port_dir_entry.filename() == ".DS_Store"; - }); - for (const auto& path : port_dirs) + for (const auto& name : port_names) { + auto path = directory / fs::u8path(name); auto maybe_spgh = try_load_port(fs, path); if (const auto spgh = maybe_spgh.get()) { - ret.paragraphs.emplace_back(std::move(*spgh), path); + ret.paragraphs.emplace_back(std::move(*spgh), std::move(path)); } else { diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index 85ac4ff58bd071..aa19f67702c20d 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -122,7 +123,7 @@ namespace vcpkg::PortFileProvider } } - if (auto registry = paths.get_configuration().registries.registry_for_port(spec)) + if (auto registry = paths.get_configuration().registry_set.registry_for_port(spec)) { auto registry_root = registry->get_registry_root(paths); auto port_directory = registry_root / fs::u8path(spec); diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index 77128115a9b2d9..f18ecf932d6a71 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -107,4 +107,24 @@ namespace vcpkg return Registry{std::move(packages), std::move(impl).value_or_exit(VCPKG_LINE_INFO)}; } + + RegistrySet::RegistrySet() : default_registry_(Registry::builtin_registry()), registries_() { } + + const RegistryImpl* RegistrySet::registry_for_port(StringView name) const + { + for (const auto& registry : registries()) + { + const auto& packages = registry.packages(); + if (std::find(packages.begin(), packages.end(), name) != packages.end()) + { + return ®istry.implementation(); + } + } + return default_registry(); + } + + void RegistrySet::add_registry(Registry&& r) { registries_.push_back(std::move(r)); } + + void RegistrySet::set_default_registry(std::unique_ptr&& r) { default_registry_ = std::move(r); } + void RegistrySet::set_default_registry(std::nullptr_t) { default_registry_.reset(); } } diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index e43673d3dc3d14..6c2e26d4a409ed 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -83,39 +84,6 @@ namespace namespace vcpkg { - RegistrySet::RegistrySet() : default_registry_(Registry::builtin_registry()), registries_() { } - - RegistrySet::RegistrySet(RegistrySet&&) noexcept = default; - RegistrySet& RegistrySet::operator=(RegistrySet&&) noexcept = default; - RegistrySet::~RegistrySet() = default; - - void swap(RegistrySet& lhs, RegistrySet& rhs) noexcept - { - swap(lhs.registries_, rhs.registries_); - swap(lhs.default_registry_, rhs.default_registry_); - } - - const RegistryImpl* RegistrySet::registry_for_port(StringView name) const - { - for (const auto& registry : registries()) - { - const auto& packages = registry.packages(); - if (std::find(packages.begin(), packages.end(), name) != packages.end()) - { - return ®istry.implementation(); - } - } - return default_registry(); - } - - void RegistrySet::add_registry(Registry&& r) { registries_.push_back(std::move(r)); } - - void RegistrySet::set_default_registry(std::unique_ptr&& r) { default_registry_ = std::move(r); } - void RegistrySet::set_default_registry(std::nullptr_t) { default_registry_.reset(); } - - // this is defined here so that we can see the definition of `Registry` - Span RegistrySet::registries() const { return registries_; } - struct ConfigurationDeserializer final : Json::IDeserializer { virtual StringView type_name() const override { return "a configuration object"; } @@ -205,8 +173,14 @@ namespace vcpkg return std::move(parsed_config_opt).value_or_exit(VCPKG_LINE_INFO); } - static std::pair>, std::pair> - load_manifest_and_config(const Files::Filesystem& fs, const fs::path& manifest_dir) + struct ManifestAndConfig + { + std::pair manifest_and_style; + fs::path config_directory; + Configuration config; + }; + + static ManifestAndConfig load_manifest_and_config(const Files::Filesystem& fs, const fs::path& manifest_dir) { std::error_code ec; auto manifest_path = manifest_dir / fs::u8path("vcpkg.json"); @@ -298,12 +272,11 @@ namespace vcpkg if (auto c = config_obj.get()) { - std::pair config = {std::move(config_dir), load_config(*c)}; - return {std::move(manifest), std::move(config)}; + return {std::move(manifest), std::move(config_dir), load_config(*c)}; } else { - return {std::move(manifest), std::pair{}}; + return {std::move(manifest), {}, {}}; } } @@ -393,9 +366,9 @@ namespace vcpkg } auto manifest_and_config = load_manifest_and_config(filesystem, manifest_root_dir); - m_pimpl->m_manifest_doc = std::move(manifest_and_config.first); - config_root_dir = std::move(manifest_and_config.second.first); - m_pimpl->m_config = std::move(manifest_and_config.second.second); + m_pimpl->m_manifest_doc = std::move(manifest_and_config.manifest_and_style); + config_root_dir = std::move(manifest_and_config.config_directory); + m_pimpl->m_config = std::move(manifest_and_config.config); } else { From 24bc8150aeacaacf44856fcdb4e44181dfd61655 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 31 Aug 2020 10:50:06 -0700 Subject: [PATCH 15/18] fix combine on linux --- toolsrc/src/vcpkg/base/files.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 560de393275fff..42efd473f3f0c9 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -1151,9 +1151,19 @@ namespace vcpkg::Files fs::path combine(const fs::path& lhs, const fs::path& rhs) { -#if VCPKG_USE_STD_FILESYSTEM || !defined(_MSC_VER) +#if VCPKG_USE_STD_FILESYSTEM return lhs / rhs; -#else // ^^^ VCPKG_USE_STD_FILESYSTEM || !windows // !VCPKG_USE_STD_FILESYSTEM && windows vvv +#else // ^^^ std::filesystem // std::experimental::filesystem vvv +#if !defined(_WIN32) + if (rhs.is_absolute()) + { + return rhs; + } + else + { + return lhs / rhs; + } +#else // ^^^ unix // windows vvv auto rhs_root_directory = rhs.root_directory(); auto rhs_root_name = rhs.root_name(); @@ -1183,6 +1193,7 @@ namespace vcpkg::Files // rhs.absolute() return rhs; } -#endif +#endif // ^^^ windows +#endif // ^^^ std::experimental::filesystem } } From 81e31ed0ccc6c74836160a517833ddcb99cbb1bb Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 31 Aug 2020 15:00:51 -0700 Subject: [PATCH 16/18] Change how vcpkg-configuration works after discussion with team We had a serious discussion today, and so the way we're going forward with this is very different -- no longer having a `"configuration"` field, adding inheritance, etc. Check the RFC for more info on how this will be done in the future; for the MVP, all it changes (fundamentally) is where the configuration stuff gets set -- it's in vcpkg-configuration.json in the manifest root. --- toolsrc/include/vcpkg/base/json.h | 1 + toolsrc/include/vcpkg/configuration.h | 25 +++ toolsrc/include/vcpkg/vcpkgcmdarguments.h | 3 + .../src/vcpkg/commands.format-manifest.cpp | 15 -- toolsrc/src/vcpkg/configuration.cpp | 66 +++++++ toolsrc/src/vcpkg/sourceparagraph.cpp | 2 - toolsrc/src/vcpkg/vcpkgcmdarguments.cpp | 3 + toolsrc/src/vcpkg/vcpkgpaths.cpp | 187 +++++------------- .../vcpkglib/vcpkglib.vcxproj | 1 + 9 files changed, 145 insertions(+), 158 deletions(-) create mode 100644 toolsrc/src/vcpkg/configuration.cpp diff --git a/toolsrc/include/vcpkg/base/json.h b/toolsrc/include/vcpkg/base/json.h index ef5bf34aab9025..3539f2df4d49e9 100644 --- a/toolsrc/include/vcpkg/base/json.h +++ b/toolsrc/include/vcpkg/base/json.h @@ -526,6 +526,7 @@ namespace vcpkg::Json template Optional visit_value(const Object& value, StringView key, IDeserializer& visitor) { + check_for_unexpected_fields(value, visitor.valid_fields(), visitor.type_name()); return visitor.visit_object(*this, key, value); } template diff --git a/toolsrc/include/vcpkg/configuration.h b/toolsrc/include/vcpkg/configuration.h index 4cba88fe5e06e5..44440fa04d0559 100644 --- a/toolsrc/include/vcpkg/configuration.h +++ b/toolsrc/include/vcpkg/configuration.h @@ -1,6 +1,9 @@ #pragma once #include +#include + +#include #include @@ -13,4 +16,26 @@ namespace vcpkg // taken care of in RegistrySet. RegistrySet registry_set; }; + + struct ConfigurationDeserializer final : Json::IDeserializer + { + virtual StringView type_name() const override { return "a configuration object"; } + + constexpr static StringLiteral DEFAULT_REGISTRY = "default-registry"; + constexpr static StringLiteral REGISTRIES = "registries"; + virtual Span valid_fields() const override + { + constexpr static StringView t[] = {DEFAULT_REGISTRY, REGISTRIES}; + return t; + } + + virtual Optional visit_object(Json::Reader& r, StringView, const Json::Object& obj) override; + + ConfigurationDeserializer(const VcpkgCmdArguments& args); + + private: + bool print_json; + + bool registries_enabled; + }; } diff --git a/toolsrc/include/vcpkg/vcpkgcmdarguments.h b/toolsrc/include/vcpkg/vcpkgcmdarguments.h index 3e956c83e5048a..626e598be6f58c 100644 --- a/toolsrc/include/vcpkg/vcpkgcmdarguments.h +++ b/toolsrc/include/vcpkg/vcpkgcmdarguments.h @@ -170,9 +170,12 @@ namespace vcpkg Optional compiler_tracking = nullopt; constexpr static StringLiteral MANIFEST_MODE_FEATURE = "manifests"; Optional manifest_mode = nullopt; + constexpr static StringLiteral REGISTRIES_FEATURE = "registries"; + Optional registries_feature = nullopt; bool binary_caching_enabled() const { return binary_caching.value_or(true); } bool compiler_tracking_enabled() const { return compiler_tracking.value_or(true); } + bool registries_enabled() const { return registries_feature.value_or(false); } bool output_json() const { return json.value_or(false); } std::string command; diff --git a/toolsrc/src/vcpkg/commands.format-manifest.cpp b/toolsrc/src/vcpkg/commands.format-manifest.cpp index d72e1e46078668..24beae0d8f29ad 100644 --- a/toolsrc/src/vcpkg/commands.format-manifest.cpp +++ b/toolsrc/src/vcpkg/commands.format-manifest.cpp @@ -17,7 +17,6 @@ namespace struct ToWrite { SourceControlFile scf; - Optional config; fs::path file_to_write; fs::path original_path; std::string original_source; @@ -53,15 +52,8 @@ namespace return nullopt; } - Optional config; - if (auto conf = parsed_json_obj.get("configuration")) - { - config = std::move(*conf); - } - return ToWrite{ std::move(*scf.value_or_exit(VCPKG_LINE_INFO)), - std::move(config), manifest_path, manifest_path, std::move(contents), @@ -99,7 +91,6 @@ namespace return ToWrite{ std::move(*scf_res.value_or_exit(VCPKG_LINE_INFO)), - nullopt, manifest_path, control_path, std::move(contents), @@ -163,12 +154,6 @@ Please open an issue at https://github.com/microsoft/vcpkg, with the following o Json::stringify(serialize_debug_manifest(*check_scf), {})); } - if (auto conf = data.config.get()) - { - // note: we don't yet canonicalize config - res.insert("configuration", std::move(*conf)); - } - // the manifest scf is correct std::error_code ec; fs.write_contents(data.file_to_write, Json::stringify(res, {}), ec); diff --git a/toolsrc/src/vcpkg/configuration.cpp b/toolsrc/src/vcpkg/configuration.cpp new file mode 100644 index 00000000000000..8b0b4101c37207 --- /dev/null +++ b/toolsrc/src/vcpkg/configuration.cpp @@ -0,0 +1,66 @@ +#include + +#include +#include + +namespace vcpkg +{ + Optional ConfigurationDeserializer::visit_object(Json::Reader& r, + StringView, + const Json::Object& obj) + { + RegistrySet registries; + + bool registries_feature_flags_warning = false; + + { + std::unique_ptr default_registry; + if (r.optional_object_field(obj, DEFAULT_REGISTRY, default_registry, RegistryImplDeserializer{})) + { + if (!registries_enabled) + { + registries_feature_flags_warning = true; + } + else + { + registries.set_default_registry(std::move(default_registry)); + } + } + } + + std::vector regs; + r.optional_object_field( + obj, + REGISTRIES, + regs, + Json::ArrayDeserializer{"an array of registries", Json::AllowEmpty::Yes}); + + if (!regs.empty() && !registries_enabled) + { + registries_feature_flags_warning = true; + regs.clear(); + } + + for (Registry& reg : regs) + { + registries.add_registry(std::move(reg)); + } + + if (registries_feature_flags_warning && !print_json) + { + System::printf( + System::Color::warning, + "Warning: configuration specified the \"registries\" or \"default-registries\" field, but the %s feature flag was not enabled.\n", + VcpkgCmdArguments::REGISTRIES_FEATURE); + } + + return Configuration{std::move(registries)}; + } + + ConfigurationDeserializer::ConfigurationDeserializer(const VcpkgCmdArguments& args) + { + registries_enabled = args.registries_enabled(); + print_json = args.output_json(); + } + +} diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 7100571a973ea0..15b5a46384de85 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -640,7 +640,6 @@ namespace vcpkg constexpr static StringLiteral FEATURES = "features"; constexpr static StringLiteral DEFAULT_FEATURES = "default-features"; constexpr static StringLiteral SUPPORTS = "supports"; - constexpr static StringLiteral CONFIGURATION = "configuration"; virtual Span valid_fields() const override { @@ -659,7 +658,6 @@ namespace vcpkg FEATURES, DEFAULT_FEATURES, SUPPORTS, - CONFIGURATION, }; return t; diff --git a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp index 7377baafb33b71..18288104fed1c4 100644 --- a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp +++ b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp @@ -49,6 +49,7 @@ namespace vcpkg {VcpkgCmdArguments::BINARY_CACHING_FEATURE, args.binary_caching}, {VcpkgCmdArguments::MANIFEST_MODE_FEATURE, args.manifest_mode}, {VcpkgCmdArguments::COMPILER_TRACKING_FEATURE, args.compiler_tracking}, + {VcpkgCmdArguments::REGISTRIES_FEATURE, args.registries_feature}, }; for (const auto& desc : flag_descriptions) @@ -730,6 +731,7 @@ namespace vcpkg {BINARY_CACHING_FEATURE, binary_caching}, {MANIFEST_MODE_FEATURE, manifest_mode}, {COMPILER_TRACKING_FEATURE, compiler_tracking}, + {REGISTRIES_FEATURE, registries_feature}, }; for (const auto& flag : flags) @@ -754,6 +756,7 @@ namespace vcpkg } flags[] = { {BINARY_CACHING_FEATURE, binary_caching_enabled()}, {COMPILER_TRACKING_FEATURE, compiler_tracking_enabled()}, + {REGISTRIES_FEATURE, registries_enabled()}, }; for (const auto& flag : flags) diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 6c2e26d4a409ed..677ac1a092bc46 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -84,52 +84,13 @@ namespace namespace vcpkg { - struct ConfigurationDeserializer final : Json::IDeserializer - { - virtual StringView type_name() const override { return "a configuration object"; } - - constexpr static StringLiteral DEFAULT_REGISTRY = "default-registry"; - constexpr static StringLiteral REGISTRIES = "registries"; - virtual Span valid_fields() const override - { - constexpr static StringView t[] = {DEFAULT_REGISTRY, REGISTRIES}; - return t; - } - - virtual Optional visit_object(Json::Reader& r, StringView, const Json::Object& obj) override - { - RegistrySet registries; - - { - std::unique_ptr default_registry; - if (r.optional_object_field(obj, DEFAULT_REGISTRY, default_registry, RegistryImplDeserializer{})) - { - registries.set_default_registry(std::move(default_registry)); - } - } - - std::vector regs; - r.optional_object_field( - obj, - REGISTRIES, - regs, - Json::ArrayDeserializer{"an array of registries", Json::AllowEmpty::Yes}); - - for (Registry& reg : regs) - { - registries.add_registry(std::move(reg)); - } - - return Configuration{std::move(registries)}; - } - }; - - static Configuration load_config(const Json::Object& obj) + static Configuration deserialize_configuration(const Json::Object& obj, const VcpkgCmdArguments& args) { Json::BasicReaderError err; Json::Reader reader{&err}; + auto deserializer = ConfigurationDeserializer(args); - auto parsed_config_opt = reader.visit_value(obj, "$", ConfigurationDeserializer{}); + auto parsed_config_opt = reader.visit_value(obj, "$", deserializer); if (err.has_error()) { if (!err.missing_fields.empty()) @@ -175,12 +136,12 @@ namespace vcpkg struct ManifestAndConfig { - std::pair manifest_and_style; fs::path config_directory; Configuration config; }; - static ManifestAndConfig load_manifest_and_config(const Files::Filesystem& fs, const fs::path& manifest_dir) + static std::pair load_manifest(const Files::Filesystem& fs, + const fs::path& manifest_dir) { std::error_code ec; auto manifest_path = manifest_dir / fs::u8path("vcpkg.json"); @@ -210,74 +171,52 @@ namespace vcpkg ": Manifest files must have a top-level object\n"); Checks::exit_fail(VCPKG_LINE_INFO); } - std::pair manifest = {std::move(manifest_value.first.object()), - std::move(manifest_value.second)}; + return {std::move(manifest_value.first.object()), std::move(manifest_value.second)}; + } - Optional config_obj; + struct ConfigAndPath + { + fs::path config_directory; + Configuration config; + }; + + // doesn't yet implement searching upwards for configurations, nor inheritance of configurations + static ConfigAndPath load_configuration(const Files::Filesystem& fs, + const VcpkgCmdArguments& args, + const fs::path& vcpkg_root, + const fs::path& manifest_dir) + { fs::path config_dir; - if (auto p_manifest_config = manifest.first.get("configuration")) + if (!manifest_dir.empty()) { - if (p_manifest_config->is_object()) - { - config_obj = std::move(p_manifest_config->object()); - config_dir = manifest_dir; - } - else if (p_manifest_config->is_string()) - { - auto config_name = fs::u8path("vcpkg-configuration.json"); - auto config_relative_path = fs::u8path(p_manifest_config->string()); - if (config_relative_path.empty()) - { - System::print2(System::Color::error, "Invalid path to vcpkg-configuration: must not be empty.\n"); - Checks::exit_fail(VCPKG_LINE_INFO); - } - - if (!config_relative_path.root_path().empty()) - { - System::printf(System::Color::error, - "Invalid path to vcpkg-configuration '%s': must not be absolute.\n", - p_manifest_config->string()); - Checks::exit_fail(VCPKG_LINE_INFO); - } - - config_dir = manifest_dir / config_relative_path; - auto config_path = config_dir / config_name; - if (!fs.exists(config_path)) - { - System::printf( - System::Color::error, "Failed to find configuration file at %s\n", fs::u8string(config_path)); - Checks::exit_fail(VCPKG_LINE_INFO); - } - auto parsed_config = Json::parse_file(VCPKG_LINE_INFO, fs, config_path); - if (!parsed_config.first.is_object()) - { - System::print2(System::Color::error, - "Failed to parse ", - fs::u8string(config_path), - ": configuration files must have a top-level object\n"); - Checks::exit_fail(VCPKG_LINE_INFO); - } - config_obj = std::move(parsed_config.first.object()); - } - else - { - System::print2(System::Color::error, - "Failed to parse manifest at ", - fs::u8string(manifest_path), - ": Manifest configuration ($.configuration) must be a string or an object.\n"); - Checks::exit_fail(VCPKG_LINE_INFO); - } + // manifest mode + config_dir = manifest_dir; + } + else + { + // classic mode + config_dir = vcpkg_root; } - if (auto c = config_obj.get()) + auto path_to_config = config_dir / fs::u8path("vcpkg-configuration.json"); + if (!fs.exists(path_to_config)) { - return {std::move(manifest), std::move(config_dir), load_config(*c)}; + return {}; } - else + + auto parsed_config = Json::parse_file(VCPKG_LINE_INFO, fs, path_to_config); + if (!parsed_config.first.is_object()) { - return {std::move(manifest), {}, {}}; + System::print2(System::Color::error, + "Failed to parse ", + fs::u8string(path_to_config), + ": configuration files must have a top-level object\n"); + Checks::exit_fail(VCPKG_LINE_INFO); } + auto config_obj = std::move(parsed_config.first.object()); + + return {std::move(config_dir), deserialize_configuration(config_obj, args)}; } namespace details @@ -365,10 +304,7 @@ namespace vcpkg Checks::exit_fail(VCPKG_LINE_INFO); } - auto manifest_and_config = load_manifest_and_config(filesystem, manifest_root_dir); - m_pimpl->m_manifest_doc = std::move(manifest_and_config.manifest_and_style); - config_root_dir = std::move(manifest_and_config.config_directory); - m_pimpl->m_config = std::move(manifest_and_config.config); + m_pimpl->m_manifest_doc = load_manifest(filesystem, manifest_root_dir); } else { @@ -403,43 +339,12 @@ If you wish to silence this error and use classic mode, you can: manifest_root_dir.clear(); installed = process_output_directory(filesystem, root, args.install_root_dir.get(), "installed", VCPKG_LINE_INFO); + } - fs::path config_path = root / fs::u8path("vcpkg-configuration.json"); - if (filesystem.exists(config_path)) - { - auto config_object = Json::parse_file(filesystem, config_path, ec); - if (ec) - { - Checks::exit_with_message(VCPKG_LINE_INFO, - "Failed to load configuration file %s: %s", - fs::u8string(config_path), - ec.message()); - } + auto config_file = load_configuration(filesystem, args, root, manifest_root_dir); - if (auto c = config_object.get()) - { - if (c->first.is_object()) - { - m_pimpl->m_config = load_config(c->first.object()); - config_root_dir = root; - } - else - { - Checks::exit_with_message( - VCPKG_LINE_INFO, - "Error: failed to parse configuration file %s: configuration must have top-level object.", - fs::u8string(config_path)); - } - } - else - { - Checks::exit_with_message(VCPKG_LINE_INFO, - "Error: failed to parse configuration file %s: %s", - fs::u8string(config_path), - config_object.error()->format()); - } - } - } + config_root_dir = std::move(config_file.config_directory); + m_pimpl->m_config = std::move(config_file.config); buildtrees = process_output_directory(filesystem, root, args.buildtrees_root_dir.get(), "buildtrees", VCPKG_LINE_INFO); diff --git a/toolsrc/windows-bootstrap/vcpkglib/vcpkglib.vcxproj b/toolsrc/windows-bootstrap/vcpkglib/vcpkglib.vcxproj index ee276af03fa5e5..240b0115bc2a66 100644 --- a/toolsrc/windows-bootstrap/vcpkglib/vcpkglib.vcxproj +++ b/toolsrc/windows-bootstrap/vcpkglib/vcpkglib.vcxproj @@ -295,6 +295,7 @@ + From a1891089c58d6141094dadcce11fe73d728717cb Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 31 Aug 2020 15:40:54 -0700 Subject: [PATCH 17/18] formatting --- toolsrc/src/vcpkg/configuration.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/toolsrc/src/vcpkg/configuration.cpp b/toolsrc/src/vcpkg/configuration.cpp index 8b0b4101c37207..adc1f814d9cabe 100644 --- a/toolsrc/src/vcpkg/configuration.cpp +++ b/toolsrc/src/vcpkg/configuration.cpp @@ -48,10 +48,10 @@ namespace vcpkg if (registries_feature_flags_warning && !print_json) { - System::printf( - System::Color::warning, - "Warning: configuration specified the \"registries\" or \"default-registries\" field, but the %s feature flag was not enabled.\n", - VcpkgCmdArguments::REGISTRIES_FEATURE); + System::printf(System::Color::warning, + "Warning: configuration specified the \"registries\" or \"default-registries\" field, but " + "the %s feature flag was not enabled.\n", + VcpkgCmdArguments::REGISTRIES_FEATURE); } return Configuration{std::move(registries)}; From ca0ece45a79c27f38faff8e15523347c7c599063 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Tue, 1 Sep 2020 17:10:45 -0700 Subject: [PATCH 18/18] Robert's CRs --- toolsrc/include/vcpkg/paragraphs.h | 6 +++--- toolsrc/include/vcpkg/registries.h | 10 +--------- toolsrc/src/vcpkg/commands.ci.cpp | 2 +- toolsrc/src/vcpkg/commands.edit.cpp | 4 ++-- toolsrc/src/vcpkg/commands.portsdiff.cpp | 5 +++-- toolsrc/src/vcpkg/install.cpp | 6 +++--- toolsrc/src/vcpkg/paragraphs.cpp | 6 +++--- toolsrc/src/vcpkg/portfileprovider.cpp | 16 ++++++++-------- toolsrc/src/vcpkg/registries.cpp | 2 -- toolsrc/src/vcpkg/sourceparagraph.cpp | 6 +++--- 10 files changed, 27 insertions(+), 36 deletions(-) diff --git a/toolsrc/include/vcpkg/paragraphs.h b/toolsrc/include/vcpkg/paragraphs.h index a276b391d906a7..95726f9135ddf5 100644 --- a/toolsrc/include/vcpkg/paragraphs.h +++ b/toolsrc/include/vcpkg/paragraphs.h @@ -40,10 +40,10 @@ namespace vcpkg::Paragraphs return (*this)(*loc.source_control_file); } const std::string& operator()(const SourceControlFile& scf) const { return scf.core_paragraph->name; } - } name_of_paragraph; + } get_name_of_control_file; - LoadResults try_load_all_ports(const VcpkgPaths& paths); + LoadResults try_load_all_registry_ports(const VcpkgPaths& paths); - std::vector load_all_ports(const VcpkgPaths& paths); + std::vector load_all_registry_ports(const VcpkgPaths& paths); std::vector load_overlay_ports(const VcpkgPaths& paths, const fs::path& dir); } diff --git a/toolsrc/include/vcpkg/registries.h b/toolsrc/include/vcpkg/registries.h index 909d549ae85171..78c055daedfbb9 100644 --- a/toolsrc/include/vcpkg/registries.h +++ b/toolsrc/include/vcpkg/registries.h @@ -16,7 +16,6 @@ namespace vcpkg { struct RegistryImpl { - virtual void update(VcpkgPaths& paths, std::error_code& ec) const = 0; virtual fs::path get_registry_root(const VcpkgPaths& paths) const = 0; virtual ~RegistryImpl() = default; @@ -59,7 +58,6 @@ namespace vcpkg struct RegistryDeserializer final : Json::IDeserializer { - // constexpr static StringLiteral SCOPES = "scopes"; constexpr static StringLiteral PACKAGES = "packages"; virtual StringView type_name() const override; @@ -73,17 +71,11 @@ namespace vcpkg // that it is the registry for that port name, else it maps to the default registry // if that registry exists; else, there is no registry for a port. // The way one sets this up is via the `"registries"` and `"default_registry"` - // configuration settings. + // configuration fields. struct RegistrySet { RegistrySet(); - friend void swap(RegistrySet& lhs, RegistrySet& rhs) noexcept - { - swap(lhs.registries_, rhs.registries_); - swap(lhs.default_registry_, rhs.default_registry_); - } - // finds the correct registry for the port name // Returns the null pointer if there is no registry set up for that name const RegistryImpl* registry_for_port(StringView port_name) const; diff --git a/toolsrc/src/vcpkg/commands.ci.cpp b/toolsrc/src/vcpkg/commands.ci.cpp index 568c086621049c..ee7b4d4a0d8208 100644 --- a/toolsrc/src/vcpkg/commands.ci.cpp +++ b/toolsrc/src/vcpkg/commands.ci.cpp @@ -458,7 +458,7 @@ namespace vcpkg::Commands::CI XunitTestResults xunitTestResults; std::vector all_ports = - Util::fmap(provider.load_all_control_files(), Paragraphs::name_of_paragraph); + Util::fmap(provider.load_all_control_files(), Paragraphs::get_name_of_control_file); std::vector results; auto timer = Chrono::ElapsedTimer::create_started(); for (Triplet triplet : triplets) diff --git a/toolsrc/src/vcpkg/commands.edit.cpp b/toolsrc/src/vcpkg/commands.edit.cpp index 0be0c461ef2aac..7ee74eae09a529 100644 --- a/toolsrc/src/vcpkg/commands.edit.cpp +++ b/toolsrc/src/vcpkg/commands.edit.cpp @@ -85,9 +85,9 @@ namespace vcpkg::Commands::Edit static std::vector valid_arguments(const VcpkgPaths& paths) { - auto sources_and_errors = Paragraphs::try_load_all_ports(paths); + auto sources_and_errors = Paragraphs::try_load_all_registry_ports(paths); - return Util::fmap(sources_and_errors.paragraphs, Paragraphs::name_of_paragraph); + return Util::fmap(sources_and_errors.paragraphs, Paragraphs::get_name_of_control_file); } static constexpr std::array EDIT_SWITCHES = { diff --git a/toolsrc/src/vcpkg/commands.portsdiff.cpp b/toolsrc/src/vcpkg/commands.portsdiff.cpp index 9ff719c709c40e..392ca70ddb5c87 100644 --- a/toolsrc/src/vcpkg/commands.portsdiff.cpp +++ b/toolsrc/src/vcpkg/commands.portsdiff.cpp @@ -100,9 +100,10 @@ namespace vcpkg::Commands::PortsDiff System::cmd_execute_and_capture_output(cmd, System::get_clean_environment()); System::cmd_execute_and_capture_output(Strings::format(R"("%s" reset)", fs::u8string(git_exe)), System::get_clean_environment()); - const auto all_ports = Paragraphs::load_overlay_ports(paths, temp_checkout_path / ports_dir_name_as_string); + const auto ports_at_commit = + Paragraphs::load_overlay_ports(paths, temp_checkout_path / ports_dir_name_as_string); std::map names_and_versions; - for (auto&& port : all_ports) + for (auto&& port : ports_at_commit) { const auto& core_pgh = *port.source_control_file->core_paragraph; names_and_versions.emplace(core_pgh.name, VersionT(core_pgh.version, core_pgh.port_version)); diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index 925a722febef37..cc0b6b93139628 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -551,9 +551,9 @@ namespace vcpkg::Install std::vector get_all_port_names(const VcpkgPaths& paths) { - auto sources_and_errors = Paragraphs::try_load_all_ports(paths); + auto sources_and_errors = Paragraphs::try_load_all_registry_ports(paths); - return Util::fmap(sources_and_errors.paragraphs, Paragraphs::name_of_paragraph); + return Util::fmap(sources_and_errors.paragraphs, Paragraphs::get_name_of_control_file); } const CommandStructure COMMAND_STRUCTURE = { @@ -794,7 +794,7 @@ namespace vcpkg::Install { print_error_message(maybe_manifest_scf.error()); Checks::exit_with_message( - VCPKG_LINE_INFO, "Failed to read manifest %s/vcpkg.json.", fs::u8string(paths.manifest_root_dir)); + VCPKG_LINE_INFO, "Failed to parse manifest %s/vcpkg.json.", fs::u8string(paths.manifest_root_dir)); } auto& manifest_scf = *maybe_manifest_scf.value_or_exit(VCPKG_LINE_INFO); diff --git a/toolsrc/src/vcpkg/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp index 63cb57a1586a03..19c1d266db4c35 100644 --- a/toolsrc/src/vcpkg/paragraphs.cpp +++ b/toolsrc/src/vcpkg/paragraphs.cpp @@ -364,7 +364,7 @@ namespace vcpkg::Paragraphs } } - LoadResults try_load_all_ports(const VcpkgPaths& paths) + LoadResults try_load_all_registry_ports(const VcpkgPaths& paths) { LoadResults ret; const auto& fs = paths.get_filesystem(); @@ -442,9 +442,9 @@ namespace vcpkg::Paragraphs } } - std::vector load_all_ports(const VcpkgPaths& paths) + std::vector load_all_registry_ports(const VcpkgPaths& paths) { - auto results = try_load_all_ports(paths); + auto results = try_load_all_registry_ports(paths); load_results_print_error(results); return std::move(results.paragraphs); } diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index aa19f67702c20d..0e065eff703378 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -190,25 +190,25 @@ namespace vcpkg::PortFileProvider } // Try loading all ports inside ports_dir - auto found_scf = Paragraphs::load_overlay_ports(paths, ports_dir); - for (auto&& scf : found_scf) + auto found_scfls = Paragraphs::load_overlay_ports(paths, ports_dir); + for (auto&& scfl : found_scfls) { - auto port_name = scf.source_control_file->core_paragraph->name; + auto port_name = scfl.source_control_file->core_paragraph->name; if (cache.find(port_name) == cache.end()) { - auto it = cache.emplace(std::move(port_name), std::move(scf)); + auto it = cache.emplace(std::move(port_name), std::move(scfl)); ret.emplace_back(&it.first->second); } } } - auto all_ports = Paragraphs::load_all_ports(paths); - for (auto&& scf : all_ports) + auto all_ports = Paragraphs::load_all_registry_ports(paths); + for (auto&& scfl : all_ports) { - auto port_name = scf.source_control_file->core_paragraph->name; + auto port_name = scfl.source_control_file->core_paragraph->name; if (cache.find(port_name) == cache.end()) { - auto it = cache.emplace(port_name, std::move(scf)); + auto it = cache.emplace(port_name, std::move(scfl)); ret.emplace_back(&it.first->second); } } diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index f18ecf932d6a71..5df38e6ef12a7d 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -6,13 +6,11 @@ namespace { struct BuiltinRegistry final : vcpkg::RegistryImpl { - virtual void update(vcpkg::VcpkgPaths&, std::error_code& ec) const override { ec.clear(); } virtual fs::path get_registry_root(const vcpkg::VcpkgPaths& paths) const override { return paths.ports; } }; struct DirectoryRegistry final : vcpkg::RegistryImpl { - virtual void update(vcpkg::VcpkgPaths&, std::error_code& ec) const override { ec.clear(); } virtual fs::path get_registry_root(const vcpkg::VcpkgPaths& paths) const override { return vcpkg::Files::combine(paths.config_root_dir, path); diff --git a/toolsrc/src/vcpkg/sourceparagraph.cpp b/toolsrc/src/vcpkg/sourceparagraph.cpp index 15b5a46384de85..a00fd757916876 100644 --- a/toolsrc/src/vcpkg/sourceparagraph.cpp +++ b/toolsrc/src/vcpkg/sourceparagraph.cpp @@ -388,7 +388,7 @@ namespace vcpkg virtual Span valid_fields() const override { - const static StringView t[] = { + static const StringView t[] = { NAME, FEATURES, DEFAULT_FEATURES, @@ -452,7 +452,7 @@ namespace vcpkg virtual Span valid_fields() const override { - const static StringView t[] = {NAME, DESCRIPTION, DEPENDENCIES}; + static const StringView t[] = {NAME, DESCRIPTION, DEPENDENCIES}; return t; } @@ -643,7 +643,7 @@ namespace vcpkg virtual Span valid_fields() const override { - const static StringView t[] = { + static const StringView t[] = { NAME, VERSION,