From ba1771458b17c623179a80949db85863bf30d218 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 14 Dec 2020 14:47:23 -0800 Subject: [PATCH 01/16] [vcpkg registries] support versions This PR merges the Registries changes and the versioning changes, so that one can use both at the same time. There is one major difference between this PR and the RFC (#13590), which is that instead of version files looking like: ```json [ ... ] ``` version files look like: ``` { "versions": [ ... ] } ``` this is to support interop between this PR and existing demos and the like; fixing this, along with perhaps renaming `port_versions` to `port-versions` should be done after this is merged, should be a trivial change. --- toolsrc/include/vcpkg/base/files.h | 1 + toolsrc/include/vcpkg/base/jsonreader.h | 2 +- .../include/vcpkg/configurationdeserializer.h | 33 +- toolsrc/include/vcpkg/fwd/registries.h | 3 +- toolsrc/include/vcpkg/portfileprovider.h | 12 +- toolsrc/include/vcpkg/registries.h | 35 +- toolsrc/include/vcpkg/sourceparagraph.h | 2 +- toolsrc/include/vcpkg/vcpkgpaths.h | 2 +- toolsrc/include/vcpkg/versiondeserializers.h | 17 +- toolsrc/src/vcpkg-test/dependencies.cpp | 5 +- toolsrc/src/vcpkg/base/files.cpp | 8 +- toolsrc/src/vcpkg/configuration.cpp | 23 +- toolsrc/src/vcpkg/install.cpp | 19 +- toolsrc/src/vcpkg/paragraphs.cpp | 11 +- toolsrc/src/vcpkg/portfileprovider.cpp | 355 +++---- toolsrc/src/vcpkg/registries.cpp | 956 ++++++++++++++---- toolsrc/src/vcpkg/vcpkgpaths.cpp | 18 +- toolsrc/src/vcpkg/versiondeserializers.cpp | 137 +-- toolsrc/src/vcpkg/versions.cpp | 2 +- 19 files changed, 988 insertions(+), 653 deletions(-) diff --git a/toolsrc/include/vcpkg/base/files.h b/toolsrc/include/vcpkg/base/files.h index b05f79a05b668a..baa6f0f9ec59fa 100644 --- a/toolsrc/include/vcpkg/base/files.h +++ b/toolsrc/include/vcpkg/base/files.h @@ -236,6 +236,7 @@ namespace vcpkg::Files void current_path(const fs::path& path, LineInfo li); // waits forever for the file lock + // creates a non-existent file virtual fs::SystemHandle take_exclusive_file_lock(const fs::path& path, std::error_code&) = 0; // waits, at most, 1.5 seconds, for the file lock virtual fs::SystemHandle try_take_exclusive_file_lock(const fs::path& path, std::error_code&) = 0; diff --git a/toolsrc/include/vcpkg/base/jsonreader.h b/toolsrc/include/vcpkg/base/jsonreader.h index bea60e7ce5b644..da086fa028cf9f 100644 --- a/toolsrc/include/vcpkg/base/jsonreader.h +++ b/toolsrc/include/vcpkg/base/jsonreader.h @@ -75,13 +75,13 @@ namespace vcpkg::Json }; std::vector m_path; + public: // 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, View valid_fields, StringView type_name); - public: template void required_object_field( StringView type, const Object& obj, StringView key, Type& place, IDeserializer& visitor) diff --git a/toolsrc/include/vcpkg/configurationdeserializer.h b/toolsrc/include/vcpkg/configurationdeserializer.h index d6b2393567a432..8d978e1ea270bc 100644 --- a/toolsrc/include/vcpkg/configurationdeserializer.h +++ b/toolsrc/include/vcpkg/configurationdeserializer.h @@ -15,32 +15,11 @@ 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_FILESYSTEM = "filesystem"; - - virtual StringView type_name() const override; - virtual View valid_fields() const override; + std::unique_ptr>> + get_registry_implementation_deserializer(const fs::path& configuration_directory); - virtual Optional> visit_null(Json::Reader&) override; - virtual Optional> visit_object(Json::Reader&, const Json::Object&) override; - - static RegistryImplDeserializer instance; - }; - - struct RegistryDeserializer final : Json::IDeserializer - { - constexpr static StringLiteral PACKAGES = "packages"; - - virtual StringView type_name() const override; - virtual View valid_fields() const override; - - virtual Optional visit_object(Json::Reader&, const Json::Object&) override; - }; + std::unique_ptr>> get_registry_array_deserializer( + const fs::path& configuration_directory); struct ConfigurationDeserializer final : Json::IDeserializer { @@ -56,11 +35,13 @@ namespace vcpkg virtual Optional visit_object(Json::Reader& r, const Json::Object& obj) override; - ConfigurationDeserializer(const VcpkgCmdArguments& args); + ConfigurationDeserializer(const VcpkgCmdArguments& args, const fs::path& configuration_directory); private: bool print_json; bool registries_enabled; + + fs::path configuration_directory; }; } diff --git a/toolsrc/include/vcpkg/fwd/registries.h b/toolsrc/include/vcpkg/fwd/registries.h index 7352c429d175f4..73783cc6bb5bf4 100644 --- a/toolsrc/include/vcpkg/fwd/registries.h +++ b/toolsrc/include/vcpkg/fwd/registries.h @@ -2,7 +2,8 @@ namespace vcpkg { - struct RegistryImpl; + struct RegistryEntry; + struct RegistryImplementation; struct Registry; struct RegistrySet; } diff --git a/toolsrc/include/vcpkg/portfileprovider.h b/toolsrc/include/vcpkg/portfileprovider.h index 1ce934c9eabecf..1f40be88988a1f 100644 --- a/toolsrc/include/vcpkg/portfileprovider.h +++ b/toolsrc/include/vcpkg/portfileprovider.h @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -40,10 +41,10 @@ namespace vcpkg::PortFileProvider struct IVersionedPortfileProvider { - virtual const std::vector& get_port_versions(StringView port_name) const = 0; + virtual View get_port_versions(StringView port_name) const = 0; virtual ExpectedS get_control_file( - const vcpkg::Versions::VersionSpec& version_spec) const = 0; + const Versions::VersionSpec& version_spec) const = 0; }; struct IBaselineProvider @@ -62,19 +63,18 @@ namespace vcpkg::PortFileProvider explicit VersionedPortfileProvider(const vcpkg::VcpkgPaths& paths); ~VersionedPortfileProvider(); - const std::vector& get_port_versions(StringView port_name) const override; + View get_port_versions(StringView port_name) const override; ExpectedS get_control_file( - const vcpkg::Versions::VersionSpec& version_spec) const override; + const Versions::VersionSpec& version) const override; private: std::unique_ptr m_impl; }; - struct BaselineProvider : IBaselineProvider, Util::ResourceBase + struct BaselineProvider final : IBaselineProvider, Util::ResourceBase { explicit BaselineProvider(const vcpkg::VcpkgPaths& paths); - BaselineProvider(const vcpkg::VcpkgPaths& paths, const std::string& baseline); ~BaselineProvider(); Optional get_baseline_version(StringView port_name) const override; diff --git a/toolsrc/include/vcpkg/registries.h b/toolsrc/include/vcpkg/registries.h index 1f8c0f393b13a8..2acfdc941d9775 100644 --- a/toolsrc/include/vcpkg/registries.h +++ b/toolsrc/include/vcpkg/registries.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -17,40 +18,46 @@ namespace vcpkg { struct RegistryEntry { - // returns fs::path() if version doesn't exist - virtual fs::path get_port_directory(const VcpkgPaths& paths, const VersionT& version) const = 0; + virtual View get_port_versions() const = 0; + + // precondition: version \in get_port_versions(). Otherwise, this function asserts. + virtual ExpectedS get_path_to_version(const VcpkgPaths& paths, const VersionT& version) const = 0; virtual ~RegistryEntry() = default; }; - struct RegistryImpl + struct RegistryImplementation { // returns nullptr if the port doesn't exist virtual std::unique_ptr get_port_entry(const VcpkgPaths& paths, StringView port_name) const = 0; + // appends the names of the ports to the out parameter + // may result in duplicated port names; make sure to Util::sort_unique_erase at the end virtual void get_all_port_names(std::vector& port_names, const VcpkgPaths& paths) const = 0; virtual Optional get_baseline_version(const VcpkgPaths& paths, StringView port_name) const = 0; - virtual ~RegistryImpl() = default; + virtual ~RegistryImplementation() = default; }; struct Registry { // requires: static_cast(implementation) - Registry(std::vector&& packages, std::unique_ptr&& implementation); + Registry(std::vector&& packages, std::unique_ptr&& implementation); Registry(std::vector&&, std::nullptr_t) = delete; // always ordered lexicographically View packages() const { return packages_; } - const RegistryImpl& implementation() const { return *implementation_; } + const RegistryImplementation& implementation() const { return *implementation_; } - static std::unique_ptr builtin_registry(); + static std::unique_ptr builtin_registry(std::string&& baseline = {}); + + friend RegistrySet; // for experimental_set_builtin_registry_baseline private: std::vector packages_; - std::unique_ptr implementation_; + std::unique_ptr implementation_; }; // this type implements the registry fall back logic from the registries RFC: @@ -65,19 +72,23 @@ 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 RegistryImpl* registry_for_port(StringView port_name) const; + const RegistryImplementation* registry_for_port(StringView port_name) const; + Optional baseline_for_port(const VcpkgPaths& paths, StringView port_name) const; View registries() const { return registries_; } - const RegistryImpl* default_registry() const { return default_registry_.get(); } + const RegistryImplementation* 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::unique_ptr&& r); void set_default_registry(std::nullptr_t r); + // this exists in order to allow versioning and registries to be developed and tested separately + void experimental_set_builtin_registry_baseline(StringView baseline) const; + private: - std::unique_ptr default_registry_; + std::unique_ptr default_registry_; std::vector registries_; }; diff --git a/toolsrc/include/vcpkg/sourceparagraph.h b/toolsrc/include/vcpkg/sourceparagraph.h index ee07826bba2842..b181c642a0498e 100644 --- a/toolsrc/include/vcpkg/sourceparagraph.h +++ b/toolsrc/include/vcpkg/sourceparagraph.h @@ -117,7 +117,7 @@ namespace vcpkg /// /// Full metadata of a package: core and other features. As well as the location the SourceControlFile was - /// loaded from. + /// loaded from (the port directory, not the actual CONTROL/vcpkg.json file). /// struct SourceControlFileLocation { diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h index 257ecf7bbd5c51..13a4867a45cfe8 100644 --- a/toolsrc/include/vcpkg/vcpkgpaths.h +++ b/toolsrc/include/vcpkg/vcpkgpaths.h @@ -115,7 +115,7 @@ namespace vcpkg const fs::path& get_tool_exe(const std::string& tool) const; const std::string& get_tool_version(const std::string& tool) const; - // Git manipulation + // Git manipulation in vcpkg directory fs::path git_checkout_baseline(Files::Filesystem& filesystem, StringView commit_sha) const; fs::path git_checkout_port(Files::Filesystem& filesystem, StringView port_name, StringView git_tree) const; ExpectedS git_show(const std::string& treeish, const fs::path& dot_git_dir) const; diff --git a/toolsrc/include/vcpkg/versiondeserializers.h b/toolsrc/include/vcpkg/versiondeserializers.h index 249d685cbbbb16..a6d42dab5d57a2 100644 --- a/toolsrc/include/vcpkg/versiondeserializers.h +++ b/toolsrc/include/vcpkg/versiondeserializers.h @@ -10,13 +10,6 @@ namespace vcpkg { - struct VersionDbEntry - { - VersionT version; - Versions::Scheme scheme = Versions::Scheme::String; - std::string git_tree; - }; - Json::IDeserializer& get_versiont_deserializer_instance(); std::unique_ptr> make_version_deserializer(StringLiteral type_name); @@ -39,12 +32,4 @@ namespace vcpkg const std::string& version, int port_version, bool always_emit_port_version = false); - - ExpectedS>> parse_baseline_file(Files::Filesystem& fs, - StringView baseline_name, - const fs::path& baseline_file_path); - - ExpectedS> parse_versions_file(Files::Filesystem& fs, - StringView port_name, - const fs::path& versions_file_path); -} \ No newline at end of file +} diff --git a/toolsrc/src/vcpkg-test/dependencies.cpp b/toolsrc/src/vcpkg-test/dependencies.cpp index 2aae7fffacf818..454543982510b5 100644 --- a/toolsrc/src/vcpkg-test/dependencies.cpp +++ b/toolsrc/src/vcpkg-test/dependencies.cpp @@ -54,10 +54,7 @@ struct MockVersionedPortfileProvider : PortFileProvider::IVersionedPortfileProvi return it2->second; } - virtual const std::vector& get_port_versions(StringView) const override - { - Checks::unreachable(VCPKG_LINE_INFO); - } + virtual View get_port_versions(StringView) const override { Checks::unreachable(VCPKG_LINE_INFO); } SourceControlFileLocation& emplace(std::string&& name, Versions::Version&& version, diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 891207445f89dc..a3279a5115c827 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -1192,7 +1192,7 @@ namespace vcpkg::Files { } -#if defined(WIN32) +#if defined(_WIN32) void assign_busy_error(std::error_code& ec) { ec.assign(ERROR_BUSY, std::system_category()); } bool operator()(std::error_code& ec) @@ -1218,7 +1218,7 @@ namespace vcpkg::Files res.system_handle = reinterpret_cast(handle); return true; } -#else // ^^^ WIN32 / !WIN32 vvv +#else // ^^^ _WIN32 / !_WIN32 vvv int fd = -1; void assign_busy_error(std::error_code& ec) { ec.assign(EBUSY, std::generic_category()); } @@ -1228,7 +1228,7 @@ namespace vcpkg::Files ec.clear(); if (fd == -1) { - fd = ::open(native.c_str(), 0); + fd = ::open(native.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { ec.assign(errno, std::generic_category()); @@ -1311,7 +1311,7 @@ namespace vcpkg::Files virtual void unlock_file_lock(fs::SystemHandle handle, std::error_code& ec) override { -#if defined(WIN32) +#if defined(_WIN32) if (CloseHandle(reinterpret_cast(handle.system_handle)) == 0) { ec.assign(GetLastError(), std::system_category()); diff --git a/toolsrc/src/vcpkg/configuration.cpp b/toolsrc/src/vcpkg/configuration.cpp index f062af51d37d20..ca8c01cdf4c7ee 100644 --- a/toolsrc/src/vcpkg/configuration.cpp +++ b/toolsrc/src/vcpkg/configuration.cpp @@ -13,9 +13,11 @@ namespace vcpkg bool registries_feature_flags_warning = false; + auto impl_des = get_registry_implementation_deserializer(configuration_directory); + { - std::unique_ptr default_registry; - if (r.optional_object_field(obj, DEFAULT_REGISTRY, default_registry, RegistryImplDeserializer::instance)) + std::unique_ptr default_registry; + if (r.optional_object_field(obj, DEFAULT_REGISTRY, default_registry, *impl_des)) { if (!registries_enabled) { @@ -28,10 +30,9 @@ namespace vcpkg } } - static Json::ArrayDeserializer array_of_registries{"an array of registries"}; - + auto reg_des = get_registry_array_deserializer(configuration_directory); std::vector regs; - r.optional_object_field(obj, REGISTRIES, regs, array_of_registries); + r.optional_object_field(obj, REGISTRIES, regs, *reg_des); if (!regs.empty() && !registries_enabled) { @@ -39,6 +40,14 @@ namespace vcpkg regs.clear(); } + if (!r.errors().empty()) + { + System::print2(System::Color::error, "Errors occurred while parsing configuration.\n"); + for (auto&& msg : r.errors()) + System::print2(" ", msg, '\n'); + Checks::exit_fail(VCPKG_LINE_INFO); + } + for (Registry& reg : regs) { registries.add_registry(std::move(reg)); @@ -58,7 +67,9 @@ namespace vcpkg constexpr StringLiteral ConfigurationDeserializer::DEFAULT_REGISTRY; constexpr StringLiteral ConfigurationDeserializer::REGISTRIES; - ConfigurationDeserializer::ConfigurationDeserializer(const VcpkgCmdArguments& args) + ConfigurationDeserializer::ConfigurationDeserializer(const VcpkgCmdArguments& args, + const fs::path& configuration_directory) + : configuration_directory(configuration_directory) { registries_enabled = args.registries_enabled(); print_json = args.output_json(); diff --git a/toolsrc/src/vcpkg/install.cpp b/toolsrc/src/vcpkg/install.cpp index eee0eca0ed881e..ebc5ffc22c2e0f 100644 --- a/toolsrc/src/vcpkg/install.cpp +++ b/toolsrc/src/vcpkg/install.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include namespace vcpkg::Install { @@ -839,17 +841,12 @@ namespace vcpkg::Install if (args.versions_enabled()) { PortFileProvider::VersionedPortfileProvider verprovider(paths); - auto baseprovider = [&]() -> std::unique_ptr { - if (auto p_baseline = manifest_scf.core_paragraph->extra_info.get("$x-default-baseline")) - { - return std::make_unique(paths, - p_baseline->string().to_string()); - } - else - { - return std::make_unique(paths); - } - }(); + auto baseprovider = std::make_unique(paths); + if (auto p_baseline = manifest_scf.core_paragraph->extra_info.get("$x-default-baseline")) + { + paths.get_configuration().registry_set.experimental_set_builtin_registry_baseline( + p_baseline->string()); + } auto install_plan = Dependencies::create_versioned_install_plan(verprovider, diff --git a/toolsrc/src/vcpkg/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp index 421f28b002df17..44304b2618e6a0 100644 --- a/toolsrc/src/vcpkg/paragraphs.cpp +++ b/toolsrc/src/vcpkg/paragraphs.cpp @@ -423,15 +423,8 @@ namespace vcpkg::Paragraphs auto baseline_version = impl->get_baseline_version(paths, port_name); if (port_entry && baseline_version) { - auto port_path = port_entry->get_port_directory(paths, *baseline_version.get()); - if (port_path.empty()) - { - Debug::print("Registry for port `", - port_name, - "` is incorrect - baseline port version `", - baseline_version.get()->to_string(), - "` not found."); - } + auto port_path = + port_entry->get_path_to_version(paths, *baseline_version.get()).value_or_exit(VCPKG_LINE_INFO); auto maybe_spgh = try_load_port(fs, port_path); if (const auto spgh = maybe_spgh.get()) { diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index f22464fbe41f96..c1e08d779dd93b 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -17,29 +17,20 @@ using namespace Versions; namespace { - ExpectedS get_versions_json_path(const VcpkgPaths& paths, StringView port_name) - { - auto json_path = paths.root / fs::u8path("port_versions") / - fs::u8path(Strings::concat(port_name.substr(0, 1), "-")) / - fs::u8path(Strings::concat(port_name, ".json")); - if (paths.get_filesystem().exists(json_path)) - { - return std::move(json_path); - } - return {Strings::concat("Error: Versions database file does not exist: ", fs::u8string(json_path)), - expected_right_tag}; - } + using namespace vcpkg; - ExpectedS get_baseline_json_path(const VcpkgPaths& paths, StringView baseline_commit_sha) + struct OverlayRegistryEntry final : RegistryEntry { - auto baseline_path = paths.git_checkout_baseline(paths.get_filesystem(), baseline_commit_sha); - if (paths.get_filesystem().exists(baseline_path)) + View get_port_versions() const override { return {&version, 1}; } + ExpectedS get_path_to_version(const VcpkgPaths&, const VersionT& v) const override { - return std::move(baseline_path); + Checks::check_exit(VCPKG_LINE_INFO, v == version); + return path; } - return {Strings::concat("Error: Baseline database file does not exist: ", fs::u8string(baseline_path)), - expected_right_tag}; - } + + VersionT version; + fs::path path; + }; } namespace vcpkg::PortFileProvider @@ -95,9 +86,9 @@ namespace vcpkg::PortFileProvider } } - static Optional try_load_overlay_port(const Files::Filesystem& fs, - View overlay_ports, - const std::string& spec) + static std::unique_ptr try_load_overlay_port(const Files::Filesystem& fs, + View overlay_ports, + const std::string& spec) { for (auto&& ports_dir : overlay_ports) { @@ -105,11 +96,15 @@ namespace vcpkg::PortFileProvider if (Paragraphs::is_port_directory(fs, ports_dir)) { auto maybe_scf = Paragraphs::try_load_port(fs, ports_dir); - if (auto scf = maybe_scf.get()) + if (auto scfp = maybe_scf.get()) { - if (scf->get()->core_paragraph->name == spec) + auto& scf = *scfp; + if (scf->core_paragraph->name == spec) { - return SourceControlFileLocation{std::move(*scf), ports_dir}; + auto res = std::make_unique(); + res->path = std::move(ports_dir); + res->version = VersionT{scf->core_paragraph->version, scf->core_paragraph->port_version}; + return res; } } else @@ -126,17 +121,21 @@ namespace vcpkg::PortFileProvider if (Paragraphs::is_port_directory(fs, ports_spec)) { auto found_scf = Paragraphs::try_load_port(fs, ports_spec); - if (auto scf = found_scf.get()) + if (auto scfp = found_scf.get()) { - if (scf->get()->core_paragraph->name == spec) + auto& scf = *scfp; + if (scf->core_paragraph->name == spec) { - return SourceControlFileLocation{std::move(*scf), std::move(ports_spec)}; + auto res = std::make_unique(); + res->path = std::move(ports_dir); + res->version = VersionT{scf->core_paragraph->version, scf->core_paragraph->port_version}; + return res; } Checks::exit_with_message(VCPKG_LINE_INFO, "Error: Failed to load port from %s: names did not match: '%s' != '%s'", fs::u8string(ports_spec), spec, - scf->get()->core_paragraph->name); + scf->core_paragraph->name); } else { @@ -146,61 +145,39 @@ namespace vcpkg::PortFileProvider } } } - return nullopt; + return nullptr; } - static Optional try_load_registry_port(const VcpkgPaths& paths, const std::string& spec) + static std::pair, Optional> try_load_registry_port_and_baseline( + const VcpkgPaths& paths, const std::string& spec) { - const auto& fs = paths.get_filesystem(); if (auto registry = paths.get_configuration().registry_set.registry_for_port(spec)) { - auto baseline_version = registry->get_baseline_version(paths, spec); auto entry = registry->get_port_entry(paths, spec); - if (entry && baseline_version) + auto maybe_baseline = registry->get_baseline_version(paths, spec); + if (entry) { - auto port_directory = entry->get_port_directory(paths, *baseline_version.get()); - if (port_directory.empty()) + if (!maybe_baseline) { - Checks::exit_with_message(VCPKG_LINE_INFO, - "Error: registry is incorrect. Baseline version for port `%s` is `%s`, " - "but that version is not in the registry.\n", - spec, - baseline_version.get()->to_string()); - } - auto found_scf = Paragraphs::try_load_port(fs, port_directory); - if (auto scf = found_scf.get()) - { - if (scf->get()->core_paragraph->name == spec) + if (entry->get_port_versions().size() == 1) { - return SourceControlFileLocation{std::move(*scf), std::move(port_directory)}; + maybe_baseline = entry->get_port_versions()[0]; } - 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 - { - 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::move(entry), std::move(maybe_baseline)}; } else { - Debug::print("Failed to find port `", - spec, - "` in registry:", - entry ? " entry found;" : " no entry found;", - baseline_version ? " baseline version found\n" : " no baseline version found\n"); + Debug::print( + "Failed to find port `", spec, "` in registry:", entry ? " entry found." : " no entry found"); } } else { Debug::print("Failed to find registry for port: `", spec, "`.\n"); } - return nullopt; + + return {nullptr, nullopt}; } ExpectedS PathsPortFileProvider::get_control_file(const std::string& spec) const @@ -209,18 +186,46 @@ namespace vcpkg::PortFileProvider if (cache_it == cache.end()) { const auto& fs = paths.get_filesystem(); - auto maybe_port = try_load_overlay_port(fs, overlay_ports, spec); - if (!maybe_port) + + std::unique_ptr port; + VersionT port_version; + + auto maybe_overlay_port = try_load_overlay_port(fs, overlay_ports, spec); + if (maybe_overlay_port) { - maybe_port = try_load_registry_port(paths, spec); + port_version = maybe_overlay_port->version; + port = std::move(maybe_overlay_port); } - if (auto p = maybe_port.get()) + else { - auto maybe_error = - p->source_control_file->check_against_feature_flags(p->source_location, paths.get_feature_flags()); - if (maybe_error) return std::move(*maybe_error.get()); + auto maybe_registry_port = try_load_registry_port_and_baseline(paths, spec); + port = std::move(maybe_registry_port.first); + if (auto version = maybe_registry_port.second.get()) + { + port_version = std::move(*version); + } + else if (port) + { + return std::string("No baseline version available."); + } + } - cache_it = cache.emplace(spec, std::move(*p)).first; + if (port) + { + auto port_path = port->get_path_to_version(paths, port_version).value_or_exit(VCPKG_LINE_INFO); + auto maybe_scfl = Paragraphs::try_load_port(fs, port_path); + if (auto p = maybe_scfl.get()) + { + auto maybe_error = (*p)->check_against_feature_flags(port_path, paths.get_feature_flags()); + if (maybe_error) return std::move(*maybe_error.get()); + + cache_it = + cache.emplace(spec, SourceControlFileLocation{std::move(*p), std::move(port_path)}).first; + } + else + { + return maybe_scfl.error()->error; + } } } @@ -294,108 +299,45 @@ namespace vcpkg::PortFileProvider namespace details { + struct VersionedPortfileProviderImpl + { + std::map, std::less> entry_cache; + std::unordered_map path_cache; + std::unordered_map control_cache; + + VersionedPortfileProviderImpl(const VcpkgPaths& paths) : paths(paths) { } + ~VersionedPortfileProviderImpl() { } + + const VcpkgPaths& get_paths() const { return paths; } + Files::Filesystem& get_filesystem() const { return paths.get_filesystem(); } + + private: + const VcpkgPaths& paths; + }; + struct BaselineProviderImpl { BaselineProviderImpl(const VcpkgPaths& paths) : paths(paths) { } - BaselineProviderImpl(const VcpkgPaths& paths, const std::string& baseline) - : paths(paths), m_baseline(baseline) - { - } - ~BaselineProviderImpl() { } - - const Optional>>& get_baseline_cache() const - { - return baseline_cache.get_lazy([&]() -> Optional>> { - if (auto baseline = m_baseline.get()) - { - auto baseline_file = get_baseline_json_path(paths, *baseline).value_or_exit(VCPKG_LINE_INFO); - - auto maybe_baselines_map = - parse_baseline_file(paths.get_filesystem(), "default", baseline_file); - Checks::check_exit(VCPKG_LINE_INFO, - maybe_baselines_map.has_value(), - "Error: Couldn't parse baseline `%s` from `%s`", - "default", - fs::u8string(baseline_file)); - auto baselines_map = *maybe_baselines_map.get(); - return std::move(baselines_map); - } - else - { - // No baseline was provided, so use current repo - const auto& fs = paths.get_filesystem(); - auto baseline_file = paths.root / fs::u8path("port_versions") / fs::u8path("baseline.json"); - if (fs.exists(baseline_file)) - { - auto maybe_baselines_map = - parse_baseline_file(paths.get_filesystem(), "default", baseline_file); - Checks::check_exit(VCPKG_LINE_INFO, - maybe_baselines_map.has_value(), - "Error: Couldn't parse baseline `%s` from `%s`", - "default", - fs::u8string(baseline_file)); - auto baselines_map = *maybe_baselines_map.get(); - return std::move(baselines_map); - } - else - { - // No baseline file in current repo -- use current port versions. - m_portfile_provider = - std::make_unique(paths, std::vector{}); - return nullopt; - } - } - }); - } + ~BaselineProviderImpl() = default; Optional get_baseline_version(StringView port_name) const { - const auto& cache = get_baseline_cache(); - if (auto p_cache = cache.get()) + auto it = baseline_cache.find(port_name); + if (it != baseline_cache.end()) { - auto it = p_cache->find(port_name.to_string()); - if (it != p_cache->end()) - { - return it->second; - } - return nullopt; + return it->second; } else { - auto maybe_scfl = m_portfile_provider->get_control_file(port_name.to_string()); - if (auto p_scfl = maybe_scfl.get()) - { - auto cpgh = p_scfl->source_control_file->core_paragraph.get(); - return VersionT{cpgh->version, cpgh->port_version}; - } - else - { - return nullopt; - } + auto version = paths.get_configuration().registry_set.baseline_for_port(paths, port_name); + baseline_cache.emplace(port_name.to_string(), version); + return version; } } private: const VcpkgPaths& paths; - const Optional m_baseline; - Lazy>>> baseline_cache; - mutable std::unique_ptr m_portfile_provider; - }; - - struct VersionedPortfileProviderImpl - { - std::map> versions_cache; - std::unordered_map git_tree_cache; - std::unordered_map control_cache; - - VersionedPortfileProviderImpl(const VcpkgPaths& paths) : paths(paths) { } - ~VersionedPortfileProviderImpl() { } - - const VcpkgPaths& get_paths() const { return paths; } - Files::Filesystem& get_filesystem() const { return paths.get_filesystem(); } - - private: - const VcpkgPaths& paths; + mutable std::map, std::less<>> baseline_cache; }; } @@ -405,55 +347,22 @@ namespace vcpkg::PortFileProvider } VersionedPortfileProvider::~VersionedPortfileProvider() { } - const std::vector& VersionedPortfileProvider::get_port_versions(StringView port_name) const + View VersionedPortfileProvider::get_port_versions(StringView port_name) const { - auto cache_it = m_impl->versions_cache.find(port_name.to_string()); - if (cache_it != m_impl->versions_cache.end()) + auto cache_it = m_impl->entry_cache.find(port_name); + if (cache_it != m_impl->entry_cache.end()) { - return cache_it->second; + return cache_it->second->get_port_versions(); } - auto maybe_versions_file_path = get_versions_json_path(m_impl->get_paths(), port_name); - if (auto versions_file_path = maybe_versions_file_path.get()) + auto entry = try_load_registry_port_and_baseline(m_impl->get_paths(), port_name.to_string()); + if (entry.first) { - auto maybe_version_entries = parse_versions_file(m_impl->get_filesystem(), port_name, *versions_file_path); - Checks::check_exit(VCPKG_LINE_INFO, - maybe_version_entries.has_value(), - "Error: Couldn't parse versions from file: %s", - fs::u8string(*versions_file_path)); - auto version_entries = maybe_version_entries.value_or_exit(VCPKG_LINE_INFO); - - auto port = port_name.to_string(); - for (auto&& version_entry : version_entries) - { - VersionSpec spec(port, version_entry.version); - m_impl->versions_cache[port].push_back(spec); - m_impl->git_tree_cache.emplace(std::move(spec), std::move(version_entry.git_tree)); - } - return m_impl->versions_cache.at(port); + auto it = m_impl->entry_cache.emplace(port_name.to_string(), std::move(entry.first)); + return it.first->second->get_port_versions(); } else { - // Fall back to current available version - const auto& paths = m_impl->get_paths(); - auto maybe_port = try_load_registry_port(paths, port_name.to_string()); - if (auto p = maybe_port.get()) - { - auto maybe_error = - p->source_control_file->check_against_feature_flags(p->source_location, paths.get_feature_flags()); - - if (auto error = maybe_error.get()) - { - Checks::exit_with_message(VCPKG_LINE_INFO, "Error: %s", *error); - } - - VersionSpec vspec(port_name.to_string(), - VersionT(p->source_control_file->core_paragraph->version, - p->source_control_file->core_paragraph->port_version)); - m_impl->control_cache.emplace(vspec, std::move(*p)); - return m_impl->versions_cache.emplace(port_name.to_string(), std::vector{vspec}) - .first->second; - } Checks::exit_with_message(VCPKG_LINE_INFO, "Error: Could not find a definition for port %s", port_name); } } @@ -461,28 +370,42 @@ namespace vcpkg::PortFileProvider ExpectedS VersionedPortfileProvider::get_control_file( const VersionSpec& version_spec) const { - // Pre-populate versions cache. - get_port_versions(version_spec.port_name); - auto cache_it = m_impl->control_cache.find(version_spec); if (cache_it != m_impl->control_cache.end()) { return cache_it->second; } - auto git_tree_cache_it = m_impl->git_tree_cache.find(version_spec); - if (git_tree_cache_it == m_impl->git_tree_cache.end()) + auto entry_it = m_impl->entry_cache.find(version_spec.port_name); + if (entry_it == m_impl->entry_cache.end()) { - return Strings::concat("Error: No git object SHA for entry ", - version_spec.port_name, - " at version ", - version_spec.version, - "."); + auto reg_for_port = + m_impl->get_paths().get_configuration().registry_set.registry_for_port(version_spec.port_name); + + if (!reg_for_port) + { + return Strings::format("Error: no registry set up for port %s", version_spec.port_name); + } + + auto entry = reg_for_port->get_port_entry(m_impl->get_paths(), version_spec.port_name); + entry_it = m_impl->entry_cache.emplace(version_spec.port_name, std::move(entry)).first; + } + + auto path_cache_it = m_impl->path_cache.find(version_spec); + if (path_cache_it == m_impl->path_cache.end()) + { + auto maybe_path = entry_it->second->get_path_to_version(m_impl->get_paths(), version_spec.version); + if (auto p = maybe_path.get()) + { + path_cache_it = m_impl->path_cache.emplace(version_spec, std::move(*p)).first; + } + else + { + Checks::exit_with_message(VCPKG_LINE_INFO, maybe_path.error()); + } } - const std::string git_tree = git_tree_cache_it->second; - auto port_directory = - m_impl->get_paths().git_checkout_port(m_impl->get_filesystem(), version_spec.port_name, git_tree); + const auto& port_directory = path_cache_it->second; auto maybe_control_file = Paragraphs::try_load_port(m_impl->get_filesystem(), port_directory); if (auto scf = maybe_control_file.get()) @@ -509,11 +432,7 @@ namespace vcpkg::PortFileProvider { } - BaselineProvider::BaselineProvider(const VcpkgPaths& paths, const std::string& baseline) - : m_impl(std::make_unique(paths, baseline)) - { - } - BaselineProvider::~BaselineProvider() { } + BaselineProvider::~BaselineProvider() = default; Optional BaselineProvider::get_baseline_version(StringView port_name) const { diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index 51c8849c97fcf7..7d2989c89df4cf 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -4,7 +4,9 @@ #include #include +#include #include +#include #include #include #include @@ -16,342 +18,707 @@ namespace { using namespace vcpkg; - struct BuiltinEntry final : RegistryEntry + using Baseline = std::map>; + + struct GitRegistryEntry final { - fs::path port_directory; + explicit GitRegistryEntry(std::string&& port_name) : port_name(port_name) { } - BuiltinEntry(fs::path&& p) : port_directory(std::move(p)) { } + std::string port_name; - fs::path get_port_directory(const VcpkgPaths&, const VersionT&) const override { return port_directory; } + // these two map port versions to git trees + // these shall have the same size, and git_trees[i] shall be the git tree for port_versions[i] + std::vector port_versions; + std::vector git_trees; }; - struct BuiltinRegistry final : RegistryImpl + struct BuiltinRegistryEntry final : RegistryEntry { - std::unique_ptr get_port_entry(const VcpkgPaths& paths, StringView port_name) const override + explicit BuiltinRegistryEntry(std::unique_ptr&& entry) + : git_entry(std::move(entry)), scfl(nullptr) + { + } + explicit BuiltinRegistryEntry(std::unique_ptr&& scfl_) + : git_entry(nullptr), scfl(std::move(scfl_)), scfl_version(scfl->to_versiont()) + { + } + + View get_port_versions() const override { - auto p = paths.builtin_ports_directory() / fs::u8path(port_name); - if (paths.get_filesystem().exists(p)) + if (git_entry) { - return std::make_unique(std::move(p)); + return git_entry->port_versions; } else { - return nullptr; + return {&scfl_version, 1}; } } + ExpectedS get_path_to_version(const VcpkgPaths&, const VersionT& version) const override; - void get_all_port_names(std::vector& names, const VcpkgPaths& paths) const override - { - const auto& fs = paths.get_filesystem(); - auto port_dirs = fs.get_files_non_recursive(paths.builtin_ports_directory()); - Util::sort(port_dirs); + // exactly one of these two shall be null - Util::erase_remove_if(port_dirs, - [&](auto&& port_dir_entry) { return port_dir_entry.filename() == ".DS_Store"; }); + // if we find a versions.json, this shall be non-null and BuiltinRegistryEntry uses git_entry's implementation + std::unique_ptr git_entry; + // otherwise, if we don't find a versions.json, + // we fall back to just using the version in the ports directory, and this is the non-null one + std::unique_ptr scfl; + VersionT scfl_version; // this exists so that we can return a pointer to it + }; - std::transform(port_dirs.begin(), port_dirs.end(), std::back_inserter(names), [](const fs::path& p) { - return fs::u8string(p.filename()); - }); - } + struct BuiltinRegistry final : RegistryImplementation + { + BuiltinRegistry(std::string&& baseline) : m_baseline_identifier(std::move(baseline)) { } + + std::unique_ptr get_port_entry(const VcpkgPaths& paths, StringView port_name) const override; - Optional get_baseline_version(const VcpkgPaths&, StringView) const override { return VersionT{}; } + void get_all_port_names(std::vector&, const VcpkgPaths&) const override; + + Optional get_baseline_version(const VcpkgPaths& paths, StringView port_name) const override; + + ~BuiltinRegistry() = default; + + std::string m_baseline_identifier; + DelayedInit m_baseline; }; - struct FilesystemEntry final : RegistryEntry + struct FilesystemRegistryEntry final : RegistryEntry { - std::map versions; + explicit FilesystemRegistryEntry(std::string&& port_name) : port_name(port_name) { } - fs::path get_port_directory(const VcpkgPaths&, const VersionT& version) const override - { - auto it = versions.find(version); - if (it != versions.end()) - { - return it->second; - } - return {}; - } + View get_port_versions() const override { return port_versions; } + + ExpectedS get_path_to_version(const VcpkgPaths& paths, const VersionT& version) const override; + + std::string port_name; + + // these two map port versions to paths + // these shall have the same size, and paths[i] shall be the path for port_versions[i] + std::vector port_versions; + std::vector version_paths; }; - struct FilesystemVersionEntryDeserializer final : Json::IDeserializer> + struct FilesystemRegistry final : RegistryImplementation { - StringView type_name() const override { return "a version entry object"; } - View valid_fields() const override + FilesystemRegistry(fs::path&& path, std::string&& baseline) + : m_path(std::move(path)), m_baseline_identifier(baseline) { - static const StringView t[] = {"version-string", "port-version", "registry-path"}; - return t; } - Optional> visit_object(Json::Reader& r, const Json::Object& obj) override - { - fs::path registry_path; + std::unique_ptr get_port_entry(const VcpkgPaths&, StringView) const override; - auto version = get_versiont_deserializer_instance().visit_object(r, obj); + void get_all_port_names(std::vector&, const VcpkgPaths&) const override; - r.required_object_field( - "version entry", obj, "registry-path", registry_path, Json::PathDeserializer::instance); - // registry_path should look like `/blah/foo` - if (registry_path.has_root_name() || !registry_path.has_root_directory()) - { - r.add_generic_error(type_name(), "must be an absolute path without a drive name"); - registry_path.clear(); - } + Optional get_baseline_version(const VcpkgPaths&, StringView) const override; + + private: + fs::path m_path; + std::string m_baseline_identifier; + DelayedInit m_baseline; + }; - return std::pair{std::move(version).value_or(VersionT{}), std::move(registry_path)}; + ExpectedS get_git_baseline_json_path(const VcpkgPaths& paths, StringView baseline_commit_sha) + { + auto baseline_path = paths.git_checkout_baseline(paths.get_filesystem(), baseline_commit_sha); + if (paths.get_filesystem().exists(baseline_path)) + { + return std::move(baseline_path); } + return {Strings::concat("Error: Baseline database file does not exist: ", fs::u8string(baseline_path)), + expected_right_tag}; + } - static FilesystemVersionEntryDeserializer instance; + struct VersionDbEntry + { + VersionT version; + Versions::Scheme scheme = Versions::Scheme::String; + + // only one of these may be non-empty + std::string git_tree; + fs::path path; }; - FilesystemVersionEntryDeserializer FilesystemVersionEntryDeserializer::instance; - struct FilesystemEntryDeserializer final : Json::IDeserializer + // VersionDbType::Git => VersionDbEntry.git_tree is filled + // VersionDbType::Filesystem => VersionDbEntry.path is filled + enum class VersionDbType { - StringView type_name() const override { return "a registry entry object"; } + Git, + Filesystem, + }; - Optional visit_array(Json::Reader& r, const Json::Array& arr) override + fs::path relative_path_to_versions(StringView port_name); + ExpectedS> load_versions_file(Files::Filesystem& fs, + VersionDbType vdb, + const fs::path& port_versions, + StringView port_name, + const fs::path& registry_root = {}); + + // returns nullopt if the baseline is valid, but doesn't contain the specified baseline, + // or (equivalently) if the baseline does not exist. + ExpectedS> parse_baseline_versions(StringView contents, StringView baseline); + ExpectedS> load_baseline_versions(const VcpkgPaths& paths, + const fs::path& path_to_baseline, + StringView identifier = {}); + + void load_all_port_names_from_port_versions(std::vector& out, + const VcpkgPaths& paths, + const fs::path& port_versions_path) + { + for (auto super_directory : fs::directory_iterator(port_versions_path)) { - FilesystemEntry res; + if (!fs::is_directory(paths.get_filesystem().status(VCPKG_LINE_INFO, super_directory))) continue; - std::pair buffer; - for (std::size_t idx = 0; idx < arr.size(); ++idx) + for (auto file : fs::directory_iterator(super_directory)) { - r.visit_at_index( - arr[idx], static_cast(idx), buffer, FilesystemVersionEntryDeserializer::instance); - - auto it = res.versions.lower_bound(buffer.first); - if (it == res.versions.end() || it->first != buffer.first) - { - buffer.second = registry_root / fs::lexically_normal(buffer.second).relative_path(); - res.versions.insert(it, std::move(buffer)); - } - else if (buffer.first != VersionT{}) + auto filename = fs::u8string(file.path().filename()); + if (Strings::ends_with(filename, ".json")) { - r.add_generic_error( - type_name(), "Gave multiple definitions for version: ", buffer.first.to_string()); + auto port_name = filename.substr(0, filename.size() - 5); + if (!Json::PackageNameDeserializer::is_package_name(port_name)) + { + Checks::exit_with_message( + VCPKG_LINE_INFO, "Error: found invalid port version file name: `%s`.", fs::u8string(file)); + } + out.push_back(std::move(port_name)); } } + } + } + + // { RegistryImplementation + // { BuiltinRegistry::RegistryImplementation + std::unique_ptr BuiltinRegistry::get_port_entry(const VcpkgPaths& paths, StringView port_name) const + { + auto versions_path = paths.root / fs::u8path("port_versions") / relative_path_to_versions(port_name); + if (paths.get_filesystem().exists(versions_path)) + { + auto maybe_version_entries = load_versions_file( + paths.get_filesystem(), VersionDbType::Git, paths.root / fs::u8path("port_versions"), port_name); + Checks::check_exit( + VCPKG_LINE_INFO, maybe_version_entries.has_value(), "Error: %s", maybe_version_entries.error()); + auto version_entries = std::move(maybe_version_entries).value_or_exit(VCPKG_LINE_INFO); + + auto res = + std::make_unique(std::make_unique(port_name.to_string())); + auto gre = res->git_entry.get(); + for (auto&& version_entry : version_entries) + { + gre->port_versions.push_back(version_entry.version); + gre->git_trees.push_back(version_entry.git_tree); + } return res; } + else + { + // Fall back to current available version + auto port_directory = paths.builtin_ports_directory() / fs::u8path(port_name); + if (paths.get_filesystem().exists(port_directory)) + { + auto found_scf = Paragraphs::try_load_port(paths.get_filesystem(), port_directory); + if (auto scfp = found_scf.get()) + { + auto& scf = *scfp; + auto maybe_error = scf->check_against_feature_flags(port_directory, paths.get_feature_flags()); + if (maybe_error) + Checks::exit_with_message(VCPKG_LINE_INFO, "Parsing manifest failed: %s", *maybe_error.get()); - FilesystemEntryDeserializer(const fs::path& p) : registry_root(p) { } + if (scf->core_paragraph->name == port_name) + { + return std::make_unique( + std::make_unique(std::move(scf), std::move(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), + port_name, + scf->core_paragraph->name); + } + } - const fs::path& registry_root; - }; + return nullptr; + } + } - struct FilesystemRegistry final : RegistryImpl + Optional BuiltinRegistry::get_baseline_version(const VcpkgPaths& paths, StringView port_name) const { - std::unique_ptr get_port_entry(const VcpkgPaths& paths, StringView port_name) const override - { - const auto& fs = paths.get_filesystem(); - auto entry_path = this->path_to_port_entry(paths, port_name); - if (!fs.exists(entry_path)) + const auto& baseline = m_baseline.get([this, &paths]() -> Baseline { + auto path_to_baseline = paths.root / fs::u8path("port_versions") / fs::u8path("baseline.json"); + auto res_baseline = load_baseline_versions(paths, path_to_baseline, m_baseline_identifier); + + if (!res_baseline.has_value()) + { + Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error()); + } + auto opt_baseline = res_baseline.get(); + if (auto p = opt_baseline->get()) { - Debug::print( - "Failed to find entry for port `", port_name, "` in file: ", fs::u8string(entry_path), "\n"); - return nullptr; + return std::move(*p); } - std::error_code ec; - auto json_document = Json::parse_file(fs, entry_path, ec); - if (auto p = json_document.get()) + if (m_baseline_identifier.empty()) { - Json::Reader r; - auto real_path = paths.config_root_dir / path; - FilesystemEntryDeserializer deserializer{real_path}; - auto entry = r.visit(p->first, deserializer); - auto pentry = entry.get(); - if (pentry && r.errors().empty()) + return {}; + } + + if (m_baseline_identifier == "default") + { + Checks::exit_with_message( + VCPKG_LINE_INFO, + "Couldn't find explicitly specified baseline `\"default\"` in the baseline file.", + m_baseline_identifier); + } + + // attempt to check out the baseline: + auto maybe_path = get_git_baseline_json_path(paths, m_baseline_identifier); + if (auto path_to_git_baseline = maybe_path.get()) + { + res_baseline = load_baseline_versions(paths, *path_to_git_baseline); + if (!res_baseline.has_value()) { - return std::make_unique(std::move(*pentry)); + Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error()); + } + opt_baseline = res_baseline.get(); + if (auto p = opt_baseline->get()) + { + return std::move(*p); } else { - vcpkg::Checks::exit_with_message(VCPKG_LINE_INFO, - "Failed to parse the port entry for port `%s` at `%s`.\n%s", - port_name, - fs::u8string(entry_path), - Strings::join("\n", r.errors())); + Checks::exit_with_message(VCPKG_LINE_INFO, + "Couldn't find explicitly specified baseline `\"%s\"` in the baseline " + "file, and the `\"default\"` baseline does not exist at that commit.", + m_baseline_identifier); } } else { - Debug::print("Failed to parse json document: ", json_document.error()->format(), "\n"); + Checks::exit_with_message(VCPKG_LINE_INFO, + "Couldn't find explicitly specified baseline `\"%s\"` in the baseline file, " + "and there was no baseline at that commit or the commit didn't exist.\n%s", + m_baseline_identifier, + maybe_path.error()); } + }); - return nullptr; + auto it = baseline.find(port_name); + if (it != baseline.end()) + { + return it->second; + } + else + { + // fall back to using the ports directory version + auto maybe_scf = Paragraphs::try_load_port(paths.get_filesystem(), + paths.builtin_ports_directory() / fs::u8path(port_name)); + if (auto pscf = maybe_scf.get()) + { + auto& scf = *pscf; + return scf->to_versiont(); + } + Debug::print("Failed to load port `%s` from the ports tree: %s.", port_name, maybe_scf.error()->error); + return nullopt; + } + } + + void BuiltinRegistry::get_all_port_names(std::vector& out, const VcpkgPaths& paths) const + { + auto port_versions_path = paths.root / fs::u8path("port_versions"); + if (paths.get_filesystem().exists(port_versions_path)) + { + load_all_port_names_from_port_versions(out, paths, port_versions_path); } - void get_all_port_names(std::vector& port_names, const VcpkgPaths& paths) const override + for (auto port_directory : fs::directory_iterator(paths.builtin_ports_directory())) { - std::error_code ec; - for (const auto& super_dir : fs::directory_iterator(path)) + if (!fs::is_directory(paths.get_filesystem().status(VCPKG_LINE_INFO, port_directory))) continue; + auto filename = fs::u8string(port_directory.path().filename()); + if (filename == ".DS_Store") continue; + out.push_back(filename); + } + } + // } BuiltinRegistry::RegistryImplementation + + // { FilesystemRegistry::RegistryImplementation + Optional FilesystemRegistry::get_baseline_version(const VcpkgPaths& paths, StringView port_name) const + { + const auto& baseline = m_baseline.get([this, &paths]() -> Baseline { + auto path_to_baseline = m_path / fs::u8path("port_versions") / fs::u8path("baseline.json"); + auto res_baseline = load_baseline_versions(paths, path_to_baseline, m_baseline_identifier); + if (auto opt_baseline = res_baseline.get()) { - if (!fs::is_directory(paths.get_filesystem().status(super_dir, ec))) + if (auto p = opt_baseline->get()) { - continue; + return std::move(*p); } - - auto super_dir_filename = fs::u8string(super_dir.path().filename()); - if (!Strings::ends_with(super_dir_filename, "-")) + else if (m_baseline_identifier.empty()) { - continue; + return {}; } - - super_dir_filename.pop_back(); - for (const auto& database_entry : fs::directory_iterator(super_dir)) + else { - auto database_entry_filename = database_entry.path().filename(); - auto database_entry_filename_str = fs::u8string(database_entry_filename); - - if (!Strings::starts_with(database_entry_filename_str, super_dir_filename) || - !Strings::ends_with(database_entry_filename_str, ".json")) - { - Debug::print("Unexpected file in database (this is not an error): ", - fs::u8string(database_entry.path()), - "\n"); - continue; - } - - port_names.push_back(fs::u8string(database_entry_filename.replace_extension())); + Checks::exit_with_message( + VCPKG_LINE_INFO, + "Error: could not find explicitly specified baseline `\"%s\"` in baseline file `%s`.", + m_baseline_identifier, + fs::u8string(path_to_baseline)); } } + else + { + Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error()); + } + }); + + auto it = baseline.find(port_name); + if (it != baseline.end()) + { + return it->second; + } + else + { + return nullopt; } + } - Optional get_baseline_version(const VcpkgPaths& paths, StringView port_name) const override + std::unique_ptr FilesystemRegistry::get_port_entry(const VcpkgPaths& paths, + StringView port_name) const + { + auto maybe_version_entries = load_versions_file( + paths.get_filesystem(), VersionDbType::Filesystem, m_path / fs::u8path("port_versions"), port_name, m_path); + Checks::check_exit( + VCPKG_LINE_INFO, maybe_version_entries.has_value(), "Error: %s", maybe_version_entries.error()); + auto version_entries = std::move(maybe_version_entries).value_or_exit(VCPKG_LINE_INFO); + + auto res = std::make_unique(port_name.to_string()); + for (auto&& version_entry : version_entries) { - if (!paths.get_feature_flags().versions) - { - Checks::check_exit(VCPKG_LINE_INFO, - "This invocation failed because the `versions` feature flag is not enabled."); - } + res->port_versions.push_back(std::move(version_entry.version)); + res->version_paths.push_back(std::move(version_entry.path)); + } + return res; + } - const auto& baseline_cache = baseline.get([this, &paths] { return load_baseline_versions(paths); }); - auto it = baseline_cache.find(port_name); - if (it != baseline_cache.end()) - { - return it->second; - } - else + void FilesystemRegistry::get_all_port_names(std::vector& out, const VcpkgPaths& paths) const + { + load_all_port_names_from_port_versions(out, paths, m_path / fs::u8path("port_versions")); + } + // } FilesystemRegistry::RegistryImplementation + + // } RegistryImplementation + + // { RegistryEntry + + // { BuiltinRegistryEntry::RegistryEntry + ExpectedS BuiltinRegistryEntry::get_path_to_version(const VcpkgPaths& paths, + const VersionT& version) const + { + if (git_entry) + { + auto it = std::find(git_entry->port_versions.begin(), git_entry->port_versions.end(), version); + if (it == git_entry->port_versions.end()) { - return nullopt; + return Strings::concat( + "Error: No version entry for ", git_entry->port_name, " at version ", version, "."); } + + const auto& git_tree = git_entry->git_trees[it - git_entry->port_versions.begin()]; + return paths.git_checkout_port(paths.get_filesystem(), git_entry->port_name, git_tree); + } + else if (scfl_version == version) + { + return scfl->source_location; + } + else + { + auto& name = scfl->source_control_file->core_paragraph->name; + return Strings::format( + "Error: no version entry for %s at version %s.\n" + "We are currently using the version in the ports tree, since no %s.json was found in port_versions.", + name, + scfl->to_versiont().to_string(), + name); + } + } + // } BuiltinRegistryEntry::RegistryEntry + + // { FilesystemRegistryEntry::RegistryEntry + ExpectedS FilesystemRegistryEntry::get_path_to_version(const VcpkgPaths&, const VersionT& version) const + { + auto it = std::find(port_versions.begin(), port_versions.end(), version); + if (it == port_versions.end()) + { + return Strings::concat("Error: No version entry for ", port_name, " at version ", version, "."); } + return version_paths[it - port_versions.begin()]; + } + // } FilesystemRegistryEntry::RegistryEntry + + // } RegistryEntry +} - FilesystemRegistry(fs::path&& path_) : path(path_) { } +// deserializers +namespace +{ + using namespace vcpkg; - private: - fs::path path_to_registry_database(const VcpkgPaths& paths) const + struct BaselineDeserializer final : Json::IDeserializer>> + { + StringView type_name() const override { return "a baseline object"; } + + Optional visit_object(Json::Reader& r, const Json::Object& obj) override { - fs::path path_to_db = paths.config_root_dir / path; - path_to_db /= fs::u8path( - {'\xF0', '\x9F', '\x98', '\x87'}); // utf-8 for https://emojipedia.org/smiling-face-with-halo/ - return path_to_db; + std::map> result; + + for (auto pr : obj) + { + const auto& version_value = pr.second; + VersionT version; + r.visit_in_key(version_value, pr.first, version, get_versiont_deserializer_instance()); + + result.emplace(pr.first.to_string(), std::move(version)); + } + + return std::move(result); } - fs::path path_to_port_entry(const VcpkgPaths& paths, StringView port_name) const + static BaselineDeserializer instance; + }; + BaselineDeserializer BaselineDeserializer::instance; + + struct VersionDbEntryDeserializer final : Json::IDeserializer + { + static constexpr StringLiteral GIT_TREE = "git-tree"; + static constexpr StringLiteral PATH = "path"; + + StringView type_name() const override { return "a version database entry"; } + View valid_fields() const override { - Checks::check_exit(VCPKG_LINE_INFO, port_name.size() != 0); - fs::path path_to_entry = path_to_registry_database(paths); - path_to_entry /= fs::u8path({port_name.byte_at_index(0), '-'}); - path_to_entry /= fs::u8path(port_name); - path_to_entry += fs::u8path(".json"); + static const StringView u_git[] = {GIT_TREE}; + static const StringView u_path[] = {PATH}; + static const auto t_git = vcpkg::Util::Vectors::concat(schemed_deserializer_fields(), u_git); + static const auto t_path = vcpkg::Util::Vectors::concat(schemed_deserializer_fields(), u_path); - return path_to_entry; + return type == VersionDbType::Git ? t_git : t_path; } - std::map> load_baseline_versions(const VcpkgPaths& paths) const + Optional visit_object(Json::Reader& r, const Json::Object& obj) override { - auto baseline_file = path_to_registry_database(paths) / fs::u8path("baseline.json"); + VersionDbEntry ret; - auto value = Json::parse_file(VCPKG_LINE_INFO, paths.get_filesystem(), baseline_file); - if (!value.first.is_object()) - { - Checks::exit_with_message(VCPKG_LINE_INFO, "Error: `baseline.json` does not have a top-level object."); - } + auto schemed_version = visit_required_schemed_deserializer(type_name(), r, obj); + ret.scheme = schemed_version.scheme; + ret.version = std::move(schemed_version.versiont); - auto maybe_baseline_versions = parse_baseline_file(paths.get_filesystem(), "default", baseline_file); - if (auto baseline_versions = maybe_baseline_versions.get()) - { - return std::move(*baseline_versions); - } - else + static Json::StringDeserializer git_tree_deserializer("a git object SHA"); + static Json::StringDeserializer path_deserializer("a registry path"); + + switch (type) { - Checks::exit_with_message(VCPKG_LINE_INFO, - "Error: failed to parse `%s`:\n%s", - fs::u8string(baseline_file), - maybe_baseline_versions.error()); + case VersionDbType::Git: + { + r.required_object_field(type_name(), obj, GIT_TREE, ret.git_tree, git_tree_deserializer); + break; + } + case VersionDbType::Filesystem: + { + std::string path_res; + r.required_object_field(type_name(), obj, PATH, path_res, path_deserializer); + fs::path p = fs::u8path(path_res); + if (p.is_absolute()) + { + r.add_generic_error("a registry path", + "A registry path may not be absolute, and must start with a `$` to mean " + "the registry root; e.g., `$/foo/bar`."); + return ret; + } + else if (p.empty()) + { + r.add_generic_error("a registry path", "A registry path must not be empty."); + return ret; + } + + auto it = p.begin(); + if (*it != "$") + { + r.add_generic_error( + "a registry path", + "A registry path must start with `$` to mean the registry root; e.g., `$/foo/bar`"); + } + + ret.path = registry_root; + ++it; + std::for_each(it, p.end(), [&r, &ret](const fs::path& p) { + if (p == "..") + { + r.add_generic_error("a registry path", "A registry path must not contain `..`."); + } + else + { + ret.path /= p; + } + }); + + break; + } } + + return ret; } - fs::path path; - DelayedInit>> baseline; + VersionDbEntryDeserializer(VersionDbType type, const fs::path& root) : type(type), registry_root(root) { } + + VersionDbType type; + fs::path registry_root; }; -} -namespace vcpkg -{ - std::unique_ptr Registry::builtin_registry() { return std::make_unique(); } + struct VersionDbEntryArrayDeserializer final : Json::IDeserializer> + { + virtual StringView type_name() const override { return "an array of versions"; } - Registry::Registry(std::vector&& packages, std::unique_ptr&& impl) - : packages_(std::move(packages)), implementation_(std::move(impl)) + virtual Optional> visit_array(Json::Reader& r, const Json::Array& arr) override + { + return r.array_elements(arr, underlying); + } + + VersionDbEntryArrayDeserializer(VersionDbType type, const fs::path& root) : underlying{type, root} { } + + VersionDbEntryDeserializer underlying; + }; + + struct RegistryImplDeserializer : Json::IDeserializer> { - Checks::check_exit(VCPKG_LINE_INFO, implementation_ != nullptr); - } + constexpr static StringLiteral KIND = "kind"; + constexpr static StringLiteral BASELINE = "baseline"; + constexpr static StringLiteral PATH = "path"; + constexpr static StringLiteral REPO = "repository"; + + constexpr static StringLiteral KIND_BUILTIN = "builtin"; + constexpr static StringLiteral KIND_FILESYSTEM = "filesystem"; - RegistryImplDeserializer RegistryImplDeserializer::instance; + virtual StringView type_name() const override { return "a registry"; } + virtual View valid_fields() const override; - StringView RegistryImplDeserializer::type_name() const { return "a registry"; } + virtual Optional> visit_null(Json::Reader&) override; + virtual Optional> visit_object(Json::Reader&, + const Json::Object&) override; + RegistryImplDeserializer(const fs::path& configuration_directory) + : config_directory(configuration_directory) { } + + fs::path config_directory; + }; constexpr StringLiteral RegistryImplDeserializer::KIND; + constexpr StringLiteral RegistryImplDeserializer::BASELINE; constexpr StringLiteral RegistryImplDeserializer::PATH; + constexpr StringLiteral RegistryImplDeserializer::REPO; constexpr StringLiteral RegistryImplDeserializer::KIND_BUILTIN; constexpr StringLiteral RegistryImplDeserializer::KIND_FILESYSTEM; + struct RegistryDeserializer final : Json::IDeserializer + { + constexpr static StringLiteral PACKAGES = "packages"; + + virtual StringView type_name() const override { return "a registry"; } + virtual View valid_fields() const override; + + virtual Optional visit_object(Json::Reader&, const Json::Object&) override; + + explicit RegistryDeserializer(const fs::path& configuration_directory) : impl_des(configuration_directory) { } + + RegistryImplDeserializer impl_des; + }; + constexpr StringLiteral RegistryDeserializer::PACKAGES; + View RegistryImplDeserializer::valid_fields() const { - static const StringView t[] = {KIND, PATH}; + static const StringView t[] = {KIND, BASELINE, PATH, REPO}; + return t; + } + View valid_builtin_fields() + { + static const StringView t[] = { + RegistryImplDeserializer::KIND, + RegistryImplDeserializer::BASELINE, + RegistryDeserializer::PACKAGES, + }; + return t; + } + View valid_filesystem_fields() + { + static const StringView t[] = { + RegistryImplDeserializer::KIND, + RegistryImplDeserializer::BASELINE, + RegistryImplDeserializer::PATH, + RegistryDeserializer::PACKAGES, + }; + return t; + } + View valid_git_fields() + { + static const StringView t[] = { + RegistryImplDeserializer::KIND, + RegistryImplDeserializer::BASELINE, + RegistryImplDeserializer::REPO, + RegistryDeserializer::PACKAGES, + }; return t; } - Optional> RegistryImplDeserializer::visit_null(Json::Reader&) { return nullptr; } + Optional> RegistryImplDeserializer::visit_null(Json::Reader&) + { + return nullptr; + } - Optional> RegistryImplDeserializer::visit_object(Json::Reader& r, - const Json::Object& obj) + Optional> RegistryImplDeserializer::visit_object(Json::Reader& r, + const Json::Object& obj) { static Json::StringDeserializer kind_deserializer{"a registry implementation kind"}; + static Json::StringDeserializer baseline_deserializer{"a baseline"}; std::string kind; + std::string baseline; + r.required_object_field(type_name(), obj, KIND, kind, kind_deserializer); + r.optional_object_field(obj, BASELINE, baseline, baseline_deserializer); + + std::unique_ptr res; if (kind == KIND_BUILTIN) { - if (obj.contains(PATH)) - { - r.add_extra_field_error("a builtin registry", PATH); - } - return static_cast>(std::make_unique()); + r.check_for_unexpected_fields(obj, valid_builtin_fields(), "a builtin registry"); + res = std::make_unique(std::move(baseline)); } else if (kind == KIND_FILESYSTEM) { + r.check_for_unexpected_fields(obj, valid_filesystem_fields(), "a filesystem registry"); + fs::path path; r.required_object_field("a filesystem registry", obj, PATH, path, Json::PathDeserializer::instance); - return static_cast>(std::make_unique(std::move(path))); + res = std::make_unique(config_directory / path, std::move(baseline)); } else { + StringLiteral valid_kinds[] = {KIND_BUILTIN, KIND_FILESYSTEM}; + r.add_generic_error(type_name(), + "Field \"kind\" did not have an expected value (expected one of: \"", + Strings::join("\", \"", valid_kinds), + "\", found \"", + kind, + "\")."); return nullopt; } - } - StringView RegistryDeserializer::type_name() const { return "a registry"; } - - constexpr StringLiteral RegistryDeserializer::PACKAGES; + return std::move(res); + } View RegistryDeserializer::valid_fields() const { static const StringView t[] = { RegistryImplDeserializer::KIND, + RegistryImplDeserializer::BASELINE, RegistryImplDeserializer::PATH, + RegistryImplDeserializer::REPO, PACKAGES, }; return t; @@ -359,7 +726,7 @@ namespace vcpkg Optional RegistryDeserializer::visit_object(Json::Reader& r, const Json::Object& obj) { - auto impl = RegistryImplDeserializer::instance.visit_object(r, obj); + auto impl = impl_des.visit_object(r, obj); if (!impl.has_value()) { @@ -375,9 +742,163 @@ namespace vcpkg return Registry{std::move(packages), std::move(impl).value_or_exit(VCPKG_LINE_INFO)}; } + fs::path relative_path_to_versions(StringView port_name) + { + auto port_filename = fs::u8path(port_name.to_string() + ".json"); + return fs::u8path({port_name.byte_at_index(0), '-'}) / port_filename; + } + + ExpectedS> load_versions_file(Files::Filesystem& fs, + VersionDbType type, + const fs::path& port_versions, + StringView port_name, + const fs::path& registry_root) + { + Checks::check_exit(VCPKG_LINE_INFO, + !(type == VersionDbType::Filesystem && registry_root.empty()), + "Bug in vcpkg; type should never = Filesystem when registry_root is empty."); + + auto versions_file_path = port_versions / relative_path_to_versions(port_name); + + if (!fs.exists(versions_file_path)) + { + return Strings::format("Couldn't find the versions database file: %s", fs::u8string(versions_file_path)); + } + + auto maybe_contents = fs.read_contents(versions_file_path); + if (auto contents = maybe_contents.get()) + { + auto maybe_versions_json = Json::parse(*contents); + if (!maybe_versions_json.has_value()) + { + return Strings::format("Error: failed to parse versions file for `%s`: %s", + port_name, + maybe_versions_json.error()->format()); + } + if (!maybe_versions_json.get()->first.is_object()) + { + return Strings::format("Error: versions file for `%s` does not have a top level object.", port_name); + } + + const auto& versions_object = maybe_versions_json.get()->first.object(); + auto maybe_versions_array = versions_object.get("versions"); + if (!maybe_versions_array || !maybe_versions_array->is_array()) + { + return Strings::format("Error: versions file for `%s` does not contain a versions array.", port_name); + } + + std::vector db_entries; + VersionDbEntryArrayDeserializer deserializer{type, registry_root}; + // Avoid warning treated as error. + if (maybe_versions_array != nullptr) + { + Json::Reader r; + r.visit_in_key(*maybe_versions_array, "versions", db_entries, deserializer); + if (!r.errors().empty()) + { + return Strings::format("Error: failed to parse versions file for `%s`:\n%s", + port_name, + Strings::join("\n", r.errors())); + } + } + return db_entries; + } + else + { + return Strings::format("Failed to load the versions database file %s: %s", + fs::u8string(versions_file_path), + maybe_contents.error().message()); + } + } + + ExpectedS> parse_baseline_versions(StringView contents, StringView baseline) + { + auto maybe_value = Json::parse(contents); + if (!maybe_value.has_value()) + { + return Strings::format("Error: failed to parse baseline file: %s", maybe_value.error()->format()); + } + + auto& value = *maybe_value.get(); + + if (!value.first.is_object()) + { + return std::string("Error: baseline does not have a top-level object."); + } + + auto real_baseline = baseline.size() == 0 ? "default" : baseline; + + const auto& obj = value.first.object(); + auto baseline_value = obj.get(real_baseline); + if (!baseline_value) + { + return {nullopt, expected_left_tag}; + } + + Json::Reader r; + std::map> result; + r.visit_in_key(*baseline_value, real_baseline, result, BaselineDeserializer::instance); + if (r.errors().empty()) + { + return {std::move(result), expected_left_tag}; + } + else + { + Checks::exit_with_message( + VCPKG_LINE_INFO, "Error: failed to parse baseline:\n%s", Strings::join("\n", r.errors())); + } + } + + ExpectedS> load_baseline_versions(const VcpkgPaths& paths, + const fs::path& path_to_baseline, + StringView baseline) + { + auto maybe_contents = paths.get_filesystem().read_contents(path_to_baseline); + if (auto contents = maybe_contents.get()) + { + return parse_baseline_versions(*contents, baseline); + } + else if (maybe_contents.error() == std::errc::no_such_file_or_directory) + { + return {nullopt, expected_left_tag}; + } + else + { + return Strings::format("Error: failed to read file `%s`: %s", + fs::u8string(path_to_baseline), + maybe_contents.error().message()); + } + } +} + +namespace vcpkg +{ + std::unique_ptr>> + get_registry_implementation_deserializer(const fs::path& configuration_directory) + { + return std::make_unique(configuration_directory); + } + std::unique_ptr>> get_registry_array_deserializer( + const fs::path& configuration_directory) + { + return std::make_unique>( + "an array of registries", RegistryDeserializer(configuration_directory)); + } + + std::unique_ptr Registry::builtin_registry(std::string&& baseline) + { + return std::make_unique(std::move(baseline)); + } + + Registry::Registry(std::vector&& packages, std::unique_ptr&& impl) + : packages_(std::move(packages)), implementation_(std::move(impl)) + { + Checks::check_exit(VCPKG_LINE_INFO, implementation_ != nullptr); + } + RegistrySet::RegistrySet() : default_registry_(Registry::builtin_registry()), registries_() { } - const RegistryImpl* RegistrySet::registry_for_port(StringView name) const + const RegistryImplementation* RegistrySet::registry_for_port(StringView name) const { for (const auto& registry : registries()) { @@ -390,8 +911,45 @@ namespace vcpkg return default_registry(); } + Optional RegistrySet::baseline_for_port(const VcpkgPaths& paths, StringView port_name) const + { + auto impl = registry_for_port(port_name); + if (!impl) return nullopt; + return impl->get_baseline_version(paths, port_name); + } + 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::unique_ptr&& r) + { + default_registry_ = std::move(r); + } void RegistrySet::set_default_registry(std::nullptr_t) { default_registry_.reset(); } + + void RegistrySet::experimental_set_builtin_registry_baseline(StringView baseline) const + { + // to check if we should warn + bool default_registry_is_builtin = false; + if (auto builtin_registry = dynamic_cast(default_registry_.get())) + { + default_registry_is_builtin = true; + builtin_registry->m_baseline_identifier.assign(baseline.begin(), baseline.end()); + } + + if (!default_registry_is_builtin || registries_.size() != 0) + { + System::print2(System::Color::warning, + "Warning: when using the registries feature, one should not use `\"$x-default-baseline\"` " + "to set the baseline.\n", + " Instead, use the \"baseline\" field of the registry."); + } + + for (auto& reg : registries_) + { + if (auto builtin_registry = dynamic_cast(reg.implementation_.get())) + { + builtin_registry->m_baseline_identifier.assign(baseline.begin(), baseline.end()); + } + } + } } diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 869605ed57a2d9..856c6388266045 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -89,7 +89,7 @@ namespace vcpkg const fs::path& filepath) { Json::Reader reader; - ConfigurationDeserializer deserializer(args); + ConfigurationDeserializer deserializer(args, filepath.parent_path()); auto parsed_config_opt = reader.visit(obj, deserializer); if (!reader.errors().empty()) @@ -201,6 +201,17 @@ namespace vcpkg , m_env_cache(ff_settings.compiler_tracking) , m_ff_settings(ff_settings) { + auto platform_cache_home = System::get_platform_cache_home(); + if (auto cache_home = platform_cache_home.get()) + { + m_registries_path = std::move(*cache_home) / fs::u8path("vcpkg") / fs::u8path("registries"); + } + else + { + Debug::print( + "Failed to find platform cache home; the features depending on that will be unavailable. ", + platform_cache_home.error()); + } } Lazy> available_triplets; @@ -222,7 +233,12 @@ namespace vcpkg fs::path m_manifest_path; Configuration m_config; + fs::path m_registries_path; + FeatureFlagSettings m_ff_settings; + + fs::path registries_work_tree_dir() const { return m_registries_path / fs::u8path("git"); } + fs::path registries_dot_git_dir() const { return registries_work_tree_dir() / fs::u8path(".git"); } }; } diff --git a/toolsrc/src/vcpkg/versiondeserializers.cpp b/toolsrc/src/vcpkg/versiondeserializers.cpp index 5c57a99222e650..5fe28ac4727549 100644 --- a/toolsrc/src/vcpkg/versiondeserializers.cpp +++ b/toolsrc/src/vcpkg/versiondeserializers.cpp @@ -21,6 +21,7 @@ namespace Optional visit_string(Json::Reader& r, StringView sv) override { + (void)GIT_TREE; StringView pv(std::find(sv.begin(), sv.end(), '#'), sv.end()); if (pv.size() == 1) { @@ -147,75 +148,6 @@ namespace vcpkg namespace { - struct VersionDbEntryDeserializer final : Json::IDeserializer - { - static constexpr StringLiteral GIT_TREE = "git-tree"; - - StringView type_name() const override { return "a version database entry"; } - View valid_fields() const override - { - static const StringView u[] = {GIT_TREE}; - static const auto t = vcpkg::Util::Vectors::concat(schemed_deserializer_fields(), u); - return t; - } - - Optional visit_object(Json::Reader& r, const Json::Object& obj) override - { - VersionDbEntry ret; - - auto schemed_version = visit_required_schemed_deserializer(type_name(), r, obj); - ret.scheme = schemed_version.scheme; - ret.version = std::move(schemed_version.versiont); - - static Json::StringDeserializer git_tree_deserializer("a git object SHA"); - - r.required_object_field(type_name(), obj, GIT_TREE, ret.git_tree, git_tree_deserializer); - - return std::move(ret); - } - - static VersionDbEntryDeserializer instance; - }; - - struct VersionDbEntryArrayDeserializer final : Json::IDeserializer> - { - virtual StringView type_name() const override { return "an array of versions"; } - - virtual Optional> visit_array(Json::Reader& r, const Json::Array& arr) override - { - return r.array_elements(arr, VersionDbEntryDeserializer::instance); - } - - static VersionDbEntryArrayDeserializer instance; - }; - - VersionDbEntryDeserializer VersionDbEntryDeserializer::instance; - VersionDbEntryArrayDeserializer VersionDbEntryArrayDeserializer::instance; - - struct BaselineDeserializer final : Json::IDeserializer>> - { - StringView type_name() const override { return "a baseline object"; } - - Optional visit_object(Json::Reader& r, const Json::Object& obj) override - { - std::map> result; - - for (auto&& pr : obj) - { - const auto& version_value = pr.second; - VersionT version; - r.visit_in_key(version_value, pr.first, version, get_versiont_deserializer_instance()); - - result.emplace(pr.first.to_string(), std::move(version)); - } - - return std::move(result); - } - - static BaselineDeserializer instance; - }; - BaselineDeserializer BaselineDeserializer::instance; - struct VersionTDeserializer final : Json::IDeserializer { StringView type_name() const override { return "a version object"; } @@ -246,71 +178,4 @@ namespace namespace vcpkg { Json::IDeserializer& get_versiont_deserializer_instance() { return VersionTDeserializer::instance; } - - ExpectedS>> parse_baseline_file(Files::Filesystem& fs, - StringView baseline_name, - const fs::path& baseline_file_path) - { - if (!fs.exists(baseline_file_path)) - { - return Strings::format("Couldn't find `%s`", fs::u8string(baseline_file_path)); - } - - auto value = Json::parse_file(VCPKG_LINE_INFO, fs, baseline_file_path); - if (!value.first.is_object()) - { - return Strings::format("Error: `%s` does not have a top-level object.", fs::u8string(baseline_file_path)); - } - - const auto& obj = value.first.object(); - auto baseline_value = obj.get(baseline_name); - if (!baseline_value) - { - return Strings::format( - "Error: `%s` does not contain the baseline \"%s\"", fs::u8string(baseline_file_path), baseline_name); - } - - Json::Reader r; - std::map> result; - r.visit_in_key(*baseline_value, baseline_name, result, BaselineDeserializer::instance); - if (!r.errors().empty()) - { - return Strings::format( - "Error: failed to parse `%s`:\n%s", fs::u8string(baseline_file_path), Strings::join("\n", r.errors())); - } - return result; - } - - ExpectedS> parse_versions_file(Files::Filesystem& fs, - StringView port_name, - const fs::path& versions_file_path) - { - (void)port_name; - if (!fs.exists(versions_file_path)) - { - return Strings::format("Couldn't find the versions database file: %s", fs::u8string(versions_file_path)); - } - - auto versions_json = Json::parse_file(VCPKG_LINE_INFO, fs, versions_file_path); - if (!versions_json.first.is_object()) - { - return Strings::format("Error: `%s` does not have a top level object.", fs::u8string(versions_file_path)); - } - - const auto& versions_object = versions_json.first.object(); - auto maybe_versions_array = versions_object.get("versions"); - if (!maybe_versions_array || !maybe_versions_array->is_array()) - { - return Strings::format("Error: `%s` does not contain a versions array.", fs::u8string(versions_file_path)); - } - - std::vector db_entries; - // Avoid warning treated as error. - if (maybe_versions_array != nullptr) - { - Json::Reader r; - r.visit_in_key(*maybe_versions_array, "versions", db_entries, VersionDbEntryArrayDeserializer::instance); - } - return db_entries; - } } diff --git a/toolsrc/src/vcpkg/versions.cpp b/toolsrc/src/vcpkg/versions.cpp index 5ea2a8182e5f73..239c0e72859a0e 100644 --- a/toolsrc/src/vcpkg/versions.cpp +++ b/toolsrc/src/vcpkg/versions.cpp @@ -244,4 +244,4 @@ namespace vcpkg::Versions Checks::unreachable(VCPKG_LINE_INFO); } -} \ No newline at end of file +} From 96b9c3040382346c50fc40ae7b7ded4bbc849b3b Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 14 Dec 2020 15:00:09 -0800 Subject: [PATCH 02/16] robert CRs --- toolsrc/src/vcpkg/configuration.cpp | 5 +---- toolsrc/src/vcpkg/portfileprovider.cpp | 28 +++++++++++++------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/toolsrc/src/vcpkg/configuration.cpp b/toolsrc/src/vcpkg/configuration.cpp index ca8c01cdf4c7ee..680a6365fdca3a 100644 --- a/toolsrc/src/vcpkg/configuration.cpp +++ b/toolsrc/src/vcpkg/configuration.cpp @@ -42,10 +42,7 @@ namespace vcpkg if (!r.errors().empty()) { - System::print2(System::Color::error, "Errors occurred while parsing configuration.\n"); - for (auto&& msg : r.errors()) - System::print2(" ", msg, '\n'); - Checks::exit_fail(VCPKG_LINE_INFO); + return nullopt; } for (Registry& reg : regs) diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index c1e08d779dd93b..5d532cb7814d1f 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -376,24 +376,24 @@ namespace vcpkg::PortFileProvider return cache_it->second; } - auto entry_it = m_impl->entry_cache.find(version_spec.port_name); - if (entry_it == m_impl->entry_cache.end()) + auto path_cache_it = m_impl->path_cache.find(version_spec); + if (path_cache_it == m_impl->path_cache.end()) { - auto reg_for_port = - m_impl->get_paths().get_configuration().registry_set.registry_for_port(version_spec.port_name); - - if (!reg_for_port) + auto entry_it = m_impl->entry_cache.find(version_spec.port_name); + if (entry_it == m_impl->entry_cache.end()) { - return Strings::format("Error: no registry set up for port %s", version_spec.port_name); - } + auto reg_for_port = + m_impl->get_paths().get_configuration().registry_set.registry_for_port(version_spec.port_name); - auto entry = reg_for_port->get_port_entry(m_impl->get_paths(), version_spec.port_name); - entry_it = m_impl->entry_cache.emplace(version_spec.port_name, std::move(entry)).first; - } + if (!reg_for_port) + { + return Strings::format("Error: no registry set up for port %s", version_spec.port_name); + } + + auto entry = reg_for_port->get_port_entry(m_impl->get_paths(), version_spec.port_name); + entry_it = m_impl->entry_cache.emplace(version_spec.port_name, std::move(entry)).first; + } - auto path_cache_it = m_impl->path_cache.find(version_spec); - if (path_cache_it == m_impl->path_cache.end()) - { auto maybe_path = entry_it->second->get_path_to_version(m_impl->get_paths(), version_spec.version); if (auto p = maybe_path.get()) { From e0b0ddd30d367ecdfb1cc39811690181bc2a27c3 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 14 Dec 2020 15:12:24 -0800 Subject: [PATCH 03/16] Fix nicole CRs. --- toolsrc/src/vcpkg/registries.cpp | 15 +-------------- toolsrc/src/vcpkg/vcpkgpaths.cpp | 16 ---------------- toolsrc/src/vcpkg/versiondeserializers.cpp | 1 - 3 files changed, 1 insertion(+), 31 deletions(-) diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index 7d2989c89df4cf..61b734f04eadf3 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -591,7 +591,6 @@ namespace constexpr static StringLiteral KIND = "kind"; constexpr static StringLiteral BASELINE = "baseline"; constexpr static StringLiteral PATH = "path"; - constexpr static StringLiteral REPO = "repository"; constexpr static StringLiteral KIND_BUILTIN = "builtin"; constexpr static StringLiteral KIND_FILESYSTEM = "filesystem"; @@ -611,7 +610,6 @@ namespace constexpr StringLiteral RegistryImplDeserializer::KIND; constexpr StringLiteral RegistryImplDeserializer::BASELINE; constexpr StringLiteral RegistryImplDeserializer::PATH; - constexpr StringLiteral RegistryImplDeserializer::REPO; constexpr StringLiteral RegistryImplDeserializer::KIND_BUILTIN; constexpr StringLiteral RegistryImplDeserializer::KIND_FILESYSTEM; @@ -632,7 +630,7 @@ namespace View RegistryImplDeserializer::valid_fields() const { - static const StringView t[] = {KIND, BASELINE, PATH, REPO}; + static const StringView t[] = {KIND, BASELINE, PATH}; return t; } View valid_builtin_fields() @@ -654,16 +652,6 @@ namespace }; return t; } - View valid_git_fields() - { - static const StringView t[] = { - RegistryImplDeserializer::KIND, - RegistryImplDeserializer::BASELINE, - RegistryImplDeserializer::REPO, - RegistryDeserializer::PACKAGES, - }; - return t; - } Optional> RegistryImplDeserializer::visit_null(Json::Reader&) { @@ -718,7 +706,6 @@ namespace RegistryImplDeserializer::KIND, RegistryImplDeserializer::BASELINE, RegistryImplDeserializer::PATH, - RegistryImplDeserializer::REPO, PACKAGES, }; return t; diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 856c6388266045..d03af0a3629b04 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -201,17 +201,6 @@ namespace vcpkg , m_env_cache(ff_settings.compiler_tracking) , m_ff_settings(ff_settings) { - auto platform_cache_home = System::get_platform_cache_home(); - if (auto cache_home = platform_cache_home.get()) - { - m_registries_path = std::move(*cache_home) / fs::u8path("vcpkg") / fs::u8path("registries"); - } - else - { - Debug::print( - "Failed to find platform cache home; the features depending on that will be unavailable. ", - platform_cache_home.error()); - } } Lazy> available_triplets; @@ -233,12 +222,7 @@ namespace vcpkg fs::path m_manifest_path; Configuration m_config; - fs::path m_registries_path; - FeatureFlagSettings m_ff_settings; - - fs::path registries_work_tree_dir() const { return m_registries_path / fs::u8path("git"); } - fs::path registries_dot_git_dir() const { return registries_work_tree_dir() / fs::u8path(".git"); } }; } diff --git a/toolsrc/src/vcpkg/versiondeserializers.cpp b/toolsrc/src/vcpkg/versiondeserializers.cpp index 5fe28ac4727549..ce0667a84f749d 100644 --- a/toolsrc/src/vcpkg/versiondeserializers.cpp +++ b/toolsrc/src/vcpkg/versiondeserializers.cpp @@ -21,7 +21,6 @@ namespace Optional visit_string(Json::Reader& r, StringView sv) override { - (void)GIT_TREE; StringView pv(std::find(sv.begin(), sv.end(), '#'), sv.end()); if (pv.size() == 1) { From b2cdfd132d6cd893cf72146f122ae1df042875b0 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 14 Dec 2020 15:57:24 -0800 Subject: [PATCH 04/16] fix minor logic bug in overlay ports --- toolsrc/src/vcpkg/portfileprovider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index 5d532cb7814d1f..af7409c625ef48 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -127,7 +127,7 @@ namespace vcpkg::PortFileProvider if (scf->core_paragraph->name == spec) { auto res = std::make_unique(); - res->path = std::move(ports_dir); + res->path = std::move(ports_spec); res->version = VersionT{scf->core_paragraph->version, scf->core_paragraph->port_version}; return res; } From ac58c58314ca30e11f828d76601d495b56087655 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 14 Dec 2020 19:08:02 -0800 Subject: [PATCH 05/16] add a comment explaining GitRegistryEntry --- toolsrc/src/vcpkg/registries.cpp | 38 ++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index 61b734f04eadf3..72b31f01109ef5 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -20,7 +20,11 @@ namespace using Baseline = std::map>; - struct GitRegistryEntry final + // this class is an implementation detail of `BuiltinRegistryEntry`; + // when `BuiltinRegistryEntry` is using a port versions file for a port, + // it uses this as it's underlying type; + // when `BuiltinRegistryEntry` is using a port tree, it uses the scfl + struct GitRegistryEntry { explicit GitRegistryEntry(std::string&& port_name) : port_name(port_name) { } @@ -66,22 +70,6 @@ namespace VersionT scfl_version; // this exists so that we can return a pointer to it }; - struct BuiltinRegistry final : RegistryImplementation - { - BuiltinRegistry(std::string&& baseline) : m_baseline_identifier(std::move(baseline)) { } - - std::unique_ptr get_port_entry(const VcpkgPaths& paths, StringView port_name) const override; - - void get_all_port_names(std::vector&, const VcpkgPaths&) const override; - - Optional get_baseline_version(const VcpkgPaths& paths, StringView port_name) const override; - - ~BuiltinRegistry() = default; - - std::string m_baseline_identifier; - DelayedInit m_baseline; - }; - struct FilesystemRegistryEntry final : RegistryEntry { explicit FilesystemRegistryEntry(std::string&& port_name) : port_name(port_name) { } @@ -98,6 +86,22 @@ namespace std::vector version_paths; }; + struct BuiltinRegistry final : RegistryImplementation + { + BuiltinRegistry(std::string&& baseline) : m_baseline_identifier(std::move(baseline)) { } + + std::unique_ptr get_port_entry(const VcpkgPaths& paths, StringView port_name) const override; + + void get_all_port_names(std::vector&, const VcpkgPaths&) const override; + + Optional get_baseline_version(const VcpkgPaths& paths, StringView port_name) const override; + + ~BuiltinRegistry() = default; + + std::string m_baseline_identifier; + DelayedInit m_baseline; + }; + struct FilesystemRegistry final : RegistryImplementation { FilesystemRegistry(fs::path&& path, std::string&& baseline) From e1562bf46905dd8f1a525b7e58eb1e00f92480be Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 16 Dec 2020 12:25:13 -0800 Subject: [PATCH 06/16] Billy CRs --- toolsrc/include/vcpkg/base/files.h | 7 +- toolsrc/include/vcpkg/configuration.h | 7 + .../include/vcpkg/configurationdeserializer.h | 47 --- toolsrc/include/vcpkg/registries.h | 6 + toolsrc/src/vcpkg/configuration.cpp | 41 ++- toolsrc/src/vcpkg/portfileprovider.cpp | 30 +- toolsrc/src/vcpkg/registries.cpp | 307 +++++++++--------- toolsrc/src/vcpkg/vcpkgpaths.cpp | 5 +- 8 files changed, 219 insertions(+), 231 deletions(-) delete mode 100644 toolsrc/include/vcpkg/configurationdeserializer.h diff --git a/toolsrc/include/vcpkg/base/files.h b/toolsrc/include/vcpkg/base/files.h index ca95327340db22..69ec41fe311d1f 100644 --- a/toolsrc/include/vcpkg/base/files.h +++ b/toolsrc/include/vcpkg/base/files.h @@ -239,8 +239,13 @@ namespace vcpkg::Files virtual void current_path(const fs::path& path, std::error_code&) = 0; void current_path(const fs::path& path, LineInfo li); + // if the path does not exist, then (try_|)take_exclusive_file_lock attempts to create the file + // (but not any path members above the file itself) + // in other words, if `/a/b` is a directory, and you're attempting to lock `/a/b/c`, + // then these lock functions create `/a/b/c` if it doesn't exist; + // however, if `/a/b` doesn't exist, then the functions will fail. + // waits forever for the file lock - // creates a non-existent file virtual fs::SystemHandle take_exclusive_file_lock(const fs::path& path, std::error_code&) = 0; // waits, at most, 1.5 seconds, for the file lock virtual fs::SystemHandle try_take_exclusive_file_lock(const fs::path& path, std::error_code&) = 0; diff --git a/toolsrc/include/vcpkg/configuration.h b/toolsrc/include/vcpkg/configuration.h index 4cba88fe5e06e5..94fa519d990a49 100644 --- a/toolsrc/include/vcpkg/configuration.h +++ b/toolsrc/include/vcpkg/configuration.h @@ -1,6 +1,10 @@ #pragma once #include +#include + +#include +#include #include @@ -13,4 +17,7 @@ namespace vcpkg // taken care of in RegistrySet. RegistrySet registry_set; }; + + std::unique_ptr> make_configuration_deserializer( + const VcpkgCmdArguments& args, const fs::path& config_directory); } diff --git a/toolsrc/include/vcpkg/configurationdeserializer.h b/toolsrc/include/vcpkg/configurationdeserializer.h deleted file mode 100644 index 8d978e1ea270bc..00000000000000 --- a/toolsrc/include/vcpkg/configurationdeserializer.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include - -namespace vcpkg -{ - std::unique_ptr>> - get_registry_implementation_deserializer(const fs::path& configuration_directory); - - std::unique_ptr>> get_registry_array_deserializer( - const fs::path& configuration_directory); - - 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 View valid_fields() const override - { - constexpr static StringView t[] = {DEFAULT_REGISTRY, REGISTRIES}; - return t; - } - - virtual Optional visit_object(Json::Reader& r, const Json::Object& obj) override; - - ConfigurationDeserializer(const VcpkgCmdArguments& args, const fs::path& configuration_directory); - - private: - bool print_json; - - bool registries_enabled; - - fs::path configuration_directory; - }; -} diff --git a/toolsrc/include/vcpkg/registries.h b/toolsrc/include/vcpkg/registries.h index 2acfdc941d9775..d20dcdbbdc650f 100644 --- a/toolsrc/include/vcpkg/registries.h +++ b/toolsrc/include/vcpkg/registries.h @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -92,4 +93,9 @@ namespace vcpkg std::vector registries_; }; + std::unique_ptr>> + get_registry_implementation_deserializer(const fs::path& configuration_directory); + + std::unique_ptr>> get_registry_array_deserializer( + const fs::path& configuration_directory); } diff --git a/toolsrc/src/vcpkg/configuration.cpp b/toolsrc/src/vcpkg/configuration.cpp index 680a6365fdca3a..737563deda1ef0 100644 --- a/toolsrc/src/vcpkg/configuration.cpp +++ b/toolsrc/src/vcpkg/configuration.cpp @@ -2,11 +2,39 @@ #include #include -#include #include -namespace vcpkg +namespace { + using 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 View valid_fields() const override + { + constexpr static StringView t[] = {DEFAULT_REGISTRY, REGISTRIES}; + return t; + } + + virtual Optional visit_object(Json::Reader& r, const Json::Object& obj) override; + + ConfigurationDeserializer(const VcpkgCmdArguments& args, const fs::path& configuration_directory); + + private: + bool print_json; + + bool registries_enabled; + + fs::path configuration_directory; + }; + + constexpr StringLiteral ConfigurationDeserializer::DEFAULT_REGISTRY; + constexpr StringLiteral ConfigurationDeserializer::REGISTRIES; + Optional ConfigurationDeserializer::visit_object(Json::Reader& r, const Json::Object& obj) { RegistrySet registries; @@ -61,9 +89,6 @@ namespace vcpkg return Configuration{std::move(registries)}; } - constexpr StringLiteral ConfigurationDeserializer::DEFAULT_REGISTRY; - constexpr StringLiteral ConfigurationDeserializer::REGISTRIES; - ConfigurationDeserializer::ConfigurationDeserializer(const VcpkgCmdArguments& args, const fs::path& configuration_directory) : configuration_directory(configuration_directory) @@ -73,3 +98,9 @@ namespace vcpkg } } + +std::unique_ptr> vcpkg::make_configuration_deserializer( + const VcpkgCmdArguments& args, const fs::path& config_directory) +{ + return std::make_unique(args, config_directory); +} diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index f6723872cbd4bc..eb61662d2de36f 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -21,6 +21,8 @@ namespace struct OverlayRegistryEntry final : RegistryEntry { + OverlayRegistryEntry(fs::path&& p, VersionT&& v) : path(p), version(v) { } + View get_port_versions() const override { return {&version, 1}; } ExpectedS get_path_to_version(const VcpkgPaths&, const VersionT& v) const override { @@ -28,8 +30,8 @@ namespace return path; } - VersionT version; fs::path path; + VersionT version; }; } @@ -101,10 +103,7 @@ namespace vcpkg::PortFileProvider auto& scf = *scfp; if (scf->core_paragraph->name == spec) { - auto res = std::make_unique(); - res->path = std::move(ports_dir); - res->version = VersionT{scf->core_paragraph->version, scf->core_paragraph->port_version}; - return res; + return std::make_unique(fs::path(ports_dir), scf->to_versiont()); } } else @@ -126,10 +125,7 @@ namespace vcpkg::PortFileProvider auto& scf = *scfp; if (scf->core_paragraph->name == spec) { - auto res = std::make_unique(); - res->path = std::move(ports_spec); - res->version = VersionT{scf->core_paragraph->version, scf->core_paragraph->port_version}; - return res; + return std::make_unique(std::move(ports_spec), scf->to_versiont()); } Checks::exit_with_message(VCPKG_LINE_INFO, "Error: Failed to load port from %s: names did not match: '%s' != '%s'", @@ -301,7 +297,7 @@ namespace vcpkg::PortFileProvider { struct BaselineProviderImpl : IBaselineProvider, Util::ResourceBase { - BaselineProviderImpl(const VcpkgPaths& paths_) : paths(paths_) {} + BaselineProviderImpl(const VcpkgPaths& paths_) : paths(paths_) { } virtual Optional get_baseline_version(StringView port_name) const override { @@ -343,12 +339,12 @@ namespace vcpkg::PortFileProvider } else { - Checks::exit_with_message(VCPKG_LINE_INFO, "Error: Could not find a definition for port %s", port_name); + Checks::exit_with_message( + VCPKG_LINE_INFO, "Error: Could not find a definition for port %s", port_name); } } - ExpectedS get_control_file( - const VersionSpec& version_spec) const override + ExpectedS get_control_file(const VersionSpec& version_spec) const override { auto cache_it = m_control_cache.find(version_spec); if (cache_it != m_control_cache.end()) @@ -385,13 +381,13 @@ namespace vcpkg::PortFileProvider { return m_control_cache .emplace(version_spec, - SourceControlFileLocation{std::move(*scf), std::move(port_directory)}) + SourceControlFileLocation{std::move(*scf), std::move(port_directory)}) .first->second; } return Strings::format("Error: Failed to load port from %s: names did not match: '%s' != '%s'", - fs::u8string(port_directory), - version_spec.port_name, - scf->get()->core_paragraph->name); + fs::u8string(port_directory), + version_spec.port_name, + scf->get()->core_paragraph->name); } print_error_message(maybe_control_file.error()); diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index 72b31f01109ef5..9a301b2624c53a 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -175,16 +174,15 @@ namespace for (auto file : fs::directory_iterator(super_directory)) { auto filename = fs::u8string(file.path().filename()); - if (Strings::ends_with(filename, ".json")) + if (!Strings::ends_with(filename, ".json")) continue; + + auto port_name = filename.substr(0, filename.size() - 5); + if (!Json::PackageNameDeserializer::is_package_name(port_name)) { - auto port_name = filename.substr(0, filename.size() - 5); - if (!Json::PackageNameDeserializer::is_package_name(port_name)) - { - Checks::exit_with_message( - VCPKG_LINE_INFO, "Error: found invalid port version file name: `%s`.", fs::u8string(file)); - } - out.push_back(std::move(port_name)); + Checks::exit_with_message( + VCPKG_LINE_INFO, "Error: found invalid port version file name: `%s`.", fs::u8string(file)); } + out.push_back(std::move(port_name)); } } } @@ -213,97 +211,95 @@ namespace } return res; } - else + + // Fall back to current available version + auto port_directory = paths.builtin_ports_directory() / fs::u8path(port_name); + if (paths.get_filesystem().exists(port_directory)) { - // Fall back to current available version - auto port_directory = paths.builtin_ports_directory() / fs::u8path(port_name); - if (paths.get_filesystem().exists(port_directory)) + auto found_scf = Paragraphs::try_load_port(paths.get_filesystem(), port_directory); + if (auto scfp = found_scf.get()) { - auto found_scf = Paragraphs::try_load_port(paths.get_filesystem(), port_directory); - if (auto scfp = found_scf.get()) + auto& scf = *scfp; + auto maybe_error = scf->check_against_feature_flags(port_directory, paths.get_feature_flags()); + if (maybe_error) { - auto& scf = *scfp; - auto maybe_error = scf->check_against_feature_flags(port_directory, paths.get_feature_flags()); - if (maybe_error) - Checks::exit_with_message(VCPKG_LINE_INFO, "Parsing manifest failed: %s", *maybe_error.get()); + Checks::exit_with_message(VCPKG_LINE_INFO, "Parsing manifest failed: %s", *maybe_error.get()); + } - if (scf->core_paragraph->name == port_name) - { - return std::make_unique( - std::make_unique(std::move(scf), std::move(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), - port_name, - scf->core_paragraph->name); + if (scf->core_paragraph->name == port_name) + { + return std::make_unique( + std::make_unique(std::move(scf), std::move(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), + port_name, + scf->core_paragraph->name); } - - return nullptr; } + + return nullptr; } - Optional BuiltinRegistry::get_baseline_version(const VcpkgPaths& paths, StringView port_name) const + Baseline parse_builtin_baseline(const VcpkgPaths& paths, StringView baseline_identifier) { - const auto& baseline = m_baseline.get([this, &paths]() -> Baseline { - auto path_to_baseline = paths.root / fs::u8path("port_versions") / fs::u8path("baseline.json"); - auto res_baseline = load_baseline_versions(paths, path_to_baseline, m_baseline_identifier); + auto path_to_baseline = paths.root / fs::u8path("port_versions") / fs::u8path("baseline.json"); + auto res_baseline = load_baseline_versions(paths, path_to_baseline, baseline_identifier); - if (!res_baseline.has_value()) - { - Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error()); - } - auto opt_baseline = res_baseline.get(); - if (auto p = opt_baseline->get()) - { - return std::move(*p); - } + if (!res_baseline.has_value()) + { + Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error()); + } + auto opt_baseline = res_baseline.get(); + if (auto p = opt_baseline->get()) + { + return std::move(*p); + } - if (m_baseline_identifier.empty()) - { - return {}; - } + if (baseline_identifier.size() == 0) + { + return {}; + } - if (m_baseline_identifier == "default") - { - Checks::exit_with_message( - VCPKG_LINE_INFO, - "Couldn't find explicitly specified baseline `\"default\"` in the baseline file.", - m_baseline_identifier); - } + if (baseline_identifier == "default") + { + Checks::exit_with_message(VCPKG_LINE_INFO, + "Couldn't find explicitly specified baseline `\"default\"` in the baseline file.", + baseline_identifier); + } - // attempt to check out the baseline: - auto maybe_path = get_git_baseline_json_path(paths, m_baseline_identifier); - if (auto path_to_git_baseline = maybe_path.get()) - { - res_baseline = load_baseline_versions(paths, *path_to_git_baseline); - if (!res_baseline.has_value()) - { - Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error()); - } - opt_baseline = res_baseline.get(); - if (auto p = opt_baseline->get()) - { - return std::move(*p); - } - else - { - Checks::exit_with_message(VCPKG_LINE_INFO, - "Couldn't find explicitly specified baseline `\"%s\"` in the baseline " - "file, and the `\"default\"` baseline does not exist at that commit.", - m_baseline_identifier); - } - } - else - { - Checks::exit_with_message(VCPKG_LINE_INFO, - "Couldn't find explicitly specified baseline `\"%s\"` in the baseline file, " - "and there was no baseline at that commit or the commit didn't exist.\n%s", - m_baseline_identifier, - maybe_path.error()); - } - }); + // attempt to check out the baseline: + auto maybe_path = get_git_baseline_json_path(paths, baseline_identifier); + if (!maybe_path.has_value()) + { + Checks::exit_with_message(VCPKG_LINE_INFO, + "Couldn't find explicitly specified baseline `\"%s\"` in the baseline file, " + "and there was no baseline at that commit or the commit didn't exist.\n%s", + baseline_identifier, + maybe_path.error()); + } + + res_baseline = load_baseline_versions(paths, *maybe_path.get()); + if (!res_baseline.has_value()) + { + Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error()); + } + opt_baseline = res_baseline.get(); + if (auto p = opt_baseline->get()) + { + return std::move(*p); + } + + Checks::exit_with_message(VCPKG_LINE_INFO, + "Couldn't find explicitly specified baseline `\"%s\"` in the baseline " + "file, and the `\"default\"` baseline does not exist at that commit.", + baseline_identifier); + } + Optional BuiltinRegistry::get_baseline_version(const VcpkgPaths& paths, StringView port_name) const + { + const auto& baseline = m_baseline.get( + [this, &paths]() -> Baseline { return parse_builtin_baseline(paths, m_baseline_identifier); }); auto it = baseline.find(port_name); if (it != baseline.end()) @@ -344,35 +340,35 @@ namespace // } BuiltinRegistry::RegistryImplementation // { FilesystemRegistry::RegistryImplementation - Optional FilesystemRegistry::get_baseline_version(const VcpkgPaths& paths, StringView port_name) const + Baseline parse_filesystem_baseline(const VcpkgPaths& paths, const fs::path& root, StringView baseline_identifier) { - const auto& baseline = m_baseline.get([this, &paths]() -> Baseline { - auto path_to_baseline = m_path / fs::u8path("port_versions") / fs::u8path("baseline.json"); - auto res_baseline = load_baseline_versions(paths, path_to_baseline, m_baseline_identifier); - if (auto opt_baseline = res_baseline.get()) + auto path_to_baseline = root / fs::u8path("port_versions") / fs::u8path("baseline.json"); + auto res_baseline = load_baseline_versions(paths, path_to_baseline, baseline_identifier); + if (auto opt_baseline = res_baseline.get()) + { + if (auto p = opt_baseline->get()) { - if (auto p = opt_baseline->get()) - { - return std::move(*p); - } - else if (m_baseline_identifier.empty()) - { - return {}; - } - else - { - Checks::exit_with_message( - VCPKG_LINE_INFO, - "Error: could not find explicitly specified baseline `\"%s\"` in baseline file `%s`.", - m_baseline_identifier, - fs::u8string(path_to_baseline)); - } + return std::move(*p); } - else + + if (baseline_identifier.size() == 0) { - Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error()); + return {}; } - }); + + Checks::exit_with_message( + VCPKG_LINE_INFO, + "Error: could not find explicitly specified baseline `\"%s\"` in baseline file `%s`.", + baseline_identifier, + fs::u8string(path_to_baseline)); + } + + Checks::exit_with_message(VCPKG_LINE_INFO, res_baseline.error()); + } + Optional FilesystemRegistry::get_baseline_version(const VcpkgPaths& paths, StringView port_name) const + { + const auto& baseline = m_baseline.get( + [this, &paths]() -> Baseline { return parse_filesystem_baseline(paths, m_path, m_baseline_identifier); }); auto it = baseline.find(port_name); if (it != baseline.end()) @@ -429,20 +425,19 @@ namespace const auto& git_tree = git_entry->git_trees[it - git_entry->port_versions.begin()]; return paths.git_checkout_port(paths.get_filesystem(), git_entry->port_name, git_tree); } - else if (scfl_version == version) + + if (scfl_version == version) { return scfl->source_location; } - else - { - auto& name = scfl->source_control_file->core_paragraph->name; - return Strings::format( - "Error: no version entry for %s at version %s.\n" - "We are currently using the version in the ports tree, since no %s.json was found in port_versions.", - name, - scfl->to_versiont().to_string(), - name); - } + + auto& name = scfl->source_control_file->core_paragraph->name; + return Strings::format( + "Error: no version entry for %s at version %s.\n" + "We are currently using the version in the ports tree, since no %s.json was found in port_versions.", + name, + scfl->to_versiont().to_string(), + name); } // } BuiltinRegistryEntry::RegistryEntry @@ -757,49 +752,45 @@ namespace } auto maybe_contents = fs.read_contents(versions_file_path); - if (auto contents = maybe_contents.get()) + if (!maybe_contents.has_value()) { - auto maybe_versions_json = Json::parse(*contents); - if (!maybe_versions_json.has_value()) - { - return Strings::format("Error: failed to parse versions file for `%s`: %s", - port_name, - maybe_versions_json.error()->format()); - } - if (!maybe_versions_json.get()->first.is_object()) - { - return Strings::format("Error: versions file for `%s` does not have a top level object.", port_name); - } + return Strings::format("Failed to load the versions database file %s: %s", + fs::u8string(versions_file_path), + maybe_contents.error().message()); + } - const auto& versions_object = maybe_versions_json.get()->first.object(); - auto maybe_versions_array = versions_object.get("versions"); - if (!maybe_versions_array || !maybe_versions_array->is_array()) - { - return Strings::format("Error: versions file for `%s` does not contain a versions array.", port_name); - } + auto maybe_versions_json = Json::parse(*maybe_contents.get()); + if (!maybe_versions_json.has_value()) + { + return Strings::format( + "Error: failed to parse versions file for `%s`: %s", port_name, maybe_versions_json.error()->format()); + } + if (!maybe_versions_json.get()->first.is_object()) + { + return Strings::format("Error: versions file for `%s` does not have a top level object.", port_name); + } - std::vector db_entries; - VersionDbEntryArrayDeserializer deserializer{type, registry_root}; - // Avoid warning treated as error. - if (maybe_versions_array != nullptr) - { - Json::Reader r; - r.visit_in_key(*maybe_versions_array, "versions", db_entries, deserializer); - if (!r.errors().empty()) - { - return Strings::format("Error: failed to parse versions file for `%s`:\n%s", - port_name, - Strings::join("\n", r.errors())); - } - } - return db_entries; + const auto& versions_object = maybe_versions_json.get()->first.object(); + auto maybe_versions_array = versions_object.get("versions"); + if (!maybe_versions_array || !maybe_versions_array->is_array()) + { + return Strings::format("Error: versions file for `%s` does not contain a versions array.", port_name); } - else + + std::vector db_entries; + VersionDbEntryArrayDeserializer deserializer{type, registry_root}; + // Avoid warning treated as error. + if (maybe_versions_array != nullptr) { - return Strings::format("Failed to load the versions database file %s: %s", - fs::u8string(versions_file_path), - maybe_contents.error().message()); + Json::Reader r; + r.visit_in_key(*maybe_versions_array, "versions", db_entries, deserializer); + if (!r.errors().empty()) + { + return Strings::format( + "Error: failed to parse versions file for `%s`:\n%s", port_name, Strings::join("\n", r.errors())); + } } + return db_entries; } ExpectedS> parse_baseline_versions(StringView contents, StringView baseline) diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 682d2ed59a9852..fc082197361fd1 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -89,9 +88,9 @@ namespace vcpkg const fs::path& filepath) { Json::Reader reader; - ConfigurationDeserializer deserializer(args, filepath.parent_path()); + auto deserializer = make_configuration_deserializer(args, filepath.parent_path()); - auto parsed_config_opt = reader.visit(obj, deserializer); + auto parsed_config_opt = reader.visit(obj, *deserializer); if (!reader.errors().empty()) { System::print2(System::Color::error, "Errors occurred while parsing ", fs::u8string(filepath), "\n"); From 7dcc5eb2e59d56abf8b5e996c293e1fcf9189767 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 16 Dec 2020 14:42:54 -0800 Subject: [PATCH 07/16] add unit tests for RegistrySet --- toolsrc/src/vcpkg-test/registries.cpp | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 toolsrc/src/vcpkg-test/registries.cpp diff --git a/toolsrc/src/vcpkg-test/registries.cpp b/toolsrc/src/vcpkg-test/registries.cpp new file mode 100644 index 00000000000000..5dfd13dec63e85 --- /dev/null +++ b/toolsrc/src/vcpkg-test/registries.cpp @@ -0,0 +1,54 @@ +#include + +#include + +using namespace vcpkg; + +namespace +{ + template + struct TestRegistryImplementation final : RegistryImplementation + { + std::unique_ptr get_port_entry(const VcpkgPaths&, StringView) const override { return nullptr; } + + void get_all_port_names(std::vector&, const VcpkgPaths&) const override { } + + Optional get_baseline_version(const VcpkgPaths&, StringView) const override { return nullopt; } + }; + + template + Registry make_registry(std::vector&& port_names) + { + return {std::move(port_names), std::make_unique>()}; + } +} + +TEST_CASE ("registry_set_selects_registry", "[registries]") +{ + RegistrySet set; + set.set_default_registry(std::make_unique>()); + + set.add_registry(make_registry<1>({"p1", "q1", "r1"})); + set.add_registry(make_registry<2>({"p2", "q2", "r2"})); + + auto reg = set.registry_for_port("p1"); + REQUIRE(reg); + CHECK(typeid(*reg) == typeid(TestRegistryImplementation<1>)); + reg = set.registry_for_port("r2"); + REQUIRE(reg); + CHECK(typeid(*reg) == typeid(TestRegistryImplementation<2>)); + reg = set.registry_for_port("a"); + REQUIRE(reg); + CHECK(typeid(*reg) == typeid(TestRegistryImplementation<0>)); + + set.set_default_registry(nullptr); + + reg = set.registry_for_port("q1"); + REQUIRE(reg); + CHECK(typeid(*reg) == typeid(TestRegistryImplementation<1>)); + reg = set.registry_for_port("p2"); + REQUIRE(reg); + CHECK(typeid(*reg) == typeid(TestRegistryImplementation<2>)); + reg = set.registry_for_port("a"); + CHECK_FALSE(reg); +} From fdf651f81f86996c9a84a0063151fc736a15a162 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 16 Dec 2020 15:07:36 -0800 Subject: [PATCH 08/16] testing: add e2e testing for registries --- scripts/e2e_ports/vcpkg-internal-e2e-test-port/portfile.cmake | 1 + scripts/e2e_ports/vcpkg-internal-e2e-test-port/vcpkg.json | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 scripts/e2e_ports/vcpkg-internal-e2e-test-port/portfile.cmake create mode 100644 scripts/e2e_ports/vcpkg-internal-e2e-test-port/vcpkg.json diff --git a/scripts/e2e_ports/vcpkg-internal-e2e-test-port/portfile.cmake b/scripts/e2e_ports/vcpkg-internal-e2e-test-port/portfile.cmake new file mode 100644 index 00000000000000..065116c276adcf --- /dev/null +++ b/scripts/e2e_ports/vcpkg-internal-e2e-test-port/portfile.cmake @@ -0,0 +1 @@ +set(VCPKG_POLICY_EMPTY_PACKAGE enabled) diff --git a/scripts/e2e_ports/vcpkg-internal-e2e-test-port/vcpkg.json b/scripts/e2e_ports/vcpkg-internal-e2e-test-port/vcpkg.json new file mode 100644 index 00000000000000..a25da6d2369849 --- /dev/null +++ b/scripts/e2e_ports/vcpkg-internal-e2e-test-port/vcpkg.json @@ -0,0 +1,4 @@ +{ + "name": "vcpkg-internal-e2e-test-port", + "version-string": "1.0.0" +} From 916f6e7c5bba28dbbe1b6c927273a627e31ff8c7 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Wed, 16 Dec 2020 16:32:02 -0800 Subject: [PATCH 09/16] Add e2e tests found a bug! --- .../end-to-end-tests-dir/create.ps1 | 4 +- .../integrate-install.ps1 | 14 ++--- .../end-to-end-tests-dir/registries.ps1 | 13 +++++ .../end-to-end-tests-dir/spaces.ps1 | 4 +- .../end-to-end-tests-prelude.ps1 | 21 ++++--- scripts/azure-pipelines/end-to-end-tests.ps1 | 2 +- scripts/e2e_port_versions/baseline.json | 3 + .../v-/vcpkg-internal-e2e-test-port.json | 8 +++ .../vcpkg-uses-test-cmake/portfile.cmake | 0 .../vcpkg-uses-test-cmake/vcpkg.json | 0 .../portfile.cmake | 0 .../vcpkg.json | 0 toolsrc/include/vcpkg/vcpkgcmdarguments.h | 2 + toolsrc/include/vcpkg/vcpkgpaths.h | 1 + toolsrc/src/vcpkg/registries.cpp | 58 ++++++++++--------- toolsrc/src/vcpkg/vcpkgcmdarguments.cpp | 1 + toolsrc/src/vcpkg/vcpkgpaths.cpp | 2 + 17 files changed, 84 insertions(+), 49 deletions(-) create mode 100644 scripts/azure-pipelines/end-to-end-tests-dir/registries.ps1 create mode 100644 scripts/e2e_port_versions/baseline.json create mode 100644 scripts/e2e_port_versions/v-/vcpkg-internal-e2e-test-port.json rename scripts/e2e_ports/{ => overlays}/vcpkg-uses-test-cmake/portfile.cmake (100%) rename scripts/e2e_ports/{ => overlays}/vcpkg-uses-test-cmake/vcpkg.json (100%) rename scripts/e2e_ports/{ => overlays}/vcpkg-uses-vcpkg-common-functions/portfile.cmake (100%) rename scripts/e2e_ports/{ => overlays}/vcpkg-uses-vcpkg-common-functions/vcpkg.json (100%) diff --git a/scripts/azure-pipelines/end-to-end-tests-dir/create.ps1 b/scripts/azure-pipelines/end-to-end-tests-dir/create.ps1 index 53686fe5095da5..9d59da5396e671 100644 --- a/scripts/azure-pipelines/end-to-end-tests-dir/create.ps1 +++ b/scripts/azure-pipelines/end-to-end-tests-dir/create.ps1 @@ -1,8 +1,8 @@ . $PSScriptRoot/../end-to-end-tests-prelude.ps1 # Test vcpkg create -$CurrentTest = "create zlib" -Write-Host $CurrentTest +$Script:CurrentTest = "create zlib" +Write-Host $Script:CurrentTest ./vcpkg --x-builtin-ports-root=$TestingRoot/ports create zlib https://github.com/madler/zlib/archive/v1.2.11.tar.gz zlib-1.2.11.tar.gz Throw-IfFailed diff --git a/scripts/azure-pipelines/end-to-end-tests-dir/integrate-install.ps1 b/scripts/azure-pipelines/end-to-end-tests-dir/integrate-install.ps1 index 38769775141764..38362ba8cb777d 100644 --- a/scripts/azure-pipelines/end-to-end-tests-dir/integrate-install.ps1 +++ b/scripts/azure-pipelines/end-to-end-tests-dir/integrate-install.ps1 @@ -2,24 +2,24 @@ if (-not $IsLinux -and -not $IsMacOS) { . $PSScriptRoot/../end-to-end-tests-prelude.ps1 # Test msbuild props and targets - $CurrentTest = "zlib:x86-windows-static msbuild scripts\testing\integrate-install\..." - Write-Host $CurrentTest + $Script:CurrentTest = "zlib:x86-windows-static msbuild scripts\testing\integrate-install\..." + Write-Host $Script:CurrentTest ./vcpkg $commonArgs install zlib:x86-windows-static --x-binarysource=clear Throw-IfFailed foreach ($project in @("VcpkgTriplet", "VcpkgTriplet2", "VcpkgUseStatic", "VcpkgUseStatic2")) { - $CurrentTest = "msbuild scripts\testing\integrate-install\$project.vcxproj" + $Script:CurrentTest = "msbuild scripts\testing\integrate-install\$project.vcxproj" ./vcpkg $commonArgs env "msbuild scripts\testing\integrate-install\$project.vcxproj /p:VcpkgRoot=$TestingRoot /p:IntDir=$TestingRoot\int\ /p:OutDir=$TestingRoot\out\ " Throw-IfFailed Remove-Item -Recurse -Force $TestingRoot\int Remove-Item -Recurse -Force $TestingRoot\out } - $CurrentTest = "zlib:x86-windows msbuild scripts\testing\integrate-install\..." - Write-Host $CurrentTest + $Script:CurrentTest = "zlib:x86-windows msbuild scripts\testing\integrate-install\..." + Write-Host $Script:CurrentTest ./vcpkg $commonArgs install zlib:x86-windows --x-binarysource=clear Throw-IfFailed foreach ($project in @("Project1", "NoProps")) { - $CurrentTest = "msbuild scripts\testing\integrate-install\$project.vcxproj" - Write-Host $CurrentTest + $Script:CurrentTest = "msbuild scripts\testing\integrate-install\$project.vcxproj" + Write-Host $Script:CurrentTest ./vcpkg $commonArgs env "msbuild scripts\testing\integrate-install\$project.vcxproj /p:VcpkgRoot=$TestingRoot /p:IntDir=$TestingRoot\int\ /p:OutDir=$TestingRoot\out\ " Throw-IfFailed Remove-Item -Recurse -Force $TestingRoot\int diff --git a/scripts/azure-pipelines/end-to-end-tests-dir/registries.ps1 b/scripts/azure-pipelines/end-to-end-tests-dir/registries.ps1 new file mode 100644 index 00000000000000..403e6b95143859 --- /dev/null +++ b/scripts/azure-pipelines/end-to-end-tests-dir/registries.ps1 @@ -0,0 +1,13 @@ +. "$PSScriptRoot/../end-to-end-tests-prelude.ps1" + + +$commonArgs += @("--x-builtin-port-versions-dir=$PSScriptRoot/../../e2e_port_versions") + +Run-Vcpkg install @commonArgs 'vcpkg-internal-e2e-test-port' +Throw-IfNotFailed + +Run-Vcpkg install @commonArgs --feature-flags=registries 'vcpkg-internal-e2e-test-port' +Throw-IfFailed + +Run-Vcpkg install @commonArgs --feature-flags=registries 'zlib' +Throw-IfFailed diff --git a/scripts/azure-pipelines/end-to-end-tests-dir/spaces.ps1 b/scripts/azure-pipelines/end-to-end-tests-dir/spaces.ps1 index 49796c1b063218..b7aaf6462c6e42 100644 --- a/scripts/azure-pipelines/end-to-end-tests-dir/spaces.ps1 +++ b/scripts/azure-pipelines/end-to-end-tests-dir/spaces.ps1 @@ -1,8 +1,8 @@ . $PSScriptRoot/../end-to-end-tests-prelude.ps1 ##### Test spaces in the path -$CurrentTest = "zlib with spaces in path" -Write-Host $CurrentTest +$Script:CurrentTest = "zlib with spaces in path" +Write-Host $Script:CurrentTest ./vcpkg install zlib "--triplet" $Triplet ` "--no-binarycaching" ` "--x-buildtrees-root=$TestingRoot/build Trees" ` diff --git a/scripts/azure-pipelines/end-to-end-tests-prelude.ps1 b/scripts/azure-pipelines/end-to-end-tests-prelude.ps1 index 057df9fa66a8e5..0c675e9bf23506 100644 --- a/scripts/azure-pipelines/end-to-end-tests-prelude.ps1 +++ b/scripts/azure-pipelines/end-to-end-tests-prelude.ps1 @@ -12,9 +12,9 @@ $commonArgs = @( "--x-buildtrees-root=$buildtreesRoot", "--x-install-root=$installRoot", "--x-packages-root=$packagesRoot", - "--overlay-ports=scripts/e2e_ports" + "--overlay-ports=scripts/e2e_ports/overlays" ) -$CurrentTest = 'unassigned' +$Script:CurrentTest = 'unassigned' function Refresh-TestRoot { Remove-Item -Recurse -Force $TestingRoot -ErrorAction SilentlyContinue @@ -28,7 +28,7 @@ function Require-FileExists { [string]$File ) if (-Not (Test-Path $File)) { - throw "'$CurrentTest' failed to create file '$File'" + throw "'$Script:CurrentTest' failed to create file '$File'" } } @@ -38,26 +38,29 @@ function Require-FileNotExists { [string]$File ) if (Test-Path $File) { - throw "'$CurrentTest' should not have created file '$File'" + throw "'$Script:CurrentTest' should not have created file '$File'" } } function Throw-IfFailed { if ($LASTEXITCODE -ne 0) { - throw "'$CurrentTest' had a step with a nonzero exit code" + throw "'$Script:CurrentTest' had a step with a nonzero exit code" } } function Throw-IfNotFailed { if ($LASTEXITCODE -eq 0) { - throw "'$CurrentTest' had a step with an unexpectedly zero exit code" + throw "'$Script:CurrentTest' had a step with an unexpectedly zero exit code" } } function Run-Vcpkg { - param([string[]]$TestArgs) - $CurrentTest = "./vcpkg $($testArgs -join ' ')" - Write-Host $CurrentTest + Param( + [Parameter(ValueFromRemainingArguments)] + [string[]]$TestArgs + ) + $Script:CurrentTest = "./vcpkg $($testArgs -join ' ')" + Write-Host $Script:CurrentTest ./vcpkg @testArgs } diff --git a/scripts/azure-pipelines/end-to-end-tests.ps1 b/scripts/azure-pipelines/end-to-end-tests.ps1 index f6b5c2e6bf9bbc..029120d5460e1d 100644 --- a/scripts/azure-pipelines/end-to-end-tests.ps1 +++ b/scripts/azure-pipelines/end-to-end-tests.ps1 @@ -34,7 +34,7 @@ $ErrorActionPreference = "Stop" $AllTests = Get-ChildItem $PSScriptRoot/end-to-end-tests-dir/*.ps1 if ($Filter -ne $Null) { - $AllTests = $AllTests | ? { $_ -match $Filter } + $AllTests = $AllTests | ? { $_.Name -match $Filter } } $n = 1 $m = $AllTests.Count diff --git a/scripts/e2e_port_versions/baseline.json b/scripts/e2e_port_versions/baseline.json new file mode 100644 index 00000000000000..953e8752d5ae58 --- /dev/null +++ b/scripts/e2e_port_versions/baseline.json @@ -0,0 +1,3 @@ +{ + "vcpkg-internal-e2e-test-port": { "version-string": "1.0.0" } +} diff --git a/scripts/e2e_port_versions/v-/vcpkg-internal-e2e-test-port.json b/scripts/e2e_port_versions/v-/vcpkg-internal-e2e-test-port.json new file mode 100644 index 00000000000000..ce7698ebb8d1d0 --- /dev/null +++ b/scripts/e2e_port_versions/v-/vcpkg-internal-e2e-test-port.json @@ -0,0 +1,8 @@ +{ + "versions": [ + { + "version-string": "1.0.0", + "git-tree": "1dc3e42a3c0cafe2884d379af4399273238b986e" + } + ] +} diff --git a/scripts/e2e_ports/vcpkg-uses-test-cmake/portfile.cmake b/scripts/e2e_ports/overlays/vcpkg-uses-test-cmake/portfile.cmake similarity index 100% rename from scripts/e2e_ports/vcpkg-uses-test-cmake/portfile.cmake rename to scripts/e2e_ports/overlays/vcpkg-uses-test-cmake/portfile.cmake diff --git a/scripts/e2e_ports/vcpkg-uses-test-cmake/vcpkg.json b/scripts/e2e_ports/overlays/vcpkg-uses-test-cmake/vcpkg.json similarity index 100% rename from scripts/e2e_ports/vcpkg-uses-test-cmake/vcpkg.json rename to scripts/e2e_ports/overlays/vcpkg-uses-test-cmake/vcpkg.json diff --git a/scripts/e2e_ports/vcpkg-uses-vcpkg-common-functions/portfile.cmake b/scripts/e2e_ports/overlays/vcpkg-uses-vcpkg-common-functions/portfile.cmake similarity index 100% rename from scripts/e2e_ports/vcpkg-uses-vcpkg-common-functions/portfile.cmake rename to scripts/e2e_ports/overlays/vcpkg-uses-vcpkg-common-functions/portfile.cmake diff --git a/scripts/e2e_ports/vcpkg-uses-vcpkg-common-functions/vcpkg.json b/scripts/e2e_ports/overlays/vcpkg-uses-vcpkg-common-functions/vcpkg.json similarity index 100% rename from scripts/e2e_ports/vcpkg-uses-vcpkg-common-functions/vcpkg.json rename to scripts/e2e_ports/overlays/vcpkg-uses-vcpkg-common-functions/vcpkg.json diff --git a/toolsrc/include/vcpkg/vcpkgcmdarguments.h b/toolsrc/include/vcpkg/vcpkgcmdarguments.h index f18f4843cb82f0..2677e6811bcb8c 100644 --- a/toolsrc/include/vcpkg/vcpkgcmdarguments.h +++ b/toolsrc/include/vcpkg/vcpkgcmdarguments.h @@ -134,6 +134,8 @@ namespace vcpkg std::unique_ptr scripts_root_dir; constexpr static StringLiteral BUILTIN_PORTS_ROOT_DIR_ARG = "x-builtin-ports-root"; std::unique_ptr builtin_ports_root_dir; + constexpr static StringLiteral BUILTIN_PORT_VERSIONS_DIR_ARG = "x-builtin-port-versions-dir"; + std::unique_ptr builtin_port_versions_dir; constexpr static StringLiteral DEFAULT_VISUAL_STUDIO_PATH_ENV = "VCPKG_VISUAL_STUDIO_PATH"; std::unique_ptr default_visual_studio_path; diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h index d7ee48923028b3..fc934e66329621 100644 --- a/toolsrc/include/vcpkg/vcpkgpaths.h +++ b/toolsrc/include/vcpkg/vcpkgpaths.h @@ -92,6 +92,7 @@ namespace vcpkg fs::path scripts; fs::path prefab; fs::path builtin_ports; + fs::path builtin_port_versions; fs::path tools; fs::path buildsystems; diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index 9a301b2624c53a..43666a2d7a5583 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -19,6 +19,8 @@ namespace using Baseline = std::map>; + static fs::path port_versions_dir = fs::u8path("port_versions"); + // this class is an implementation detail of `BuiltinRegistryEntry`; // when `BuiltinRegistryEntry` is using a port versions file for a port, // it uses this as it's underlying type; @@ -192,11 +194,11 @@ namespace // { BuiltinRegistry::RegistryImplementation std::unique_ptr BuiltinRegistry::get_port_entry(const VcpkgPaths& paths, StringView port_name) const { - auto versions_path = paths.root / fs::u8path("port_versions") / relative_path_to_versions(port_name); - if (paths.get_filesystem().exists(versions_path)) + auto versions_path = paths.builtin_port_versions / relative_path_to_versions(port_name); + if (paths.get_feature_flags().registries && paths.get_filesystem().exists(versions_path)) { - auto maybe_version_entries = load_versions_file( - paths.get_filesystem(), VersionDbType::Git, paths.root / fs::u8path("port_versions"), port_name); + auto maybe_version_entries = + load_versions_file(paths.get_filesystem(), VersionDbType::Git, paths.builtin_port_versions, port_name); Checks::check_exit( VCPKG_LINE_INFO, maybe_version_entries.has_value(), "Error: %s", maybe_version_entries.error()); auto version_entries = std::move(maybe_version_entries).value_or_exit(VCPKG_LINE_INFO); @@ -244,7 +246,7 @@ namespace Baseline parse_builtin_baseline(const VcpkgPaths& paths, StringView baseline_identifier) { - auto path_to_baseline = paths.root / fs::u8path("port_versions") / fs::u8path("baseline.json"); + auto path_to_baseline = paths.builtin_port_versions / fs::u8path("baseline.json"); auto res_baseline = load_baseline_versions(paths, path_to_baseline, baseline_identifier); if (!res_baseline.has_value()) @@ -298,35 +300,35 @@ namespace } Optional BuiltinRegistry::get_baseline_version(const VcpkgPaths& paths, StringView port_name) const { - const auto& baseline = m_baseline.get( - [this, &paths]() -> Baseline { return parse_builtin_baseline(paths, m_baseline_identifier); }); - - auto it = baseline.find(port_name); - if (it != baseline.end()) - { - return it->second; - } - else + if (paths.get_feature_flags().registries) { - // fall back to using the ports directory version - auto maybe_scf = Paragraphs::try_load_port(paths.get_filesystem(), - paths.builtin_ports_directory() / fs::u8path(port_name)); - if (auto pscf = maybe_scf.get()) + const auto& baseline = m_baseline.get( + [this, &paths]() -> Baseline { return parse_builtin_baseline(paths, m_baseline_identifier); }); + + auto it = baseline.find(port_name); + if (it != baseline.end()) { - auto& scf = *pscf; - return scf->to_versiont(); + return it->second; } - Debug::print("Failed to load port `%s` from the ports tree: %s.", port_name, maybe_scf.error()->error); - return nullopt; } + + // fall back to using the ports directory version + auto maybe_scf = + Paragraphs::try_load_port(paths.get_filesystem(), paths.builtin_ports_directory() / fs::u8path(port_name)); + if (auto pscf = maybe_scf.get()) + { + auto& scf = *pscf; + return scf->to_versiont(); + } + Debug::print("Failed to load port `%s` from the ports tree: %s.", port_name, maybe_scf.error()->error); + return nullopt; } void BuiltinRegistry::get_all_port_names(std::vector& out, const VcpkgPaths& paths) const { - auto port_versions_path = paths.root / fs::u8path("port_versions"); - if (paths.get_filesystem().exists(port_versions_path)) + if (paths.get_feature_flags().registries && paths.get_filesystem().exists(paths.builtin_port_versions)) { - load_all_port_names_from_port_versions(out, paths, port_versions_path); + load_all_port_names_from_port_versions(out, paths, paths.builtin_port_versions); } for (auto port_directory : fs::directory_iterator(paths.builtin_ports_directory())) @@ -342,7 +344,7 @@ namespace // { FilesystemRegistry::RegistryImplementation Baseline parse_filesystem_baseline(const VcpkgPaths& paths, const fs::path& root, StringView baseline_identifier) { - auto path_to_baseline = root / fs::u8path("port_versions") / fs::u8path("baseline.json"); + auto path_to_baseline = root / port_versions_dir / fs::u8path("baseline.json"); auto res_baseline = load_baseline_versions(paths, path_to_baseline, baseline_identifier); if (auto opt_baseline = res_baseline.get()) { @@ -385,7 +387,7 @@ namespace StringView port_name) const { auto maybe_version_entries = load_versions_file( - paths.get_filesystem(), VersionDbType::Filesystem, m_path / fs::u8path("port_versions"), port_name, m_path); + paths.get_filesystem(), VersionDbType::Filesystem, m_path / port_versions_dir, port_name, m_path); Checks::check_exit( VCPKG_LINE_INFO, maybe_version_entries.has_value(), "Error: %s", maybe_version_entries.error()); auto version_entries = std::move(maybe_version_entries).value_or_exit(VCPKG_LINE_INFO); @@ -401,7 +403,7 @@ namespace void FilesystemRegistry::get_all_port_names(std::vector& out, const VcpkgPaths& paths) const { - load_all_port_names_from_port_versions(out, paths, m_path / fs::u8path("port_versions")); + load_all_port_names_from_port_versions(out, paths, m_path / port_versions_dir); } // } FilesystemRegistry::RegistryImplementation diff --git a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp index 5b25b32d8af5e2..0310a01ae3c6e2 100644 --- a/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp +++ b/toolsrc/src/vcpkg/vcpkgcmdarguments.cpp @@ -277,6 +277,7 @@ namespace vcpkg {PACKAGES_ROOT_DIR_ARG, &VcpkgCmdArguments::packages_root_dir}, {SCRIPTS_ROOT_DIR_ARG, &VcpkgCmdArguments::scripts_root_dir}, {BUILTIN_PORTS_ROOT_DIR_ARG, &VcpkgCmdArguments::builtin_ports_root_dir}, + {BUILTIN_PORT_VERSIONS_DIR_ARG, &VcpkgCmdArguments::builtin_port_versions_dir}, }; constexpr static std::pair VcpkgCmdArguments::*> diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index fc082197361fd1..832b587ee3d064 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -341,6 +341,8 @@ If you wish to silence this error and use classic mode, you can: scripts = process_input_directory(filesystem, root, args.scripts_root_dir.get(), "scripts", VCPKG_LINE_INFO); builtin_ports = process_output_directory(filesystem, root, args.builtin_ports_root_dir.get(), "ports", VCPKG_LINE_INFO); + builtin_port_versions = process_output_directory( + filesystem, root, args.builtin_port_versions_dir.get(), "port_versions", VCPKG_LINE_INFO); prefab = root / fs::u8path("prefab"); if (args.default_visual_studio_path) From 9e31ad8238ccc2470bb5107d78a429f79d09757f Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 17 Dec 2020 16:00:32 -0800 Subject: [PATCH 10/16] Robert CRs, e2e test fixing switch to using the same git archive trick which is used in the git registry pr --- .../end-to-end-tests-dir/registries.ps1 | 2 +- .../port_versions}/baseline.json | 0 .../v-/vcpkg-internal-e2e-test-port.json | 0 toolsrc/include/vcpkg/configuration.h | 4 +- toolsrc/include/vcpkg/registries.h | 7 +- toolsrc/include/vcpkg/sourceparagraph.h | 4 +- toolsrc/include/vcpkg/vcpkgpaths.h | 2 +- toolsrc/src/vcpkg-test/registries.cpp | 40 +++++++---- toolsrc/src/vcpkg/configuration.cpp | 70 +++++++------------ toolsrc/src/vcpkg/portfileprovider.cpp | 7 +- toolsrc/src/vcpkg/registries.cpp | 18 +++++ toolsrc/src/vcpkg/vcpkgpaths.cpp | 65 +++++++++-------- 12 files changed, 127 insertions(+), 92 deletions(-) rename scripts/{e2e_port_versions => e2e_ports/port_versions}/baseline.json (100%) rename scripts/{e2e_port_versions => e2e_ports/port_versions}/v-/vcpkg-internal-e2e-test-port.json (100%) diff --git a/scripts/azure-pipelines/end-to-end-tests-dir/registries.ps1 b/scripts/azure-pipelines/end-to-end-tests-dir/registries.ps1 index 403e6b95143859..b985a61f56d841 100644 --- a/scripts/azure-pipelines/end-to-end-tests-dir/registries.ps1 +++ b/scripts/azure-pipelines/end-to-end-tests-dir/registries.ps1 @@ -1,7 +1,7 @@ . "$PSScriptRoot/../end-to-end-tests-prelude.ps1" -$commonArgs += @("--x-builtin-port-versions-dir=$PSScriptRoot/../../e2e_port_versions") +$commonArgs += @("--x-builtin-port-versions-dir=$PSScriptRoot/../../e2e_ports/port_versions") Run-Vcpkg install @commonArgs 'vcpkg-internal-e2e-test-port' Throw-IfNotFailed diff --git a/scripts/e2e_port_versions/baseline.json b/scripts/e2e_ports/port_versions/baseline.json similarity index 100% rename from scripts/e2e_port_versions/baseline.json rename to scripts/e2e_ports/port_versions/baseline.json diff --git a/scripts/e2e_port_versions/v-/vcpkg-internal-e2e-test-port.json b/scripts/e2e_ports/port_versions/v-/vcpkg-internal-e2e-test-port.json similarity index 100% rename from scripts/e2e_port_versions/v-/vcpkg-internal-e2e-test-port.json rename to scripts/e2e_ports/port_versions/v-/vcpkg-internal-e2e-test-port.json diff --git a/toolsrc/include/vcpkg/configuration.h b/toolsrc/include/vcpkg/configuration.h index 94fa519d990a49..6d6a9b1f447a9e 100644 --- a/toolsrc/include/vcpkg/configuration.h +++ b/toolsrc/include/vcpkg/configuration.h @@ -16,8 +16,10 @@ namespace vcpkg // `registries` and `default_registry`. The fall back logic is // taken care of in RegistrySet. RegistrySet registry_set; + + void validate_feature_flags(const FeatureFlagSettings& flags); }; std::unique_ptr> make_configuration_deserializer( - const VcpkgCmdArguments& args, const fs::path& config_directory); + const fs::path& config_directory); } diff --git a/toolsrc/include/vcpkg/registries.h b/toolsrc/include/vcpkg/registries.h index d20dcdbbdc650f..006bc789d17c97 100644 --- a/toolsrc/include/vcpkg/registries.h +++ b/toolsrc/include/vcpkg/registries.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -21,7 +22,6 @@ namespace vcpkg { virtual View get_port_versions() const = 0; - // precondition: version \in get_port_versions(). Otherwise, this function asserts. virtual ExpectedS get_path_to_version(const VcpkgPaths& paths, const VersionT& version) const = 0; virtual ~RegistryEntry() = default; @@ -88,6 +88,11 @@ namespace vcpkg // this exists in order to allow versioning and registries to be developed and tested separately void experimental_set_builtin_registry_baseline(StringView baseline) const; + // returns whether the registry set has any modifications to the default + // (i.e., whether `default_registry` was set, or `registries` had any entries) + // for checking against the registry feature flag. + bool has_modifications() const; + private: std::unique_ptr default_registry_; std::vector registries_; diff --git a/toolsrc/include/vcpkg/sourceparagraph.h b/toolsrc/include/vcpkg/sourceparagraph.h index b181c642a0498e..50417b8adc4061 100644 --- a/toolsrc/include/vcpkg/sourceparagraph.h +++ b/toolsrc/include/vcpkg/sourceparagraph.h @@ -116,8 +116,8 @@ namespace vcpkg Json::Object serialize_debug_manifest(const SourceControlFile& scf); /// - /// Full metadata of a package: core and other features. As well as the location the SourceControlFile was - /// loaded from (the port directory, not the actual CONTROL/vcpkg.json file). + /// Full metadata of a package: core and other features, + /// as well as the port directory the SourceControlFile was loaded from /// struct SourceControlFileLocation { diff --git a/toolsrc/include/vcpkg/vcpkgpaths.h b/toolsrc/include/vcpkg/vcpkgpaths.h index fc934e66329621..1f562c151773f1 100644 --- a/toolsrc/include/vcpkg/vcpkgpaths.h +++ b/toolsrc/include/vcpkg/vcpkgpaths.h @@ -117,7 +117,7 @@ namespace vcpkg const fs::path& get_tool_exe(const std::string& tool) const; const std::string& get_tool_version(const std::string& tool) const; - // Git manipulation in vcpkg directory + // Git manipulation in the vcpkg directory fs::path git_checkout_baseline(Files::Filesystem& filesystem, StringView commit_sha) const; fs::path git_checkout_port(Files::Filesystem& filesystem, StringView port_name, StringView git_tree) const; ExpectedS git_show(const std::string& treeish, const fs::path& dot_git_dir) const; diff --git a/toolsrc/src/vcpkg-test/registries.cpp b/toolsrc/src/vcpkg-test/registries.cpp index 5dfd13dec63e85..ba2f1dd76f2d6a 100644 --- a/toolsrc/src/vcpkg-test/registries.cpp +++ b/toolsrc/src/vcpkg-test/registries.cpp @@ -6,7 +6,6 @@ using namespace vcpkg; namespace { - template struct TestRegistryImplementation final : RegistryImplementation { std::unique_ptr get_port_entry(const VcpkgPaths&, StringView) const override { return nullptr; } @@ -14,41 +13,58 @@ namespace void get_all_port_names(std::vector&, const VcpkgPaths&) const override { } Optional get_baseline_version(const VcpkgPaths&, StringView) const override { return nullopt; } + + int number; + + TestRegistryImplementation(int n) : number(n) {} }; - template - Registry make_registry(std::vector&& port_names) + Registry make_registry(int n, std::vector&& port_names) + { + return {std::move(port_names), std::make_unique(n)}; + } + + int get_tri_num(const RegistryImplementation& r) { - return {std::move(port_names), std::make_unique>()}; + if (auto tri = dynamic_cast(&r)) + { + return tri->number; + } + else + { + return -1; + } + } + } TEST_CASE ("registry_set_selects_registry", "[registries]") { RegistrySet set; - set.set_default_registry(std::make_unique>()); + set.set_default_registry(std::make_unique(0)); - set.add_registry(make_registry<1>({"p1", "q1", "r1"})); - set.add_registry(make_registry<2>({"p2", "q2", "r2"})); + set.add_registry(make_registry(1, {"p1", "q1", "r1"})); + set.add_registry(make_registry(2, {"p2", "q2", "r2"})); auto reg = set.registry_for_port("p1"); REQUIRE(reg); - CHECK(typeid(*reg) == typeid(TestRegistryImplementation<1>)); + CHECK(get_tri_num(*reg) == 1); reg = set.registry_for_port("r2"); REQUIRE(reg); - CHECK(typeid(*reg) == typeid(TestRegistryImplementation<2>)); + CHECK(get_tri_num(*reg) == 2); reg = set.registry_for_port("a"); REQUIRE(reg); - CHECK(typeid(*reg) == typeid(TestRegistryImplementation<0>)); + CHECK(get_tri_num(*reg) == 0); set.set_default_registry(nullptr); reg = set.registry_for_port("q1"); REQUIRE(reg); - CHECK(typeid(*reg) == typeid(TestRegistryImplementation<1>)); + CHECK(get_tri_num(*reg) == 1); reg = set.registry_for_port("p2"); REQUIRE(reg); - CHECK(typeid(*reg) == typeid(TestRegistryImplementation<2>)); + CHECK(get_tri_num(*reg) == 2); reg = set.registry_for_port("a"); CHECK_FALSE(reg); } diff --git a/toolsrc/src/vcpkg/configuration.cpp b/toolsrc/src/vcpkg/configuration.cpp index 737563deda1ef0..d51128e3d0c76e 100644 --- a/toolsrc/src/vcpkg/configuration.cpp +++ b/toolsrc/src/vcpkg/configuration.cpp @@ -22,13 +22,9 @@ namespace virtual Optional visit_object(Json::Reader& r, const Json::Object& obj) override; - ConfigurationDeserializer(const VcpkgCmdArguments& args, const fs::path& configuration_directory); + ConfigurationDeserializer(const fs::path& configuration_directory); private: - bool print_json; - - bool registries_enabled; - fs::path configuration_directory; }; @@ -39,68 +35,54 @@ namespace { RegistrySet registries; - bool registries_feature_flags_warning = false; - auto impl_des = get_registry_implementation_deserializer(configuration_directory); + std::unique_ptr default_registry; + if (r.optional_object_field(obj, DEFAULT_REGISTRY, default_registry, *impl_des)) { - std::unique_ptr default_registry; - if (r.optional_object_field(obj, DEFAULT_REGISTRY, default_registry, *impl_des)) - { - if (!registries_enabled) - { - registries_feature_flags_warning = true; - } - else - { - registries.set_default_registry(std::move(default_registry)); - } - } + registries.set_default_registry(std::move(default_registry)); } auto reg_des = get_registry_array_deserializer(configuration_directory); std::vector regs; r.optional_object_field(obj, REGISTRIES, regs, *reg_des); - if (!regs.empty() && !registries_enabled) - { - registries_feature_flags_warning = true; - regs.clear(); - } - - if (!r.errors().empty()) - { - return nullopt; - } - 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, - const fs::path& configuration_directory) + ConfigurationDeserializer::ConfigurationDeserializer(const fs::path& configuration_directory) : configuration_directory(configuration_directory) { - registries_enabled = args.registries_enabled(); - print_json = args.output_json(); } } std::unique_ptr> vcpkg::make_configuration_deserializer( - const VcpkgCmdArguments& args, const fs::path& config_directory) + const fs::path& config_directory) +{ + return std::make_unique(config_directory); +} + +namespace vcpkg { - return std::make_unique(args, config_directory); + void Configuration::validate_feature_flags(const FeatureFlagSettings& flags) + { + if (!flags.registries) + { + if (registry_set.has_modifications()) + { + 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); + registry_set = RegistrySet(); + } + } + } } diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index eb61662d2de36f..5ab8f8fdb55cfa 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -26,8 +26,11 @@ namespace View get_port_versions() const override { return {&version, 1}; } ExpectedS get_path_to_version(const VcpkgPaths&, const VersionT& v) const override { - Checks::check_exit(VCPKG_LINE_INFO, v == version); - return path; + if (v == version) + { + return path; + } + return Strings::format("Version %s not found; only %s is available.", v.to_string(), version.to_string()); } fs::path path; diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index 43666a2d7a5583..b60afc38caea11 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -936,4 +936,22 @@ namespace vcpkg } } } + + bool RegistrySet::has_modifications() const + { + if (!registries_.empty()) + { + return true; + } + if (auto builtin_reg = dynamic_cast(default_registry_.get())) + { + if (builtin_reg->m_baseline_identifier.empty()) + { + return false; + } + return true; + } + // default_registry_ is not a BuiltinRegistry + return true; + } } diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 832b587ee3d064..5e7be25f7aee5c 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -88,7 +88,7 @@ namespace vcpkg const fs::path& filepath) { Json::Reader reader; - auto deserializer = make_configuration_deserializer(args, filepath.parent_path()); + auto deserializer = make_configuration_deserializer(filepath.parent_path()); auto parsed_config_opt = reader.visit(obj, *deserializer); if (!reader.errors().empty()) @@ -102,6 +102,8 @@ namespace vcpkg Checks::exit_fail(VCPKG_LINE_INFO); } + parsed_config_opt.get()->validate_feature_flags(args.feature_flag_settings()); + return std::move(parsed_config_opt).value_or_exit(VCPKG_LINE_INFO); } @@ -570,6 +572,7 @@ If you wish to silence this error and use classic mode, you can: Files::Filesystem& fs = paths.get_filesystem(); fs.remove_all(work_tree, VCPKG_LINE_INFO); fs.remove_all(destination, VCPKG_LINE_INFO); + fs::path destination_tar = fs::u8path(Strings::format("%s.tmp.tar", fs::u8string(destination))); if (!fs.exists(dot_git_dir)) { @@ -598,35 +601,41 @@ If you wish to silence this error and use classic mode, you can: fetch_output.output); } - if (!fs.exists(work_tree)) - { - fs.create_directories(work_tree, VCPKG_LINE_INFO); - } - - // git checkout {tree_object} . - System::CmdLineBuilder checkout_cmd_builder = git_cmd_builder(paths, dot_git_dir, work_tree) - .string_arg("checkout") - .string_arg(git_object) - .string_arg("."); - const auto checkout_output = System::cmd_execute_and_capture_output(checkout_cmd_builder.extract()); - Checks::check_exit(VCPKG_LINE_INFO, checkout_output.exit_code == 0, "Failed to checkout %s", git_object); - - const auto& containing_folder = destination.parent_path(); - if (!fs.exists(containing_folder)) - { - fs.create_directories(containing_folder, VCPKG_LINE_INFO); - } + fs.create_directories(destination_tar.parent_path(), VCPKG_LINE_INFO); + System::CmdLineBuilder git_archive = git_cmd_builder(paths, dot_git_dir, work_tree) + .string_arg("archive") + .string_arg("--format") + .string_arg("tar") + .string_arg(git_object) + .string_arg("--output") + .path_arg(destination_tar); + auto git_archive_output = System::cmd_execute_and_capture_output(git_archive.extract()); + if (git_archive_output.exit_code != 0) + { + Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to run git archive: %s", git_archive_output.output); + } + + fs.create_directories(destination, VCPKG_LINE_INFO); + System::CmdLineBuilder untar{}; + untar.string_arg("cd").path_arg(destination); + untar.ampersand(); + untar.path_arg(paths.get_tool_exe(Tools::CMAKE)) + .string_arg("-E") + .string_arg("tar") + .string_arg("xf") + .path_arg(destination_tar); + + auto untar_cmdline = untar.extract(); +#ifdef WIN32 + // Invoke through `cmd` to support `&&` + untar_cmdline.insert(0, "cmd /c \""); + untar_cmdline.push_back('"'); +#endif - std::error_code ec; - fs.rename_or_copy(work_tree, destination, ".tmp", ec); - fs.remove_all(work_tree, VCPKG_LINE_INFO); - if (ec) + auto untar_output = System::cmd_execute_and_capture_output(untar_cmdline); + if (untar_output.exit_code != 0) { - System::printf(System::Color::error, - "Error: Couldn't move checked out files from %s to destination %s", - fs::u8string(work_tree), - fs::u8string(destination)); - Checks::exit_fail(VCPKG_LINE_INFO); + Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to run cmake -E tar xf: %s", untar_output.output); } } From 31ea1d59667d960c9475b9e9bcd5694b6b48392f Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Thu, 17 Dec 2020 17:48:36 -0800 Subject: [PATCH 11/16] format --- toolsrc/src/vcpkg-test/registries.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/toolsrc/src/vcpkg-test/registries.cpp b/toolsrc/src/vcpkg-test/registries.cpp index ba2f1dd76f2d6a..fe7885a1c4775f 100644 --- a/toolsrc/src/vcpkg-test/registries.cpp +++ b/toolsrc/src/vcpkg-test/registries.cpp @@ -16,7 +16,7 @@ namespace int number; - TestRegistryImplementation(int n) : number(n) {} + TestRegistryImplementation(int n) : number(n) { } }; Registry make_registry(int n, std::vector&& port_names) @@ -34,7 +34,6 @@ namespace { return -1; } - } } From 1b8f839889b1a4fa0106fbe0bffe5da71303d0ae Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 18 Dec 2020 12:20:06 -0800 Subject: [PATCH 12/16] add --no-hardlinks --- toolsrc/src/vcpkg/vcpkgpaths.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index 5e7be25f7aee5c..f5adff1cf7d22d 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -496,11 +496,13 @@ If you wish to silence this error and use classic mode, you can: fs.remove_all(dot_git_dir, VCPKG_LINE_INFO); // All git commands are run with: --git-dir={dot_git_dir} --work-tree={work_tree_temp} - // git clone --no-checkout --local {vcpkg_root} {dot_git_dir} + // git clone --no-checkout --local --no-hardlinks {vcpkg_root} {dot_git_dir} + // note that `--no-hardlinks` is added because otherwise, git fails to clone in some cases System::CmdLineBuilder clone_cmd_builder = git_cmd_builder(paths, dot_git_dir, work_tree) .string_arg("clone") .string_arg("--no-checkout") .string_arg("--local") + .string_arg("--no-hardlinks") .path_arg(local_repo) .path_arg(dot_git_dir); const auto clone_output = System::cmd_execute_and_capture_output(clone_cmd_builder.extract()); @@ -577,11 +579,13 @@ If you wish to silence this error and use classic mode, you can: if (!fs.exists(dot_git_dir)) { // All git commands are run with: --git-dir={dot_git_dir} --work-tree={work_tree_temp} - // git clone --no-checkout --local {vcpkg_root} {dot_git_dir} + // git clone --no-checkout --local --no-hardlinks {vcpkg_root} {dot_git_dir} + // note that `--no-hardlinks` is added because otherwise, git fails to clone in some cases System::CmdLineBuilder clone_cmd_builder = git_cmd_builder(paths, dot_git_dir, work_tree) .string_arg("clone") .string_arg("--no-checkout") .string_arg("--local") + .string_arg("--no-hardlinks") .path_arg(local_repo) .path_arg(dot_git_dir); const auto clone_output = System::cmd_execute_and_capture_output(clone_cmd_builder.extract()); From 360217b3359b8b9fbf3a1dfae1de595cf4df4663 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 18 Dec 2020 12:33:58 -0800 Subject: [PATCH 13/16] Switch back to old way of doing check out --- toolsrc/src/vcpkg/paragraphs.cpp | 17 +++++-- toolsrc/src/vcpkg/portfileprovider.cpp | 8 +-- toolsrc/src/vcpkg/registries.cpp | 2 +- toolsrc/src/vcpkg/vcpkgpaths.cpp | 68 ++++++++++++-------------- 4 files changed, 49 insertions(+), 46 deletions(-) diff --git a/toolsrc/src/vcpkg/paragraphs.cpp b/toolsrc/src/vcpkg/paragraphs.cpp index 44304b2618e6a0..32103c76b9e6f6 100644 --- a/toolsrc/src/vcpkg/paragraphs.cpp +++ b/toolsrc/src/vcpkg/paragraphs.cpp @@ -357,14 +357,23 @@ namespace vcpkg::Paragraphs return res; } - ExpectedS> pghs = get_paragraphs(fs, path_to_control); - if (auto vector_pghs = pghs.get()) + + if (fs.exists(path_to_control)) { - return SourceControlFile::parse_control_file(fs::u8string(path_to_control), std::move(*vector_pghs)); + ExpectedS> pghs = get_paragraphs(fs, path_to_control); + if (auto vector_pghs = pghs.get()) + { + return SourceControlFile::parse_control_file(fs::u8string(path_to_control), std::move(*vector_pghs)); + } + auto error_info = std::make_unique(); + error_info->name = fs::u8string(path.filename()); + error_info->error = pghs.error(); + return error_info; } + auto error_info = std::make_unique(); error_info->name = fs::u8string(path.filename()); - error_info->error = pghs.error(); + error_info->error = "Failed to find either a CONTROL file or vcpkg.json file."; return error_info; } diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index 5ab8f8fdb55cfa..d49da1c803321a 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -167,8 +167,7 @@ namespace vcpkg::PortFileProvider } else { - Debug::print( - "Failed to find port `", spec, "` in registry:", entry ? " entry found." : " no entry found"); + Debug::print("Failed to find port `", spec, "` in registry: no entry found.\n"); } } else @@ -223,7 +222,10 @@ namespace vcpkg::PortFileProvider } else { - return maybe_scfl.error()->error; + return Strings::format("Error: when loading port `%s` from directory `%s`:\n%s\n", + spec, + fs::u8string(port_path), + maybe_scfl.error()->error); } } } diff --git a/toolsrc/src/vcpkg/registries.cpp b/toolsrc/src/vcpkg/registries.cpp index b60afc38caea11..22ac26fd9dbb63 100644 --- a/toolsrc/src/vcpkg/registries.cpp +++ b/toolsrc/src/vcpkg/registries.cpp @@ -320,7 +320,7 @@ namespace auto& scf = *pscf; return scf->to_versiont(); } - Debug::print("Failed to load port `%s` from the ports tree: %s.", port_name, maybe_scf.error()->error); + Debug::print("Failed to load port `", port_name, "` from the ports tree: ", maybe_scf.error()->error, "\n"); return nullopt; } diff --git a/toolsrc/src/vcpkg/vcpkgpaths.cpp b/toolsrc/src/vcpkg/vcpkgpaths.cpp index f5adff1cf7d22d..a4125876171772 100644 --- a/toolsrc/src/vcpkg/vcpkgpaths.cpp +++ b/toolsrc/src/vcpkg/vcpkgpaths.cpp @@ -574,13 +574,11 @@ If you wish to silence this error and use classic mode, you can: Files::Filesystem& fs = paths.get_filesystem(); fs.remove_all(work_tree, VCPKG_LINE_INFO); fs.remove_all(destination, VCPKG_LINE_INFO); - fs::path destination_tar = fs::u8path(Strings::format("%s.tmp.tar", fs::u8string(destination))); if (!fs.exists(dot_git_dir)) { // All git commands are run with: --git-dir={dot_git_dir} --work-tree={work_tree_temp} - // git clone --no-checkout --local --no-hardlinks {vcpkg_root} {dot_git_dir} - // note that `--no-hardlinks` is added because otherwise, git fails to clone in some cases + // git clone --no-checkout --local {vcpkg_root} {dot_git_dir} System::CmdLineBuilder clone_cmd_builder = git_cmd_builder(paths, dot_git_dir, work_tree) .string_arg("clone") .string_arg("--no-checkout") @@ -605,41 +603,35 @@ If you wish to silence this error and use classic mode, you can: fetch_output.output); } - fs.create_directories(destination_tar.parent_path(), VCPKG_LINE_INFO); - System::CmdLineBuilder git_archive = git_cmd_builder(paths, dot_git_dir, work_tree) - .string_arg("archive") - .string_arg("--format") - .string_arg("tar") - .string_arg(git_object) - .string_arg("--output") - .path_arg(destination_tar); - auto git_archive_output = System::cmd_execute_and_capture_output(git_archive.extract()); - if (git_archive_output.exit_code != 0) - { - Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to run git archive: %s", git_archive_output.output); - } - - fs.create_directories(destination, VCPKG_LINE_INFO); - System::CmdLineBuilder untar{}; - untar.string_arg("cd").path_arg(destination); - untar.ampersand(); - untar.path_arg(paths.get_tool_exe(Tools::CMAKE)) - .string_arg("-E") - .string_arg("tar") - .string_arg("xf") - .path_arg(destination_tar); - - auto untar_cmdline = untar.extract(); -#ifdef WIN32 - // Invoke through `cmd` to support `&&` - untar_cmdline.insert(0, "cmd /c \""); - untar_cmdline.push_back('"'); -#endif + if (!fs.exists(work_tree)) + { + fs.create_directories(work_tree, VCPKG_LINE_INFO); + } + + // git checkout {tree_object} . + System::CmdLineBuilder checkout_cmd_builder = git_cmd_builder(paths, dot_git_dir, work_tree) + .string_arg("checkout") + .string_arg(git_object) + .string_arg("."); + const auto checkout_output = System::cmd_execute_and_capture_output(checkout_cmd_builder.extract()); + Checks::check_exit(VCPKG_LINE_INFO, checkout_output.exit_code == 0, "Failed to checkout %s", git_object); + + const auto& containing_folder = destination.parent_path(); + if (!fs.exists(containing_folder)) + { + fs.create_directories(containing_folder, VCPKG_LINE_INFO); + } - auto untar_output = System::cmd_execute_and_capture_output(untar_cmdline); - if (untar_output.exit_code != 0) + std::error_code ec; + fs.rename_or_copy(work_tree, destination, ".tmp", ec); + fs.remove_all(work_tree, VCPKG_LINE_INFO); + if (ec) { - Checks::exit_with_message(VCPKG_LINE_INFO, "Failed to run cmake -E tar xf: %s", untar_output.output); + System::printf(System::Color::error, + "Error: Couldn't move checked out files from %s to destination %s", + fs::u8string(work_tree), + fs::u8string(destination)); + Checks::exit_fail(VCPKG_LINE_INFO); } } @@ -676,8 +668,8 @@ If you wish to silence this error and use classic mode, you can: * Since we are checking a git tree object, all files will be checked out to the root of `work-tree`. * Because of that, it makes sense to use the git hash as the name for the directory. */ - const fs::path local_repo = this->root; - const fs::path destination = this->versions_output / fs::u8path(git_tree) / fs::u8path(port_name); + const fs::path& local_repo = this->root; + fs::path destination = this->versions_output / fs::u8path(git_tree) / fs::u8path(port_name); if (!fs.exists(destination / "CONTROL") && !fs.exists(destination / "vcpkg.json")) { From 1ca69d6da419bbd9e7d852194b25607fd45751f3 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 18 Dec 2020 15:13:42 -0800 Subject: [PATCH 14/16] billy crs --- toolsrc/src/vcpkg/configuration.cpp | 17 +++++++---------- toolsrc/src/vcpkg/portfileprovider.cpp | 9 +++------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/toolsrc/src/vcpkg/configuration.cpp b/toolsrc/src/vcpkg/configuration.cpp index d51128e3d0c76e..bb03de62767840 100644 --- a/toolsrc/src/vcpkg/configuration.cpp +++ b/toolsrc/src/vcpkg/configuration.cpp @@ -72,17 +72,14 @@ namespace vcpkg { void Configuration::validate_feature_flags(const FeatureFlagSettings& flags) { - if (!flags.registries) + if (!flags.registries && registry_set.has_modifications()) { - if (registry_set.has_modifications()) - { - 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); - registry_set = RegistrySet(); - } + 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); + registry_set = RegistrySet(); } } } diff --git a/toolsrc/src/vcpkg/portfileprovider.cpp b/toolsrc/src/vcpkg/portfileprovider.cpp index d49da1c803321a..c956dfe9b06506 100644 --- a/toolsrc/src/vcpkg/portfileprovider.cpp +++ b/toolsrc/src/vcpkg/portfileprovider.cpp @@ -337,16 +337,13 @@ namespace vcpkg::PortFileProvider } auto entry = try_load_registry_port_and_baseline(paths, port_name.to_string()); - if (entry.first) - { - auto it = m_entry_cache.emplace(port_name.to_string(), std::move(entry.first)); - return it.first->second->get_port_versions(); - } - else + if (!entry.first) { Checks::exit_with_message( VCPKG_LINE_INFO, "Error: Could not find a definition for port %s", port_name); } + auto it = m_entry_cache.emplace(port_name.to_string(), std::move(entry.first)); + return it.first->second->get_port_versions(); } ExpectedS get_control_file(const VersionSpec& version_spec) const override From 64556b308c3df434005388fb43cdd7423feb64a7 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Fri, 18 Dec 2020 15:52:14 -0800 Subject: [PATCH 15/16] format --- toolsrc/src/vcpkg/configuration.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/toolsrc/src/vcpkg/configuration.cpp b/toolsrc/src/vcpkg/configuration.cpp index bb03de62767840..3fa02876ffde8b 100644 --- a/toolsrc/src/vcpkg/configuration.cpp +++ b/toolsrc/src/vcpkg/configuration.cpp @@ -74,11 +74,10 @@ namespace vcpkg { if (!flags.registries && registry_set.has_modifications()) { - 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); registry_set = RegistrySet(); } } From 260d25eeff06c5b1f4de349ff8110938b786314e Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 21 Dec 2020 12:02:04 -0800 Subject: [PATCH 16/16] add registry parsing unit tests --- toolsrc/src/vcpkg-test/registries.cpp | 63 +++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/toolsrc/src/vcpkg-test/registries.cpp b/toolsrc/src/vcpkg-test/registries.cpp index fe7885a1c4775f..1c839409d9353a 100644 --- a/toolsrc/src/vcpkg-test/registries.cpp +++ b/toolsrc/src/vcpkg-test/registries.cpp @@ -1,5 +1,7 @@ #include +#include + #include using namespace vcpkg; @@ -36,6 +38,8 @@ namespace } } + // test functions which parse string literals, so no concerns about failure + Json::Value parse_json(StringView sv) { return Json::parse(sv).value_or_exit(VCPKG_LINE_INFO).first; } } TEST_CASE ("registry_set_selects_registry", "[registries]") @@ -67,3 +71,62 @@ TEST_CASE ("registry_set_selects_registry", "[registries]") reg = set.registry_for_port("a"); CHECK_FALSE(reg); } + +TEST_CASE ("registry_parsing", "[registries]") +{ + Json::Reader r; + auto registry_impl_des = get_registry_implementation_deserializer({}); + + auto test_json = parse_json(R"json( +{ + "kind": "builtin" +} + )json"); + auto registry_impl = r.visit(test_json, *registry_impl_des); + REQUIRE(registry_impl); + CHECK(*registry_impl.get()); + CHECK(r.errors().empty()); + + test_json = parse_json(R"json( +{ + "kind": "builtin", + "baseline": "hi" +} + )json"); + registry_impl = r.visit(test_json, *registry_impl_des); + REQUIRE(registry_impl); + CHECK(*registry_impl.get()); + CHECK(r.errors().empty()); + + test_json = parse_json(R"json( +{ + "kind": "builtin", + "path": "a/b" +} + )json"); + registry_impl = r.visit(test_json, *registry_impl_des); + CHECK_FALSE(r.errors().empty()); + r.errors().clear(); + + test_json = parse_json(R"json( +{ + "kind": "filesystem", + "path": "a/b/c" +} + )json"); + registry_impl = r.visit(test_json, *registry_impl_des); + REQUIRE(registry_impl); + CHECK(*registry_impl.get()); + CHECK(r.errors().empty()); + + test_json = parse_json(R"json( +{ + "kind": "filesystem", + "path": "/a/b/c" +} + )json"); + registry_impl = r.visit(test_json, *registry_impl_des); + REQUIRE(registry_impl); + CHECK(*registry_impl.get()); + CHECK(r.errors().empty()); +}