diff --git a/include/vcpkg/base/files.h b/include/vcpkg/base/files.h index c6f38ee1b4..2e6bc164cc 100644 --- a/include/vcpkg/base/files.h +++ b/include/vcpkg/base/files.h @@ -140,25 +140,32 @@ namespace vcpkg virtual std::vector get_files_recursive(const Path& dir, std::error_code& ec) const = 0; std::vector get_files_recursive(const Path& dir, LineInfo li) const; + ExpectedL> try_get_files_recursive(const Path& dir) const; virtual std::vector get_files_non_recursive(const Path& dir, std::error_code& ec) const = 0; std::vector get_files_non_recursive(const Path& dir, LineInfo li) const; + ExpectedL> try_get_files_non_recursive(const Path& dir) const; virtual std::vector get_directories_recursive(const Path& dir, std::error_code& ec) const = 0; std::vector get_directories_recursive(const Path& dir, LineInfo li) const; + ExpectedL> try_get_directories_recursive(const Path& dir) const; virtual std::vector get_directories_non_recursive(const Path& dir, std::error_code& ec) const = 0; std::vector get_directories_non_recursive(const Path& dir, LineInfo li) const; + ExpectedL> try_get_directories_non_recursive(const Path& dir) const; virtual std::vector get_regular_files_recursive(const Path& dir, std::error_code& ec) const = 0; std::vector get_regular_files_recursive(const Path& dir, LineInfo li) const; + ExpectedL> try_get_regular_files_recursive(const Path& dir) const; virtual std::vector get_regular_files_recursive_lexically_proximate(const Path& dir, std::error_code& ec) const = 0; std::vector get_regular_files_recursive_lexically_proximate(const Path& dir, LineInfo li) const; + ExpectedL> try_get_regular_files_recursive_lexically_proximate(const Path& dir) const; virtual std::vector get_regular_files_non_recursive(const Path& dir, std::error_code& ec) const = 0; std::vector get_regular_files_non_recursive(const Path& dir, LineInfo li) const; + ExpectedL> try_get_regular_files_non_recursive(const Path& dir) const; bool exists(const Path& target, std::error_code& ec) const; bool exists(const Path& target, LineInfo li) const; diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index eb39b2ac83..168d21f128 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -915,14 +915,10 @@ DECLARE_MESSAGE(CouldNotFindBaseline, (msg::commit_sha, msg::path), "", "Could not find explicitly specified baseline `\"{commit_sha}\"` in baseline file {path}") -DECLARE_MESSAGE(CouldNotFindBaselineForRepo, - (msg::commit_sha, msg::package_name), - "", - "Couldn't find baseline `\"{commit_sha}\"` for repo {package_name}") DECLARE_MESSAGE(CouldNotFindBaselineInCommit, - (msg::commit_sha, msg::package_name), + (msg::url, msg::commit_sha, msg::package_name), "", - "Couldn't find baseline in commit `\"{commit_sha}\"` from repo {package_name}:") + "Couldn't find baseline in {url} at {commit_sha} for {package_name}.") DECLARE_MESSAGE(CouldNotFindGitTreeAtCommit, (msg::package_name, msg::commit_sha), "", @@ -1226,10 +1222,7 @@ DECLARE_MESSAGE(FailedToDetermineArchitecture, DECLARE_MESSAGE(FailedToDetermineCurrentCommit, (), "", "Failed to determine the current commit:") DECLARE_MESSAGE(FailedToDownloadFromMirrorSet, (), "", "Failed to download from mirror set") DECLARE_MESSAGE(FailedToExtract, (msg::path), "", "Failed to extract \"{path}\":") -DECLARE_MESSAGE(FailedToFetchError, - (msg::error_msg, msg::package_name), - "", - "{error_msg}\nFailed to fetch {package_name}:") +DECLARE_MESSAGE(FailedToFetchRepo, (msg::url), "", "Failed to fetch {url}.") DECLARE_MESSAGE(FailedToFindBaseline, (), "", "Failed to find baseline.json") DECLARE_MESSAGE(FailedToFindPortFeature, (msg::feature, msg::package_name), @@ -1385,12 +1378,12 @@ DECLARE_MESSAGE(GitFailedToFetch, "{value} is a git ref like 'origin/main'", "failed to fetch ref {value} from repository {url}") DECLARE_MESSAGE(GitFailedToInitializeLocalRepository, (msg::path), "", "failed to initialize local repository {path}") -DECLARE_MESSAGE(GitRegistryMustHaveBaseline, - (msg::package_name, msg::value), - "{value} is a commit sha", - "The git registry entry for \"{package_name}\" must have a \"baseline\" field that is a valid git " - "commit SHA (40 hexadecimal characters).\n" - "The current HEAD of that repo is \"{value}\".") +DECLARE_MESSAGE( + GitRegistryMustHaveBaseline, + (msg::url, msg::commit_sha), + "", + "The git registry \"{url}\" must have a \"baseline\" field that is a valid git commit SHA (40 hexadecimal " + "characters).\nTo use the current latest versions, set baseline to that repo's HEAD, \"{commit_sha}\".") DECLARE_MESSAGE(GitStatusOutputExpectedFileName, (), "", "expected a file name") DECLARE_MESSAGE(GitStatusOutputExpectedNewLine, (), "", "expected new line") DECLARE_MESSAGE(GitStatusOutputExpectedRenameOrNewline, (), "", "expected renamed file or new lines") diff --git a/include/vcpkg/paragraphparser.h b/include/vcpkg/paragraphparser.h index cbb3b55c4b..0ba8eb7b55 100644 --- a/include/vcpkg/paragraphparser.h +++ b/include/vcpkg/paragraphparser.h @@ -35,6 +35,8 @@ namespace vcpkg static std::string format_errors(View> errors); void to_string(std::string& target) const; std::string to_string() const; + + static std::unique_ptr from_error(StringView port_name, LocalizedString&& ls); }; } // namespace vcpkg @@ -46,6 +48,17 @@ namespace vcpkg template using ParseExpected = vcpkg::ExpectedT, std::unique_ptr>; + template + ExpectedL

map_parse_expected_to_localized_string(ParseExpected

&& parse_expected) + { + if (auto value = parse_expected.get()) + { + return std::move(**value); + } + + return LocalizedString::from_raw(parse_expected.error()->to_string()); + } + using Paragraph = std::map, std::less<>>; struct ParagraphParser diff --git a/include/vcpkg/registries.h b/include/vcpkg/registries.h index 5ecde7aff8..717f4975c6 100644 --- a/include/vcpkg/registries.h +++ b/include/vcpkg/registries.h @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include #include @@ -43,10 +45,10 @@ namespace vcpkg bool stale() const { return data->second.stale; } const std::string& uri() const { return data->first; } - void ensure_up_to_date(const VcpkgPaths& paths) const; + ExpectedL ensure_up_to_date(const VcpkgPaths& paths) const; }; - Entry get_or_fetch(const VcpkgPaths& paths, StringView repo, StringView reference); + ExpectedL get_or_fetch(const VcpkgPaths& paths, StringView repo, StringView reference); LockDataType lockdata; bool modified = false; @@ -63,7 +65,7 @@ namespace vcpkg struct RegistryEntry { - virtual View get_port_versions() const = 0; + virtual ExpectedL> get_port_versions() const = 0; virtual ExpectedL get_version(const Version& version) const = 0; @@ -75,16 +77,16 @@ namespace vcpkg virtual StringLiteral kind() const = 0; // returns nullptr if the port doesn't exist - virtual std::unique_ptr get_port_entry(StringView port_name) const = 0; + virtual ExpectedL> get_port_entry(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 append_all_port_names(std::vector& port_names) const = 0; + virtual ExpectedL append_all_port_names(std::vector& port_names) const = 0; // appends the names of the ports to the out parameter if this can be known without // network access. // returns true if names were appended, otherwise returns false. - virtual bool try_append_all_port_names_no_network(std::vector& port_names) const = 0; + virtual ExpectedL try_append_all_port_names_no_network(std::vector& port_names) const = 0; virtual ExpectedL get_baseline_version(StringView port_name) const = 0; @@ -142,10 +144,10 @@ namespace vcpkg bool has_modifications() const; // Returns a sorted vector of all reachable port names in this set. - std::vector get_all_reachable_port_names() const; + ExpectedL> get_all_reachable_port_names() const; // Returns a sorted vector of all reachable port names we can provably determine without touching the network. - std::vector get_all_known_reachable_port_names_no_network() const; + ExpectedL> get_all_known_reachable_port_names_no_network() const; private: std::unique_ptr default_registry_; @@ -162,8 +164,8 @@ namespace vcpkg Path path, std::string baseline); - ExpectedL>> get_builtin_versions(const VcpkgPaths& paths, - StringView port_name); + ExpectedL>>> get_builtin_versions( + const VcpkgPaths& paths, StringView port_name); ExpectedL>> get_builtin_baseline(const VcpkgPaths& paths); @@ -173,4 +175,25 @@ namespace vcpkg // No match is 0, exact match is SIZE_MAX, wildcard match is the length of the pattern. // Note that the * is included in the match size to distinguish from 0 == no match. size_t package_pattern_match(StringView name, StringView pattern); + + struct VersionDbEntry + { + Version version; + VersionScheme scheme = VersionScheme::String; + + // only one of these may be non-empty + std::string git_tree; + Path p; + }; + + // VersionDbType::Git => VersionDbEntry.git_tree is filled + // VersionDbType::Filesystem => VersionDbEntry.path is filled + enum class VersionDbType + { + Git, + Filesystem, + }; + + std::unique_ptr>> make_version_db_deserializer(VersionDbType type, + const Path& root); } diff --git a/include/vcpkg/registries.private.h b/include/vcpkg/registries.private.h deleted file mode 100644 index 4fea50041c..0000000000 --- a/include/vcpkg/registries.private.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include -#include -#include - -namespace vcpkg -{ - - struct VersionDbEntry - { - Version version; - VersionScheme scheme = VersionScheme::String; - - // only one of these may be non-empty - std::string git_tree; - Path p; - }; - - // VersionDbType::Git => VersionDbEntry.git_tree is filled - // VersionDbType::Filesystem => VersionDbEntry.path is filled - enum class VersionDbType - { - Git, - Filesystem, - }; - - std::unique_ptr>> make_version_db_deserializer(VersionDbType type, - const Path& root); -} diff --git a/locales/messages.json b/locales/messages.json index b59c739fda..a5d60e5f45 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -536,10 +536,8 @@ "_CouldNotDeduceNugetIdAndVersion.comment": "An example of {path} is /foo/bar.", "CouldNotFindBaseline": "Could not find explicitly specified baseline `\"{commit_sha}\"` in baseline file {path}", "_CouldNotFindBaseline.comment": "An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949. An example of {path} is /foo/bar.", - "CouldNotFindBaselineForRepo": "Couldn't find baseline `\"{commit_sha}\"` for repo {package_name}", - "_CouldNotFindBaselineForRepo.comment": "An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949. An example of {package_name} is zlib.", - "CouldNotFindBaselineInCommit": "Couldn't find baseline in commit `\"{commit_sha}\"` from repo {package_name}:", - "_CouldNotFindBaselineInCommit.comment": "An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949. An example of {package_name} is zlib.", + "CouldNotFindBaselineInCommit": "Couldn't find baseline in {url} at {commit_sha} for {package_name}.", + "_CouldNotFindBaselineInCommit.comment": "An example of {url} is https://github.com/microsoft/vcpkg. An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949. An example of {package_name} is zlib.", "CouldNotFindGitTreeAtCommit": "could not find the git tree for `versions` in repo {package_name} at commit {commit_sha}", "_CouldNotFindGitTreeAtCommit.comment": "An example of {package_name} is zlib. An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949.", "CouldNotFindToolVersion": "Could not find in {path}", @@ -742,8 +740,8 @@ "FailedToDownloadFromMirrorSet": "Failed to download from mirror set", "FailedToExtract": "Failed to extract \"{path}\":", "_FailedToExtract.comment": "An example of {path} is /foo/bar.", - "FailedToFetchError": "{error_msg}\nFailed to fetch {package_name}:", - "_FailedToFetchError.comment": "An example of {error_msg} is File Not Found. An example of {package_name} is zlib.", + "FailedToFetchRepo": "Failed to fetch {url}.", + "_FailedToFetchRepo.comment": "An example of {url} is https://github.com/microsoft/vcpkg.", "FailedToFindBaseline": "Failed to find baseline.json", "FailedToFindPortFeature": "{package_name} has no feature named {feature}.", "_FailedToFindPortFeature.comment": "An example of {feature} is avisynthplus. An example of {package_name} is zlib.", @@ -861,8 +859,8 @@ "_GitFailedToFetch.comment": "{value} is a git ref like 'origin/main' An example of {url} is https://github.com/microsoft/vcpkg.", "GitFailedToInitializeLocalRepository": "failed to initialize local repository {path}", "_GitFailedToInitializeLocalRepository.comment": "An example of {path} is /foo/bar.", - "GitRegistryMustHaveBaseline": "The git registry entry for \"{package_name}\" must have a \"baseline\" field that is a valid git commit SHA (40 hexadecimal characters).\nThe current HEAD of that repo is \"{value}\".", - "_GitRegistryMustHaveBaseline.comment": "{value} is a commit sha An example of {package_name} is zlib.", + "GitRegistryMustHaveBaseline": "The git registry \"{url}\" must have a \"baseline\" field that is a valid git commit SHA (40 hexadecimal characters).\nTo use the current latest versions, set baseline to that repo's HEAD, \"{commit_sha}\".", + "_GitRegistryMustHaveBaseline.comment": "An example of {url} is https://github.com/microsoft/vcpkg. An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949.", "GitStatusOutputExpectedFileName": "expected a file name", "GitStatusOutputExpectedNewLine": "expected new line", "GitStatusOutputExpectedRenameOrNewline": "expected renamed file or new lines", diff --git a/src/vcpkg-test/registries.cpp b/src/vcpkg-test/registries.cpp index 2317c663f1..811ce92e96 100644 --- a/src/vcpkg-test/registries.cpp +++ b/src/vcpkg-test/registries.cpp @@ -5,7 +5,6 @@ #include #include -#include using namespace vcpkg; @@ -15,14 +14,15 @@ namespace { StringLiteral kind() const override { return "test"; } - std::unique_ptr get_port_entry(StringView) const override { return nullptr; } + ExpectedL> get_port_entry(StringView) const override { return nullptr; } - void append_all_port_names(std::vector& port_names) const override + ExpectedL append_all_port_names(std::vector& port_names) const override { port_names.insert(port_names.end(), all_port_names.begin(), all_port_names.end()); + return Unit{}; } - bool try_append_all_port_names_no_network(std::vector& port_names) const override + ExpectedL try_append_all_port_names_no_network(std::vector& port_names) const override { port_names.insert(port_names.end(), no_network_port_names.begin(), no_network_port_names.end()); return !no_network_port_names.empty(); @@ -766,14 +766,14 @@ TEST_CASE ("get_all_port_names", "[registries]") // All the known ports from the default registry // hello, world, abcdefg, abc, abcde from the first registry // twoRegistry from the second registry - CHECK(with_default_registry.get_all_reachable_port_names() == + CHECK(with_default_registry.get_all_reachable_port_names().value_or_exit(VCPKG_LINE_INFO) == std::vector{ "aDefault", "abc", "abcde", "abcdefg", "bDefault", "cDefault", "hello", "twoRegistry", "world"}); // All the old ports from the default registry // hello, world, notpresent from the first registry (since network was unknown) // twoOld from the second registry - CHECK(with_default_registry.get_all_known_reachable_port_names_no_network() == + CHECK(with_default_registry.get_all_known_reachable_port_names_no_network().value_or_exit(VCPKG_LINE_INFO) == std::vector{ "aDefaultOld", "bDefaultOld", "cDefaultOld", "hello", "notpresent", "twoOld", "world"}); } @@ -784,12 +784,12 @@ TEST_CASE ("get_all_port_names", "[registries]") // hello, world, abcdefg, abc, abcde from the first registry // twoRegistry from the second registry - CHECK(without_default_registry.get_all_reachable_port_names() == + CHECK(without_default_registry.get_all_reachable_port_names().value_or_exit(VCPKG_LINE_INFO) == std::vector{"abc", "abcde", "abcdefg", "hello", "twoRegistry", "world"}); // hello, world, notpresent from the first registry // twoOld from the second registry - CHECK(without_default_registry.get_all_known_reachable_port_names_no_network() == + CHECK(without_default_registry.get_all_known_reachable_port_names_no_network().value_or_exit(VCPKG_LINE_INFO) == std::vector{"hello", "notpresent", "twoOld", "world"}); } } diff --git a/src/vcpkg/base/files.cpp b/src/vcpkg/base/files.cpp index 245c35860d..0ff799233b 100644 --- a/src/vcpkg/base/files.cpp +++ b/src/vcpkg/base/files.cpp @@ -1567,60 +1567,85 @@ namespace vcpkg } std::vector ReadOnlyFilesystem::get_files_recursive(const Path& dir, LineInfo li) const + { + return this->try_get_files_recursive(dir).value_or_exit(li); + } + + ExpectedL> ReadOnlyFilesystem::try_get_files_recursive(const Path& dir) const { std::error_code ec; auto maybe_files = this->get_files_recursive(dir, ec); if (ec) { - exit_filesystem_call_error(li, ec, __func__, {dir}); + return format_filesystem_call_error(ec, __func__, {dir}); } return maybe_files; } std::vector ReadOnlyFilesystem::get_files_non_recursive(const Path& dir, LineInfo li) const + { + return this->try_get_files_non_recursive(dir).value_or_exit(li); + } + + ExpectedL> ReadOnlyFilesystem::try_get_files_non_recursive(const Path& dir) const { std::error_code ec; auto maybe_files = this->get_files_non_recursive(dir, ec); if (ec) { - exit_filesystem_call_error(li, ec, __func__, {dir}); + return format_filesystem_call_error(ec, __func__, {dir}); } return maybe_files; } std::vector ReadOnlyFilesystem::get_directories_recursive(const Path& dir, LineInfo li) const + { + return this->try_get_directories_recursive(dir).value_or_exit(li); + } + + ExpectedL> ReadOnlyFilesystem::try_get_directories_recursive(const Path& dir) const { std::error_code ec; auto maybe_directories = this->get_directories_recursive(dir, ec); if (ec) { - exit_filesystem_call_error(li, ec, __func__, {dir}); + return format_filesystem_call_error(ec, __func__, {dir}); } return maybe_directories; } std::vector ReadOnlyFilesystem::get_directories_non_recursive(const Path& dir, LineInfo li) const + { + return this->try_get_directories_non_recursive(dir).value_or_exit(li); + } + + ExpectedL> ReadOnlyFilesystem::try_get_directories_non_recursive(const Path& dir) const { std::error_code ec; auto maybe_directories = this->get_directories_non_recursive(dir, ec); if (ec) { - exit_filesystem_call_error(li, ec, __func__, {dir}); + return format_filesystem_call_error(ec, __func__, {dir}); } return maybe_directories; } std::vector ReadOnlyFilesystem::get_regular_files_recursive(const Path& dir, LineInfo li) const + { + return this->try_get_regular_files_recursive(dir).value_or_exit(li); + } + + ExpectedL> ReadOnlyFilesystem::try_get_regular_files_recursive(const Path& dir) const { std::error_code ec; auto maybe_directories = this->get_regular_files_recursive(dir, ec); if (ec) { - exit_filesystem_call_error(li, ec, __func__, {dir}); + return format_filesystem_call_error(ec, __func__, {dir}); } return maybe_directories; @@ -1628,24 +1653,35 @@ namespace vcpkg std::vector ReadOnlyFilesystem::get_regular_files_recursive_lexically_proximate(const Path& dir, LineInfo li) const + { + return this->try_get_regular_files_recursive_lexically_proximate(dir).value_or_exit(li); + } + + ExpectedL> ReadOnlyFilesystem::try_get_regular_files_recursive_lexically_proximate( + const Path& dir) const { std::error_code ec; auto maybe_directories = this->get_regular_files_recursive_lexically_proximate(dir, ec); if (ec) { - exit_filesystem_call_error(li, ec, __func__, {dir}); + return format_filesystem_call_error(ec, __func__, {dir}); } return maybe_directories; } std::vector ReadOnlyFilesystem::get_regular_files_non_recursive(const Path& dir, LineInfo li) const + { + return this->try_get_regular_files_non_recursive(dir).value_or_exit(li); + } + + ExpectedL> ReadOnlyFilesystem::try_get_regular_files_non_recursive(const Path& dir) const { std::error_code ec; auto maybe_directories = this->get_regular_files_non_recursive(dir, ec); if (ec) { - exit_filesystem_call_error(li, ec, __func__, {dir}); + return format_filesystem_call_error(ec, __func__, {dir}); } return maybe_directories; diff --git a/src/vcpkg/commands.add-version.cpp b/src/vcpkg/commands.add-version.cpp index bfc748ca6e..f63020f8e5 100644 --- a/src/vcpkg/commands.add-version.cpp +++ b/src/vcpkg/commands.add-version.cpp @@ -213,96 +213,102 @@ namespace return UpdateResult::Updated; } - auto maybe_versions = get_builtin_versions(paths, port_name); - if (auto versions = maybe_versions.get()) + auto maybe_maybe_versions = get_builtin_versions(paths, port_name); + auto maybe_versions = maybe_maybe_versions.get(); + if (!maybe_versions) { - const auto& versions_end = versions->end(); + msg::println_error(msg::format(msgAddVersionUnableToParseVersionsFile, msg::path = version_db_file_path) + .append_raw('\n') + .append(maybe_maybe_versions.error())); + Checks::exit_fail(VCPKG_LINE_INFO); + } + + auto versions = maybe_versions->get(); + if (!versions) + { + Checks::unreachable(VCPKG_LINE_INFO, "Version file existed but was still unknown"); + } - auto found_same_sha = std::find_if( - versions->begin(), versions_end, [&](auto&& entry) -> bool { return entry.second == git_tree; }); - if (found_same_sha != versions_end) + const auto& versions_end = versions->end(); + auto found_same_sha = std::find_if( + versions->begin(), versions_end, [&](auto&& entry) -> bool { return entry.second == git_tree; }); + if (found_same_sha != versions_end) + { + if (found_same_sha->first.version == port_version.version) { - if (found_same_sha->first.version == port_version.version) + if (print_success) { - if (print_success) - { - msg::println(Color::success, - msgAddVersionVersionAlreadyInFile, - msg::version = port_version.version, - msg::path = version_db_file_path); - } - return UpdateResult::NotUpdated; + msg::println(Color::success, + msgAddVersionVersionAlreadyInFile, + msg::version = port_version.version, + msg::path = version_db_file_path); } - msg::println_warning(msg::format(msgAddVersionPortFilesShaUnchanged, - msg::package_name = port_name, - msg::version = found_same_sha->first.version) - .append_raw("\n-- SHA: ") - .append_raw(git_tree) - .append_raw("\n-- ") - .append(msgAddVersionCommitChangesReminder) - .append_raw("\n***") - .append(msgAddVersionNoFilesUpdated) - .append_raw("***")); - if (keep_going) return UpdateResult::NotUpdated; - Checks::exit_fail(VCPKG_LINE_INFO); + return UpdateResult::NotUpdated; } + msg::println_warning(msg::format(msgAddVersionPortFilesShaUnchanged, + msg::package_name = port_name, + msg::version = found_same_sha->first.version) + .append_raw("\n-- SHA: ") + .append_raw(git_tree) + .append_raw("\n-- ") + .append(msgAddVersionCommitChangesReminder) + .append_raw("\n***") + .append(msgAddVersionNoFilesUpdated) + .append_raw("***")); + if (keep_going) return UpdateResult::NotUpdated; + Checks::exit_fail(VCPKG_LINE_INFO); + } - auto it = std::find_if( - versions->begin(), versions_end, [&](const std::pair& entry) -> bool { - return entry.first.version == port_version.version; - }); - - if (it != versions_end) - { - if (!overwrite_version) - { - msg::println_error( - msg::format(msgAddVersionPortFilesShaChanged, msg::package_name = port_name) - .append_raw('\n') - .append(msgAddVersionVersionIs, msg::version = port_version.version) - .append_raw('\n') - .append(msgAddVersionOldShaIs, msg::commit_sha = it->second) - .append_raw('\n') - .append(msgAddVersionNewShaIs, msg::commit_sha = git_tree) - .append_raw('\n') - .append(msgAddVersionUpdateVersionReminder) - .append_raw('\n') - .append(msgAddVersionOverwriteOptionSuggestion, msg::option = OPTION_OVERWRITE_VERSION) - .append_raw("\n***") - .append(msgAddVersionNoFilesUpdated) - .append_raw("***")); - if (keep_going) return UpdateResult::NotUpdated; - Checks::exit_fail(VCPKG_LINE_INFO); - } + auto it = std::find_if( + versions->begin(), versions_end, [&](const std::pair& entry) -> bool { + return entry.first.version == port_version.version; + }); - it->first = port_version; - it->second = git_tree; - } - else + if (it != versions_end) + { + if (!overwrite_version) { - versions->insert(versions->begin(), std::make_pair(port_version, git_tree)); + msg::println_error( + msg::format(msgAddVersionPortFilesShaChanged, msg::package_name = port_name) + .append_raw('\n') + .append(msgAddVersionVersionIs, msg::version = port_version.version) + .append_raw('\n') + .append(msgAddVersionOldShaIs, msg::commit_sha = it->second) + .append_raw('\n') + .append(msgAddVersionNewShaIs, msg::commit_sha = git_tree) + .append_raw('\n') + .append(msgAddVersionUpdateVersionReminder) + .append_raw('\n') + .append(msgAddVersionOverwriteOptionSuggestion, msg::option = OPTION_OVERWRITE_VERSION) + .append_raw("\n***") + .append(msgAddVersionNoFilesUpdated) + .append_raw("***")); + if (keep_going) return UpdateResult::NotUpdated; + Checks::exit_fail(VCPKG_LINE_INFO); } - if (!skip_version_format_check) - { - check_used_version_scheme(port_version, port_name); - } + it->first = port_version; + it->second = git_tree; + } + else + { + versions->insert(versions->begin(), std::make_pair(port_version, git_tree)); + } - write_versions_file(fs, *versions, version_db_file_path); - if (print_success) - { - msg::println(Color::success, - msgAddVersionAddedVersionToFile, - msg::version = port_version.version, - msg::path = version_db_file_path); - } - return UpdateResult::Updated; + if (!skip_version_format_check) + { + check_used_version_scheme(port_version, port_name); } - msg::println_error(msg::format(msgAddVersionUnableToParseVersionsFile, msg::path = version_db_file_path) - .append_raw('\n') - .append(maybe_versions.error())); - Checks::exit_fail(VCPKG_LINE_INFO); + write_versions_file(fs, *versions, version_db_file_path); + if (print_success) + { + msg::println(Color::success, + msgAddVersionAddedVersionToFile, + msg::version = port_version.version, + msg::path = version_db_file_path); + } + return UpdateResult::Updated; } constexpr CommandSwitch AddVersionSwitches[] = { diff --git a/src/vcpkg/commands.ci-verify-versions.cpp b/src/vcpkg/commands.ci-verify-versions.cpp index 0b93407829..15a3d0c3ea 100644 --- a/src/vcpkg/commands.ci-verify-versions.cpp +++ b/src/vcpkg/commands.ci-verify-versions.cpp @@ -38,17 +38,18 @@ namespace const std::string& local_git_tree, bool verify_git_trees) { - auto maybe_versions = vcpkg::get_builtin_versions(paths, port_name); - if (!maybe_versions.has_value()) + auto maybe_maybe_versions = vcpkg::get_builtin_versions(paths, port_name); + const auto maybe_versions = maybe_maybe_versions.get(); + if (!maybe_versions) { return {msg::format_error( msgWhileParsingVersionsForPort, msg::package_name = port_name, msg::path = versions_file_path) - .append(std::move(maybe_versions).error()), + .append(std::move(maybe_maybe_versions).error()), expected_right_tag}; } - const auto& versions = maybe_versions.value_or_exit(VCPKG_LINE_INFO); - if (versions.empty()) + const auto versions = maybe_versions->get(); + if (!versions || versions->empty()) { return {msg::format_error( msgWhileParsingVersionsForPort, msg::package_name = port_name, msg::path = versions_file_path) @@ -59,7 +60,7 @@ namespace if (verify_git_trees) { - for (auto&& version_entry : versions) + for (auto&& version_entry : *versions) { bool version_ok = false; for (StringView control_file : {"CONTROL", "vcpkg.json"}) @@ -132,9 +133,9 @@ namespace const auto local_port_version = maybe_scf.value(VCPKG_LINE_INFO)->to_schemed_version(); - auto versions_end = versions.end(); + auto versions_end = versions->end(); auto it = - std::find_if(versions.begin(), versions_end, [&](const std::pair& entry) { + std::find_if(versions->begin(), versions_end, [&](const std::pair& entry) { return entry.first.version == local_port_version.version; }); if (it == versions_end) diff --git a/src/vcpkg/commands.install.cpp b/src/vcpkg/commands.install.cpp index 63230c0f56..6c333d2c1f 100644 --- a/src/vcpkg/commands.install.cpp +++ b/src/vcpkg/commands.install.cpp @@ -651,7 +651,8 @@ namespace vcpkg static std::vector get_all_known_reachable_port_names_no_network(const VcpkgPaths& paths) { - return paths.make_registry_set()->get_all_known_reachable_port_names_no_network(); + return paths.make_registry_set()->get_all_known_reachable_port_names_no_network().value_or_exit( + VCPKG_LINE_INFO); } constexpr CommandMetadata CommandInstallMetadata{ diff --git a/src/vcpkg/paragraphs.cpp b/src/vcpkg/paragraphs.cpp index 00fe1d0b8e..8166b9adc3 100644 --- a/src/vcpkg/paragraphs.cpp +++ b/src/vcpkg/paragraphs.cpp @@ -79,6 +79,14 @@ namespace vcpkg return result; } + std::unique_ptr ParseControlErrorInfo::from_error(StringView name, LocalizedString&& ls) + { + auto error_info = std::make_unique(); + error_info->name.assign(name.data(), name.size()); + error_info->error = std::move(ls); + return error_info; + } + static Optional> remove_field(Paragraph* fields, StringView fieldname) { auto it = fields->find(fieldname.to_string()); @@ -370,7 +378,6 @@ namespace vcpkg::Paragraphs MessageSink& warning_sink) { auto res = Json::parse(text, origin); - LocalizedString error; if (auto val = res.get()) { if (val->value.is_object()) @@ -379,16 +386,10 @@ namespace vcpkg::Paragraphs origin, val->value.object(VCPKG_LINE_INFO), warning_sink); } - error = msg::format(msgJsonValueNotObject); + return ParseControlErrorInfo::from_error(origin, msg::format(msgJsonValueNotObject)); } - else - { - error = LocalizedString::from_raw(res.error()->to_string()); - } - auto error_info = std::make_unique(); - error_info->name = origin.to_string(); - error_info->error = std::move(error); - return error_info; + + return ParseControlErrorInfo::from_error(origin, LocalizedString::from_raw(res.error()->to_string())); } ParseExpected try_load_port_text(const std::string& text, @@ -408,10 +409,8 @@ namespace vcpkg::Paragraphs { return SourceControlFile::parse_control_file(origin, std::move(*vector_pghs)); } - auto error_info = std::make_unique(); - error_info->name = origin.to_string(); - error_info->error = pghs.error(); - return error_info; + + return ParseControlErrorInfo::from_error(origin, std::move(pghs).error()); } ParseExpected try_load_port(const ReadOnlyFilesystem& fs, const Path& port_directory) @@ -420,55 +419,51 @@ namespace vcpkg::Paragraphs const auto manifest_path = port_directory / "vcpkg.json"; const auto control_path = port_directory / "CONTROL"; - const auto port_name = port_directory.filename().to_string(); + const auto port_name = port_directory.filename(); std::error_code ec; auto manifest_contents = fs.read_contents(manifest_path, ec); if (ec) { - if (fs.exists(manifest_path, IgnoreErrors{})) + const auto exists = ec != std::errc::no_such_file_or_directory; + if (exists) { - auto error_info = std::make_unique(); - error_info->name = port_name; - error_info->error = msg::format_error(msgFailedToParseManifest, msg::path = manifest_path); - return error_info; + auto formatted = msg::format_error(msgFailedToParseManifest, msg::path = manifest_path) + .append_raw("\n") + .append(format_filesystem_call_error(ec, "read_contents", {manifest_path})); + + return ParseControlErrorInfo::from_error(port_name, std::move(formatted)); } - } - else - { - vcpkg::Checks::msg_check_exit(VCPKG_LINE_INFO, - !fs.exists(control_path, IgnoreErrors{}), - msgManifestConflict, - msg::path = port_directory); - return try_load_manifest_text(manifest_contents, manifest_path, stdout_sink); - } + if (fs.exists(control_path, IgnoreErrors{})) + { + ExpectedL> pghs = get_paragraphs(fs, control_path); + if (auto vector_pghs = pghs.get()) + { + return SourceControlFile::parse_control_file(control_path, std::move(*vector_pghs)); + } - if (fs.exists(control_path, IgnoreErrors{})) - { - ExpectedL> pghs = get_paragraphs(fs, control_path); - if (auto vector_pghs = pghs.get()) + return ParseControlErrorInfo::from_error(port_name, std::move(pghs).error()); + } + + if (fs.exists(port_directory, IgnoreErrors{})) { - return SourceControlFile::parse_control_file(control_path, std::move(*vector_pghs)); + return ParseControlErrorInfo::from_error(port_name, + msg::format_error(msgPortMissingManifest, + msg::package_name = port_name, + msg::path = port_directory)); } - auto error_info = std::make_unique(); - error_info->name = port_name; - error_info->error = pghs.error(); - return error_info; - } - auto error_info = std::make_unique(); - error_info->name = port_name; - if (fs.exists(port_directory, IgnoreErrors{})) - { - error_info->error = - msg::format_error(msgPortMissingManifest, msg::package_name = port_name, msg::path = port_directory); + return ParseControlErrorInfo::from_error( + port_name, msg::format_error(msgPortDoesNotExist, msg::package_name = port_name)); } - else + + if (fs.exists(control_path, IgnoreErrors{})) { - error_info->error = msg::format_error(msgPortDoesNotExist, msg::package_name = port_name); + return ParseControlErrorInfo::from_error( + port_name, msg::format_error(msgManifestConflict, msg::path = port_directory)); } - return error_info; + return try_load_manifest_text(manifest_contents, manifest_path, stdout_sink); } ExpectedL try_load_cached_package(const ReadOnlyFilesystem& fs, @@ -506,10 +501,10 @@ namespace vcpkg::Paragraphs LoadResults try_load_all_registry_ports(const ReadOnlyFilesystem& fs, const RegistrySet& registries) { LoadResults ret; - std::vector ports = registries.get_all_reachable_port_names(); + std::vector ports = registries.get_all_reachable_port_names().value_or_exit(VCPKG_LINE_INFO); for (const auto& port_name : ports) { - auto impl = registries.registry_for_port(port_name); + const auto impl = registries.registry_for_port(port_name); if (!impl) { // this is a port for which no registry is set @@ -518,19 +513,23 @@ namespace vcpkg::Paragraphs continue; } - const auto baseline_version = impl->get_baseline_version(port_name); + auto maybe_baseline_version = impl->get_baseline_version(port_name); + auto baseline_version = maybe_baseline_version.get(); if (!baseline_version) continue; // port is attributed to this registry, but it is not in the baseline - const auto port_entry = impl->get_port_entry(port_name); - if (!port_entry) continue; // port is attributed to this registry, but there is no version db - auto port_location = port_entry->get_version(*baseline_version.get()); + auto maybe_port_entry = impl->get_port_entry(port_name); + const auto port_entry = maybe_port_entry.get(); + if (!port_entry) continue; // port is attributed to this registry, but loading it failed + if (!*port_entry) continue; // port is attributed to this registry, but doesn't exist in this registry + auto maybe_port_location = (*port_entry)->get_version(*baseline_version); + const auto port_location = maybe_port_location.get(); if (!port_location) continue; // baseline version was not in version db (registry consistency issue) - auto maybe_spgh = try_load_port(fs, port_location.get()->path); + auto maybe_spgh = try_load_port(fs, port_location->path); if (const auto spgh = maybe_spgh.get()) { ret.paragraphs.push_back({ std::move(*spgh), - std::move(port_location.get()->path), - std::move(port_location.get()->location), + std::move(port_location->path), + std::move(port_location->location), }); } else diff --git a/src/vcpkg/portfileprovider.cpp b/src/vcpkg/portfileprovider.cpp index 4baabb58a4..410d4cc301 100644 --- a/src/vcpkg/portfileprovider.cpp +++ b/src/vcpkg/portfileprovider.cpp @@ -20,7 +20,7 @@ namespace { OverlayRegistryEntry(Path&& p, Version&& v) : root(p), version(v) { } - View get_port_versions() const override { return {&version, 1}; } + ExpectedL> get_port_versions() const override { return View{&version, 1}; } ExpectedL get_version(const Version& v) const override { if (v == version) @@ -167,7 +167,10 @@ namespace vcpkg virtual View get_port_versions(StringView port_name) const override { - return entry(port_name).value_or_exit(VCPKG_LINE_INFO)->get_port_versions(); + return entry(port_name) + .value_or_exit(VCPKG_LINE_INFO) + ->get_port_versions() + .value_or_exit(VCPKG_LINE_INFO); } ExpectedL> load_control_file( diff --git a/src/vcpkg/registries.cpp b/src/vcpkg/registries.cpp index 1f268dcd14..fc80a08108 100644 --- a/src/vcpkg/registries.cpp +++ b/src/vcpkg/registries.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -179,15 +178,56 @@ namespace struct GitRegistry; + struct PortVersionsGitTreesStructOfArrays + { + PortVersionsGitTreesStructOfArrays() = default; + PortVersionsGitTreesStructOfArrays(const PortVersionsGitTreesStructOfArrays&) = default; + PortVersionsGitTreesStructOfArrays(PortVersionsGitTreesStructOfArrays&&) = default; + PortVersionsGitTreesStructOfArrays& operator=(const PortVersionsGitTreesStructOfArrays&) = default; + PortVersionsGitTreesStructOfArrays& operator=(PortVersionsGitTreesStructOfArrays&&) = default; + + explicit PortVersionsGitTreesStructOfArrays(std::vector&& db_entries) + { + assign(std::move(db_entries)); + } + + void assign(std::vector&& db_entries) + { + m_port_versions.reserve(db_entries.size()); + m_git_trees.reserve(db_entries.size()); + m_port_versions.clear(); + m_git_trees.clear(); + for (auto& entry : db_entries) + { + m_port_versions.push_back(std::move(entry.version)); + m_git_trees.push_back(std::move(entry.git_tree)); + } + + db_entries.clear(); + } + + // 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] + const std::vector& port_versions() const noexcept { return m_port_versions; } + const std::vector& git_trees() const noexcept { return m_git_trees; } + + private: + std::vector m_port_versions; + std::vector m_git_trees; + }; + struct GitRegistryEntry final : RegistryEntry { - GitRegistryEntry(const GitRegistry& reg, StringView name); + GitRegistryEntry(StringView port_name, + const GitRegistry& parent, + bool stale, + std::vector&& version_entries); - View get_port_versions() const override; + ExpectedL> get_port_versions() const override; ExpectedL get_version(const Version& version) const override; private: - void fill_data_from_path(const ReadOnlyFilesystem& fs, const Path& port_versions_path) const; + ExpectedL ensure_not_stale() const; std::string port_name; @@ -196,10 +236,7 @@ namespace // Indicates whether port_versions and git_trees were filled in with stale (i.e. lock) data. mutable bool stale; - // 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] - mutable std::vector port_versions; - mutable std::vector git_trees; + mutable PortVersionsGitTreesStructOfArrays last_loaded; }; struct GitRegistry final : RegistryImplementation @@ -214,48 +251,62 @@ namespace StringLiteral kind() const override { return "git"; } - std::unique_ptr get_port_entry(StringView) const override; + ExpectedL> get_port_entry(StringView) const override; - void append_all_port_names(std::vector&) const override; + ExpectedL append_all_port_names(std::vector&) const override; - bool try_append_all_port_names_no_network(std::vector& port_names) const override; + ExpectedL try_append_all_port_names_no_network(std::vector& port_names) const override; ExpectedL get_baseline_version(StringView) const override; private: friend struct GitRegistryEntry; - LockFile::Entry get_lock_entry() const + const ExpectedL& get_lock_entry() const { return m_lock_entry.get( [this]() { return m_paths.get_installed_lockfile().get_or_fetch(m_paths, m_repo, m_reference); }); } - Path get_versions_tree_path() const + const ExpectedL& get_versions_tree_path() const { - return m_versions_tree.get([this]() -> Path { - auto e = get_lock_entry(); - e.ensure_up_to_date(m_paths); + return m_versions_tree.get([this]() -> ExpectedL { + auto& maybe_lock_entry = get_lock_entry(); + auto lock_entry = maybe_lock_entry.get(); + if (!lock_entry) + { + return maybe_lock_entry.error(); + } + + auto maybe_up_to_date = lock_entry->ensure_up_to_date(m_paths); + if (!maybe_up_to_date) + { + return maybe_up_to_date.error(); + } + auto maybe_tree = m_paths.git_find_object_id_for_remote_registry_path( - e.commit_id(), registry_versions_dir_name.to_string()); - if (!maybe_tree) + lock_entry->commit_id(), registry_versions_dir_name.to_string()); + auto tree = maybe_tree.get(); + if (!tree) { get_global_metrics_collector().track_define(DefineMetric::RegistriesErrorNoVersionsAtCommit); - Checks::msg_exit_with_error(VCPKG_LINE_INFO, - msg::format(msgCouldNotFindGitTreeAtCommit, - msg::package_name = m_repo, - msg::commit_sha = e.commit_id()) - .append_raw('\n') - .append_raw(maybe_tree.error())); + return msg::format_error(msgCouldNotFindGitTreeAtCommit, + msg::package_name = m_repo, + msg::commit_sha = lock_entry->commit_id()) + .append_raw('\n') + .append_raw(maybe_tree.error()); } - auto maybe_path = m_paths.git_extract_tree_from_remote_registry(*maybe_tree.get()); - if (!maybe_path) + + auto maybe_path = m_paths.git_extract_tree_from_remote_registry(*tree); + auto path = maybe_path.get(); + if (!path) { - msg::println_error(msgFailedToCheckoutRepo, msg::package_name = m_repo); - msg::println_error(LocalizedString::from_raw(maybe_path.error())); - Checks::exit_fail(VCPKG_LINE_INFO); + return msg::format_error(msgFailedToCheckoutRepo, msg::package_name = m_repo) + .append_raw('\n') + .append(maybe_path.error()); } - return std::move(*maybe_path.get()); + + return std::move(*path); }); } @@ -265,31 +316,54 @@ namespace bool stale; }; - VersionsTreePathResult get_stale_versions_tree_path() const + ExpectedL get_unstale_stale_versions_tree_path() const + { + auto& maybe_versions_tree = get_versions_tree_path(); + if (auto versions_tree = maybe_versions_tree.get()) + { + return VersionsTreePathResult{*versions_tree, false}; + } + + return maybe_versions_tree.error(); + } + + ExpectedL get_stale_versions_tree_path() const { - auto e = get_lock_entry(); - if (!e.stale()) + const auto& maybe_entry = get_lock_entry(); + auto entry = maybe_entry.get(); + if (!entry) { - return {get_versions_tree_path(), false}; + return maybe_entry.error(); } + + if (!entry->stale()) + { + return get_unstale_stale_versions_tree_path(); + } + if (!m_stale_versions_tree.has_value()) { auto maybe_tree = m_paths.git_find_object_id_for_remote_registry_path( - e.commit_id(), registry_versions_dir_name.to_string()); - if (!maybe_tree) + entry->commit_id(), registry_versions_dir_name.to_string()); + auto tree = maybe_tree.get(); + if (!tree) { // This could be caused by git gc or otherwise -- fall back to full fetch - return {get_versions_tree_path(), false}; + return get_unstale_stale_versions_tree_path(); } - auto maybe_path = m_paths.git_extract_tree_from_remote_registry(*maybe_tree.get()); - if (!maybe_path) + + auto maybe_path = m_paths.git_extract_tree_from_remote_registry(*tree); + auto path = maybe_path.get(); + if (!path) { // This could be caused by git gc or otherwise -- fall back to full fetch - return {get_versions_tree_path(), false}; + return get_unstale_stale_versions_tree_path(); } - m_stale_versions_tree = std::move(*maybe_path.get()); + + m_stale_versions_tree = std::move(*path); } - return {*m_stale_versions_tree.get(), true}; + + return VersionsTreePathResult{m_stale_versions_tree.value_or_exit(VCPKG_LINE_INFO), true}; } const VcpkgPaths& m_paths; @@ -297,10 +371,10 @@ namespace std::string m_repo; std::string m_reference; std::string m_baseline_identifier; - DelayedInit m_lock_entry; + DelayedInit> m_lock_entry; mutable Optional m_stale_versions_tree; - DelayedInit m_versions_tree; - DelayedInit m_baseline; + DelayedInit> m_versions_tree; + DelayedInit> m_baseline; }; struct BuiltinPortTreeRegistryEntry final : RegistryEntry @@ -310,7 +384,7 @@ namespace { } - View get_port_versions() const override { return {&version, 1}; } + ExpectedL> get_port_versions() const override { return View{&version, 1}; } ExpectedL get_version(const Version& v) const override { if (v == version) @@ -333,24 +407,24 @@ namespace { BuiltinGitRegistryEntry(const VcpkgPaths& paths) : m_paths(paths) { } - View get_port_versions() const override { return port_versions; } + ExpectedL> get_port_versions() const override + { + return View{port_versions_soa.port_versions()}; + } ExpectedL get_version(const Version& version) const override; const VcpkgPaths& m_paths; std::string port_name; - // 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; + PortVersionsGitTreesStructOfArrays port_versions_soa; }; struct FilesystemRegistryEntry final : RegistryEntry { explicit FilesystemRegistryEntry(std::string&& port_name) : port_name(port_name) { } - View get_port_versions() const override { return port_versions; } + ExpectedL> get_port_versions() const override { return View{port_versions}; } ExpectedL get_version(const Version& version) const override; @@ -374,11 +448,11 @@ namespace StringLiteral kind() const override { return s_kind; } - std::unique_ptr get_port_entry(StringView port_name) const override; + ExpectedL> get_port_entry(StringView port_name) const override; - void append_all_port_names(std::vector&) const override; + ExpectedL append_all_port_names(std::vector&) const override; - bool try_append_all_port_names_no_network(std::vector& port_names) const override; + ExpectedL try_append_all_port_names_no_network(std::vector& port_names) const override; ExpectedL get_baseline_version(StringView port_name) const override; @@ -387,14 +461,16 @@ namespace DelayedInit m_baseline; private: - const ParseExpected& get_scf(const Path& path) const + const ExpectedL& get_scf(const Path& path) const { - return m_scfs.get_lazy(path, [this, &path]() { return Paragraphs::try_load_port(m_fs, path); }); + return m_scfs.get_lazy(path, [this, &path]() { + return map_parse_expected_to_localized_string(Paragraphs::try_load_port(m_fs, path)); + }); } const ReadOnlyFilesystem& m_fs; const Path m_builtin_ports_directory; - Cache> m_scfs; + Cache> m_scfs; }; constexpr StringLiteral BuiltinFilesRegistry::s_kind; @@ -413,11 +489,11 @@ namespace StringLiteral kind() const override { return s_kind; } - std::unique_ptr get_port_entry(StringView port_name) const override; + ExpectedL> get_port_entry(StringView port_name) const override; - void append_all_port_names(std::vector&) const override; + ExpectedL append_all_port_names(std::vector&) const override; - bool try_append_all_port_names_no_network(std::vector& port_names) const override; + ExpectedL try_append_all_port_names_no_network(std::vector& port_names) const override; ExpectedL get_baseline_version(StringView port_name) const override; @@ -441,24 +517,24 @@ namespace StringLiteral kind() const override { return s_kind; } - std::unique_ptr get_port_entry(StringView) const override + ExpectedL> get_port_entry(StringView) const override { - Checks::msg_exit_with_error(VCPKG_LINE_INFO, msgErrorRequireBaseline); + return msg::format_error(msgErrorRequireBaseline); } - void append_all_port_names(std::vector&) const override + ExpectedL append_all_port_names(std::vector&) const override { - Checks::msg_exit_with_error(VCPKG_LINE_INFO, msgErrorRequireBaseline); + return msg::format_error(msgErrorRequireBaseline); } - bool try_append_all_port_names_no_network(std::vector&) const override + ExpectedL try_append_all_port_names_no_network(std::vector&) const override { - Checks::msg_exit_with_error(VCPKG_LINE_INFO, msgErrorRequireBaseline); + return msg::format_error(msgErrorRequireBaseline); } ExpectedL get_baseline_version(StringView) const override { - Checks::msg_exit_with_error(VCPKG_LINE_INFO, msgErrorRequireBaseline); + return msg::format_error(msgErrorRequireBaseline); } ~BuiltinErrorRegistry() = default; @@ -474,11 +550,11 @@ namespace StringLiteral kind() const override { return "filesystem"; } - std::unique_ptr get_port_entry(StringView) const override; + ExpectedL> get_port_entry(StringView) const override; - void append_all_port_names(std::vector&) const override; + ExpectedL append_all_port_names(std::vector&) const override; - bool try_append_all_port_names_no_network(std::vector& port_names) const override; + ExpectedL try_append_all_port_names_no_network(std::vector& port_names) const override; ExpectedL get_baseline_version(StringView) const override; @@ -491,11 +567,11 @@ namespace }; Path relative_path_to_versions(StringView port_name); - ExpectedL> load_versions_file(const ReadOnlyFilesystem& fs, - VersionDbType vdb, - const Path& port_versions, - StringView port_name, - const Path& registry_root = {}); + ExpectedL>> load_versions_file(const ReadOnlyFilesystem& fs, + VersionDbType vdb, + const Path& port_versions, + StringView port_name, + const 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. @@ -504,31 +580,47 @@ namespace const Path& baseline_path, StringView identifier = {}); - void load_all_port_names_from_registry_versions(std::vector& out, - const ReadOnlyFilesystem& fs, - const Path& port_versions_path) + ExpectedL load_all_port_names_from_registry_versions(std::vector& out, + const ReadOnlyFilesystem& fs, + const Path& port_versions_path) { - for (auto&& super_directory : fs.get_directories_non_recursive(port_versions_path, VCPKG_LINE_INFO)) + auto maybe_super_directories = fs.try_get_directories_non_recursive(port_versions_path); + const auto super_directories = maybe_super_directories.get(); + if (!super_directories) + { + return std::move(maybe_super_directories.error()); + } + + for (auto&& super_directory : *super_directories) { - for (auto&& file : fs.get_regular_files_non_recursive(super_directory, VCPKG_LINE_INFO)) + auto maybe_files = fs.try_get_regular_files_non_recursive(super_directory); + const auto files = maybe_files.get(); + if (!files) + { + return std::move(maybe_files).error(); + } + + for (auto&& file : *files) { auto filename = file.filename(); if (!Strings::case_insensitive_ascii_ends_with(filename, ".json")) continue; if (!Strings::ends_with(filename, ".json")) { - Checks::msg_exit_with_message(VCPKG_LINE_INFO, msgJsonFileMissingExtension, msg::path = file); + return msg::format_error(msgJsonFileMissingExtension, msg::path = file); } auto port_name = filename.substr(0, filename.size() - 5); if (!Json::IdentifierDeserializer::is_ident(port_name)) { - Checks::msg_exit_maybe_upgrade(VCPKG_LINE_INFO, msgInvalidPortVersonName, msg::path = file); + return msg::format_error(msgInvalidPortVersonName, msg::path = file); } out.push_back(port_name.to_string()); } } + + return Unit{}; } static ExpectedL git_checkout_baseline(const VcpkgPaths& paths, StringView commit_sha) @@ -590,26 +682,27 @@ namespace // { RegistryImplementation // { BuiltinFilesRegistry::RegistryImplementation - std::unique_ptr BuiltinFilesRegistry::get_port_entry(StringView port_name) const + ExpectedL> BuiltinFilesRegistry::get_port_entry(StringView port_name) const { auto port_directory = m_builtin_ports_directory / port_name; if (m_fs.exists(port_directory, IgnoreErrors{})) { const auto& found_scf = get_scf(port_directory); - if (auto scfp = found_scf.get()) + if (auto scf = found_scf.get()) { - auto& scf = *scfp; if (scf->core_paragraph->name == port_name) { return std::make_unique( scf->core_paragraph->name, port_directory, scf->to_version()); } - msg::println_error(msgUnexpectedPortName, - msg::expected = scf->core_paragraph->name, - msg::actual = port_name, - msg::path = port_directory); - Checks::exit_fail(VCPKG_LINE_INFO); + + return msg::format_error(msgUnexpectedPortName, + msg::expected = scf->core_paragraph->name, + msg::actual = port_name, + msg::path = port_directory); } + + return found_scf.error(); } return nullptr; @@ -622,58 +715,61 @@ namespace const auto& maybe_scf = get_scf(port_path); if (auto pscf = maybe_scf.get()) { - return (*pscf)->to_version(); + return pscf->to_version(); } - return LocalizedString::from_raw(ParseControlErrorInfo::format_errors({&maybe_scf.error(), 1})); + + return maybe_scf.error(); } - void BuiltinFilesRegistry::append_all_port_names(std::vector& out) const + ExpectedL BuiltinFilesRegistry::append_all_port_names(std::vector& out) const { - std::error_code ec; - auto port_directories = m_fs.get_directories_non_recursive(m_builtin_ports_directory, VCPKG_LINE_INFO); - - for (auto&& port_directory : port_directories) + auto maybe_port_directories = m_fs.try_get_directories_non_recursive(m_builtin_ports_directory); + if (auto port_directories = maybe_port_directories.get()) { - auto filename = port_directory.filename(); - if (filename == ".DS_Store") continue; - out.push_back(filename.to_string()); + for (auto&& port_directory : *port_directories) + { + auto filename = port_directory.filename(); + if (filename == ".DS_Store") continue; + out.emplace_back(filename.data(), filename.size()); + } + + return Unit{}; } + + return std::move(maybe_port_directories).error(); } - bool BuiltinFilesRegistry::try_append_all_port_names_no_network(std::vector& port_names) const + ExpectedL BuiltinFilesRegistry::try_append_all_port_names_no_network( + std::vector& port_names) const { - append_all_port_names(port_names); - return true; + return append_all_port_names(port_names).map([](Unit) { return true; }); } // } BuiltinFilesRegistry::RegistryImplementation // { BuiltinGitRegistry::RegistryImplementation - std::unique_ptr BuiltinGitRegistry::get_port_entry(StringView port_name) const + ExpectedL> BuiltinGitRegistry::get_port_entry(StringView port_name) const { const auto& fs = m_paths.get_filesystem(); auto versions_path = m_paths.builtin_registry_versions / relative_path_to_versions(port_name); - if (fs.exists(versions_path, IgnoreErrors{})) + auto maybe_maybe_version_entries = + load_versions_file(fs, VersionDbType::Git, m_paths.builtin_registry_versions, port_name); + auto maybe_version_entries = maybe_maybe_version_entries.get(); + if (!maybe_version_entries) { - auto maybe_version_entries = - load_versions_file(fs, VersionDbType::Git, m_paths.builtin_registry_versions, port_name); - if (!maybe_version_entries) - { - Checks::msg_exit_maybe_upgrade(VCPKG_LINE_INFO, maybe_version_entries.error()); - } + return std::move(maybe_maybe_version_entries).error(); + } - auto version_entries = std::move(maybe_version_entries).value_or_exit(VCPKG_LINE_INFO); - auto res = std::make_unique(m_paths); - res->port_name = port_name.to_string(); - for (auto&& version_entry : version_entries) - { - res->port_versions.push_back(version_entry.version); - res->git_trees.push_back(version_entry.git_tree); - } - return res; + auto version_entries = maybe_version_entries->get(); + if (!version_entries) + { + return m_files_impl->get_port_entry(port_name); } - return m_files_impl->get_port_entry(port_name); + auto res = std::make_unique(m_paths); + res->port_name.assign(port_name.data(), port_name.size()); + res->port_versions_soa.assign(std::move(*version_entries)); + return res; } ExpectedL BuiltinGitRegistry::get_baseline_version(StringView port_name) const @@ -703,7 +799,7 @@ namespace return msg::format(msg::msgErrorMessage).append(msgPortNotInBaseline, msg::package_name = port_name); } - void BuiltinGitRegistry::append_all_port_names(std::vector& out) const + ExpectedL BuiltinGitRegistry::append_all_port_names(std::vector& out) const { const auto& fs = m_paths.get_filesystem(); @@ -712,13 +808,12 @@ namespace load_all_port_names_from_registry_versions(out, fs, m_paths.builtin_registry_versions); } - m_files_impl->append_all_port_names(out); + return m_files_impl->append_all_port_names(out); } - bool BuiltinGitRegistry::try_append_all_port_names_no_network(std::vector& port_names) const + ExpectedL BuiltinGitRegistry::try_append_all_port_names_no_network(std::vector& port_names) const { - append_all_port_names(port_names); - return true; + return append_all_port_names(port_names).map([](Unit) { return true; }); } // } BuiltinGitRegistry::RegistryImplementation @@ -760,131 +855,210 @@ namespace } } - std::unique_ptr FilesystemRegistry::get_port_entry(StringView port_name) const + ExpectedL> FilesystemRegistry::get_port_entry(StringView port_name) const { - auto maybe_version_entries = + auto maybe_maybe_version_entries = load_versions_file(m_fs, VersionDbType::Filesystem, m_path / registry_versions_dir_name, port_name, m_path); + auto maybe_version_entries = maybe_maybe_version_entries.get(); + if (!maybe_version_entries) + { + return std::move(maybe_maybe_version_entries).error(); + } - auto version_entries = std::move(maybe_version_entries).value_or_exit(VCPKG_LINE_INFO); + auto version_entries = maybe_version_entries->get(); + if (!version_entries) + { + return std::unique_ptr{}; + } auto res = std::make_unique(port_name.to_string()); - for (auto&& version_entry : version_entries) + for (auto&& version_entry : *version_entries) { res->port_versions.push_back(std::move(version_entry.version)); res->version_paths.push_back(std::move(version_entry.p)); } + return res; } - void FilesystemRegistry::append_all_port_names(std::vector& out) const + ExpectedL FilesystemRegistry::append_all_port_names(std::vector& out) const { - load_all_port_names_from_registry_versions(out, m_fs, m_path / registry_versions_dir_name); + return load_all_port_names_from_registry_versions(out, m_fs, m_path / registry_versions_dir_name); } - bool FilesystemRegistry::try_append_all_port_names_no_network(std::vector& port_names) const + ExpectedL FilesystemRegistry::try_append_all_port_names_no_network(std::vector& port_names) const { - append_all_port_names(port_names); - return true; + return append_all_port_names(port_names).map([](Unit) { return true; }); } // } FilesystemRegistry::RegistryImplementation // { GitRegistry::RegistryImplementation - std::unique_ptr GitRegistry::get_port_entry(StringView port_name) const + ExpectedL> GitRegistry::get_port_entry(StringView port_name) const { - return std::make_unique(*this, port_name); - } - - GitRegistryEntry::GitRegistryEntry(const GitRegistry& reg, StringView name) - : port_name(name.to_string()), parent(reg) - { - auto vtp = parent.get_stale_versions_tree_path(); - stale = vtp.stale; - fill_data_from_path(parent.m_paths.get_filesystem(), vtp.p); - } + auto maybe_stale_vtp = get_stale_versions_tree_path(); + auto stale_vtp = maybe_stale_vtp.get(); + if (!stale_vtp) + { + return std::move(maybe_stale_vtp).error(); + } - ExpectedL GitRegistry::get_baseline_version(StringView port_name) const - { - const auto& baseline = m_baseline.get([this]() -> Baseline { - // We delay baseline validation until here to give better error messages and suggestions - if (!is_git_commit_sha(m_baseline_identifier)) + { + // try to load using "stale" version database + auto maybe_maybe_version_entries = + load_versions_file(m_paths.get_filesystem(), VersionDbType::Git, stale_vtp->p, port_name); + auto maybe_version_entries = maybe_maybe_version_entries.get(); + if (!maybe_version_entries) { - auto e = get_lock_entry(); - e.ensure_up_to_date(m_paths); - Checks::msg_exit_maybe_upgrade(VCPKG_LINE_INFO, - msgGitRegistryMustHaveBaseline, - msg::package_name = m_repo, - msg::value = e.commit_id()); + return std::move(maybe_maybe_version_entries).error(); } - auto path_to_baseline = Path(registry_versions_dir_name.to_string()) / "baseline.json"; - auto maybe_contents = m_paths.git_show_from_remote_registry(m_baseline_identifier, path_to_baseline); - if (!maybe_contents) + auto version_entries = maybe_version_entries->get(); + if (version_entries) { - get_lock_entry().ensure_up_to_date(m_paths); - maybe_contents = m_paths.git_show_from_remote_registry(m_baseline_identifier, path_to_baseline); + return std::make_unique( + port_name, *this, stale_vtp->stale, std::move(*version_entries)); } - if (!maybe_contents) - { - msg::println(msgFetchingBaselineInfo, msg::package_name = m_repo); - auto maybe_err = m_paths.git_fetch(m_repo, m_baseline_identifier); - if (!maybe_err) - { - get_global_metrics_collector().track_define(DefineMetric::RegistriesErrorCouldNotFindBaseline); - - msg::println_error(msgCouldNotFindBaselineForRepo, - msg::commit_sha = m_baseline_identifier, - msg::package_name = m_repo); - - msg::println_error(msg::format(msgFailedToFetchError, - msg::error_msg = maybe_contents.error(), - msg::package_name = m_repo) - .append_raw('\n') - .append_raw(maybe_err.error())); + } - Checks::exit_fail(VCPKG_LINE_INFO); - } + if (!stale_vtp->stale) + { + // data is already live but we don't know of this port + return std::unique_ptr(); + } - maybe_contents = m_paths.git_show_from_remote_registry(m_baseline_identifier, path_to_baseline); - } + auto maybe_live_vdb = get_versions_tree_path(); + auto live_vcb = maybe_live_vdb.get(); + if (!live_vcb) + { + return std::move(maybe_live_vdb).error(); + } - if (!maybe_contents) + { + auto maybe_maybe_version_entries = + load_versions_file(m_paths.get_filesystem(), VersionDbType::Git, *live_vcb, port_name); + auto maybe_version_entries = maybe_maybe_version_entries.get(); + if (!maybe_version_entries) { - get_global_metrics_collector().track_define(DefineMetric::RegistriesErrorCouldNotFindBaseline); - Checks::msg_exit_with_message(VCPKG_LINE_INFO, - msg::format(msgCouldNotFindBaselineInCommit, - msg::commit_sha = m_baseline_identifier, - msg::package_name = m_repo) - .append_raw('\n') - .append_raw(maybe_contents.error())); + return std::move(maybe_maybe_version_entries).error(); } - auto contents = maybe_contents.get(); - auto res_baseline = parse_baseline_versions(*contents, "default", path_to_baseline); - if (auto opt_baseline = res_baseline.get()) + auto version_entries = maybe_version_entries->get(); + if (!version_entries) { - if (auto p = opt_baseline->get()) - { - return std::move(*p); - } - else - { - get_global_metrics_collector().track_define(DefineMetric::RegistriesErrorCouldNotFindBaseline); - Checks::msg_exit_maybe_upgrade(VCPKG_LINE_INFO, - msgBaselineMissingDefault, - msg::commit_sha = m_baseline_identifier, - msg::url = m_repo); - } + // data is already live but we don't know of this port + return std::unique_ptr(); } - else - { - msg::println_error(msg::format(msgErrorWhileFetchingBaseline, - msg::value = m_baseline_identifier, - msg::package_name = m_repo) - .append_raw('\n') - .append(LocalizedString::from_raw(res_baseline.error()))); - Checks::exit_fail(VCPKG_LINE_INFO); - } - }); + + return std::make_unique(port_name, *this, false, std::move(*version_entries)); + } + } + + GitRegistryEntry::GitRegistryEntry(StringView port_name, + const GitRegistry& parent, + bool stale, + std::vector&& version_entries) + : port_name(port_name.data(), port_name.size()) + , parent(parent) + , stale(stale) + , last_loaded(std::move(version_entries)) + { + } + + ExpectedL GitRegistry::get_baseline_version(StringView port_name) const + { + const auto& baseline = + m_baseline + .get([this, port_name]() -> ExpectedL { + // We delay baseline validation until here to give better error messages and suggestions + if (!is_git_commit_sha(m_baseline_identifier)) + { + auto& maybe_lock_entry = get_lock_entry(); + auto lock_entry = maybe_lock_entry.get(); + if (!lock_entry) + { + return maybe_lock_entry.error(); + } + + auto maybe_up_to_date = lock_entry->ensure_up_to_date(m_paths); + if (maybe_up_to_date) + { + return msg::format_error(msgGitRegistryMustHaveBaseline, + msg::url = m_repo, + msg::commit_sha = lock_entry->commit_id()); + } + + return std::move(maybe_up_to_date).error(); + } + + auto path_to_baseline = Path(registry_versions_dir_name.to_string()) / "baseline.json"; + auto maybe_contents = + m_paths.git_show_from_remote_registry(m_baseline_identifier, path_to_baseline); + if (!maybe_contents) + { + auto& maybe_lock_entry = get_lock_entry(); + auto lock_entry = maybe_lock_entry.get(); + if (!lock_entry) + { + return maybe_lock_entry.error(); + } + + auto maybe_up_to_date = lock_entry->ensure_up_to_date(m_paths); + if (!maybe_up_to_date) + { + return std::move(maybe_up_to_date).error(); + } + + maybe_contents = m_paths.git_show_from_remote_registry(m_baseline_identifier, path_to_baseline); + } + + if (!maybe_contents) + { + msg::println(msgFetchingBaselineInfo, msg::package_name = m_repo); + auto maybe_err = m_paths.git_fetch(m_repo, m_baseline_identifier); + if (!maybe_err) + { + get_global_metrics_collector().track_define( + DefineMetric::RegistriesErrorCouldNotFindBaseline); + return msg::format_error(msgFailedToFetchRepo, msg::url = m_repo) + .append_raw('\n') + .append(maybe_err.error()); + } + + maybe_contents = m_paths.git_show_from_remote_registry(m_baseline_identifier, path_to_baseline); + } + + if (!maybe_contents) + { + get_global_metrics_collector().track_define(DefineMetric::RegistriesErrorCouldNotFindBaseline); + return msg::format_error(msgCouldNotFindBaselineInCommit, + msg::url = m_repo, + msg::commit_sha = m_baseline_identifier, + msg::package_name = port_name) + .append_raw('\n') + .append_raw(maybe_contents.error()); + } + + auto contents = maybe_contents.get(); + auto res_baseline = parse_baseline_versions(*contents, "default", path_to_baseline); + if (auto opt_baseline = res_baseline.get()) + { + if (auto p = opt_baseline->get()) + { + return std::move(*p); + } + + get_global_metrics_collector().track_define(DefineMetric::RegistriesErrorCouldNotFindBaseline); + return msg::format_error( + msgBaselineMissingDefault, msg::commit_sha = m_baseline_identifier, msg::url = m_repo); + } + + return msg::format_error(msgErrorWhileFetchingBaseline, + msg::value = m_baseline_identifier, + msg::package_name = m_repo) + .append_raw('\n') + .append(res_baseline.error()); + }) + .value_or_exit(VCPKG_LINE_INFO); auto it = baseline.find(port_name); if (it != baseline.end()) @@ -895,13 +1069,18 @@ namespace return msg::format(msg::msgErrorMessage).append(msgPortNotInBaseline, msg::package_name = port_name); } - void GitRegistry::append_all_port_names(std::vector& out) const + ExpectedL GitRegistry::append_all_port_names(std::vector& out) const { - auto versions_path = get_stale_versions_tree_path(); - load_all_port_names_from_registry_versions(out, m_paths.get_filesystem(), versions_path.p); + auto maybe_versions_path = get_stale_versions_tree_path(); + if (auto versions_path = maybe_versions_path.get()) + { + return load_all_port_names_from_registry_versions(out, m_paths.get_filesystem(), versions_path->p); + } + + return std::move(maybe_versions_path).error(); } - bool GitRegistry::try_append_all_port_names_no_network(std::vector&) const + ExpectedL GitRegistry::try_append_all_port_names_no_network(std::vector&) const { // At this time we don't record enough information to know what the last fetch for a registry is, // so we can't even return what the most recent answer was. @@ -934,6 +1113,7 @@ namespace // { BuiltinRegistryEntry::RegistryEntry ExpectedL BuiltinGitRegistryEntry::get_version(const Version& version) const { + auto& port_versions = port_versions_soa.port_versions(); auto it = std::find(port_versions.begin(), port_versions.end(), version); if (it == port_versions.end()) { @@ -943,7 +1123,7 @@ namespace .append(msgChecksUpdateVcpkg); } - const auto& git_tree = git_trees[it - port_versions.begin()]; + const auto& git_tree = port_versions_soa.git_trees()[it - port_versions.begin()]; return m_paths.git_checkout_port(port_name, git_tree, m_paths.root / ".git") .map([&git_tree](Path&& p) -> PathAndLocation { return { @@ -971,31 +1151,74 @@ namespace // } FilesystemRegistryEntry::RegistryEntry // { GitRegistryEntry::RegistryEntry - View GitRegistryEntry::get_port_versions() const + ExpectedL GitRegistryEntry::ensure_not_stale() const { if (stale) { - fill_data_from_path(parent.m_paths.get_filesystem(), parent.get_versions_tree_path()); + auto maybe_live_vdb = parent.get_versions_tree_path(); + auto live_vdb = maybe_live_vdb.get(); + if (!live_vdb) + { + return std::move(maybe_live_vdb).error(); + } + + auto maybe_maybe_version_entries = + load_versions_file(parent.m_paths.get_filesystem(), VersionDbType::Git, *live_vdb, port_name); + auto maybe_version_entries = maybe_maybe_version_entries.get(); + if (!maybe_version_entries) + { + return std::move(maybe_maybe_version_entries).error(); + } + + auto version_entries = maybe_version_entries->get(); + if (!version_entries) + { + // Somehow the port existed in the stale version database but doesn't exist in the + // live one? + return msg::format_error(msgCouldNotFindVersionDatabaseFile, + msg::path = *live_vdb / relative_path_to_versions(port_name)); + } + + last_loaded.assign(std::move(*version_entries)); stale = false; } - return port_versions; + + return Unit{}; + } + + ExpectedL> GitRegistryEntry::get_port_versions() const + { + // Getting all versions that might exist must always be done with 'live' data + auto maybe_not_stale = ensure_not_stale(); + if (maybe_not_stale) + { + return View{last_loaded.port_versions()}; + } + + return std::move(maybe_not_stale).error(); } ExpectedL GitRegistryEntry::get_version(const Version& version) const { - auto it = std::find(port_versions.begin(), port_versions.end(), version); - if (it == port_versions.end() && stale) + auto it = std::find(last_loaded.port_versions().begin(), last_loaded.port_versions().end(), version); + if (it == last_loaded.port_versions().end() && stale) { - fill_data_from_path(parent.m_paths.get_filesystem(), parent.get_versions_tree_path()); - stale = false; - it = std::find(port_versions.begin(), port_versions.end(), version); + // didn't find the version, maybe a newer version database will have it + auto maybe_not_stale = ensure_not_stale(); + if (!maybe_not_stale) + { + return std::move(maybe_not_stale).error(); + } + + it = std::find(last_loaded.port_versions().begin(), last_loaded.port_versions().end(), version); } - if (it == port_versions.end()) + + if (it == last_loaded.port_versions().end()) { - return format_version_git_entry_missing(port_name, version, port_versions); + return format_version_git_entry_missing(port_name, version, last_loaded.port_versions()); } - const auto& git_tree = git_trees[it - port_versions.begin()]; + const auto& git_tree = last_loaded.git_trees()[it - last_loaded.port_versions().begin()]; return parent.m_paths.git_extract_tree_from_remote_registry(git_tree).map( [this, &git_tree](Path&& p) -> PathAndLocation { return { @@ -1005,18 +1228,6 @@ namespace }); } - void GitRegistryEntry::fill_data_from_path(const ReadOnlyFilesystem& fs, const Path& port_versions_path) const - { - auto maybe_version_entries = load_versions_file(fs, VersionDbType::Git, port_versions_path, port_name); - auto version_entries = std::move(maybe_version_entries).value_or_exit(VCPKG_LINE_INFO); - - for (auto&& version_entry : version_entries) - { - port_versions.push_back(version_entry.version); - git_trees.push_back(version_entry.git_tree); - } - } - // } GitRegistryEntry::RegistryEntry // } RegistryEntry @@ -1058,11 +1269,11 @@ namespace return Path(prefix) / port_name.to_string() + ".json"; } - ExpectedL> load_versions_file(const ReadOnlyFilesystem& fs, - VersionDbType type, - const Path& registry_versions, - StringView port_name, - const Path& registry_root) + ExpectedL>> load_versions_file(const ReadOnlyFilesystem& fs, + VersionDbType type, + const Path& registry_versions, + StringView port_name, + const Path& registry_root) { if (type == VersionDbType::Filesystem && registry_root.empty()) { @@ -1070,16 +1281,15 @@ namespace } auto versions_file_path = registry_versions / relative_path_to_versions(port_name); - - if (!fs.exists(versions_file_path, IgnoreErrors{})) - { - return msg::format_error(msgCouldNotFindVersionDatabaseFile, msg::path = versions_file_path); - } - std::error_code ec; auto contents = fs.read_contents(versions_file_path, ec); if (ec) { + if (ec == std::errc::no_such_file_or_directory) + { + return Optional>{}; + } + return format_filesystem_call_error(ec, "read_contents", {versions_file_path}); } @@ -1115,6 +1325,7 @@ namespace .append_raw(Strings::join("\n", r.errors())); } } + return db_entries; } @@ -1179,7 +1390,7 @@ namespace namespace vcpkg { - LockFile::Entry LockFile::get_or_fetch(const VcpkgPaths& paths, StringView repo, StringView reference) + ExpectedL LockFile::get_or_fetch(const VcpkgPaths& paths, StringView repo, StringView reference) { auto range = lockdata.equal_range(repo); auto it = std::find_if(range.first, range.second, [&reference](const LockDataType::value_type& repo2entry) { @@ -1189,15 +1400,21 @@ namespace vcpkg if (it == range.second) { msg::println(msgFetchingRegistryInfo, msg::url = repo, msg::value = reference); - auto x = paths.git_fetch_from_remote_registry(repo, reference); - it = lockdata.emplace(repo.to_string(), - EntryData{reference.to_string(), x.value_or_exit(VCPKG_LINE_INFO), false}); - modified = true; + auto maybe_commit = paths.git_fetch_from_remote_registry(repo, reference); + if (auto commit = maybe_commit.get()) + { + it = lockdata.emplace(repo.to_string(), EntryData{reference.to_string(), *commit, false}); + modified = true; + } + else + { + return std::move(maybe_commit).error(); + } } - return {this, it}; + return LockFile::Entry{this, it}; } - void LockFile::Entry::ensure_up_to_date(const VcpkgPaths& paths) const + ExpectedL LockFile::Entry::ensure_up_to_date(const VcpkgPaths& paths) const { if (data->second.stale) { @@ -1205,11 +1422,20 @@ namespace vcpkg StringView reference(data->second.reference); msg::println(msgFetchingRegistryInfo, msg::url = repo, msg::value = reference); - data->second.commit_id = - paths.git_fetch_from_remote_registry(repo, reference).value_or_exit(VCPKG_LINE_INFO); - data->second.stale = false; - lockfile->modified = true; + auto maybe_commit_id = paths.git_fetch_from_remote_registry(repo, reference); + if (const auto commit_id = maybe_commit_id.get()) + { + data->second.commit_id = *commit_id; + data->second.stale = false; + lockfile->modified = true; + } + else + { + return std::move(maybe_commit_id).error(); + } } + + return Unit{}; } Registry::Registry(std::vector&& patterns, std::unique_ptr&& impl) @@ -1322,33 +1548,49 @@ namespace namespace vcpkg { - std::vector RegistrySet::get_all_reachable_port_names() const + ExpectedL> RegistrySet::get_all_reachable_port_names() const { std::vector result; for (const auto& registry : registries()) { const auto start_at = result.size(); - registry.implementation().append_all_port_names(result); + auto this_append = registry.implementation().append_all_port_names(result); + if (!this_append) + { + return std::move(this_append).error(); + } + remove_unreachable_port_names_by_patterns(result, start_at, registry.patterns()); } if (auto registry = default_registry()) { - registry->append_all_port_names(result); + auto this_append = registry->append_all_port_names(result); + if (!this_append) + { + return std::move(this_append).error(); + } } Util::sort_unique_erase(result); return result; } - std::vector RegistrySet::get_all_known_reachable_port_names_no_network() const + ExpectedL> RegistrySet::get_all_known_reachable_port_names_no_network() const { std::vector result; for (const auto& registry : registries()) { const auto start_at = result.size(); const auto patterns = registry.patterns(); - if (registry.implementation().try_append_all_port_names_no_network(result)) + auto maybe_append = registry.implementation().try_append_all_port_names_no_network(result); + auto append = maybe_append.get(); + if (!append) + { + return std::move(maybe_append).error(); + } + + if (*append) { remove_unreachable_port_names_by_patterns(result, start_at, patterns); } @@ -1367,21 +1609,27 @@ namespace vcpkg if (auto registry = default_registry()) { - (void)registry->try_append_all_port_names_no_network(result); + auto maybe_append = registry->try_append_all_port_names_no_network(result); + if (!maybe_append) + { + return std::move(maybe_append).error(); + } } Util::sort_unique_erase(result); return result; } - ExpectedL>> get_builtin_versions(const VcpkgPaths& paths, - StringView port_name) + ExpectedL>>> get_builtin_versions( + const VcpkgPaths& paths, StringView port_name) { return load_versions_file( paths.get_filesystem(), VersionDbType::Git, paths.builtin_registry_versions, port_name) - .map([&](std::vector&& versions) { - return Util::fmap(versions, [](const VersionDbEntry& entry) -> auto { - return std::make_pair(SchemedVersion{entry.scheme, entry.version}, entry.git_tree); + .map([](const auto& maybe_versions) { + return maybe_versions.map([](const auto& versions) { + return Util::fmap(versions, [](const VersionDbEntry& entry) { + return std::pair{{entry.scheme, entry.version}, entry.git_tree}; + }); }); }); } diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 802a67dfc4..3cab387036 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -365,10 +365,7 @@ namespace vcpkg } else { - auto error_info = std::make_unique(); - error_info->name = origin.to_string(); - error_info->error = maybe_dependencies.error(); - return error_info; + return ParseControlErrorInfo::from_error(origin, std::move(maybe_dependencies).error()); } buf.clear(); @@ -382,10 +379,7 @@ namespace vcpkg } else { - auto error_info = std::make_unique(); - error_info->name = origin.to_string(); - error_info->error = maybe_default_features.error(); - return error_info; + return ParseControlErrorInfo::from_error(origin, std::move(maybe_default_features).error()); } auto supports_expr = parser.optional_field(SourceParagraphFields::SUPPORTS); @@ -430,10 +424,7 @@ namespace vcpkg } else { - auto error_info = std::make_unique(); - error_info->name = origin.to_string(); - error_info->error = maybe_dependencies.error(); - return error_info; + return ParseControlErrorInfo::from_error(origin, std::move(maybe_dependencies).error()); } auto err = parser.error_info(fpgh->name.empty() ? origin : fpgh->name);