From a7b45dfbdb7f9d60ed54bb199bdaa11774217534 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 24 Sep 2024 22:53:39 -0700 Subject: [PATCH] Improve diagnostics when an invalid triplet name is supplied. This fixes a regression introduced in https://github.com/microsoft/vcpkg-tool/pull/1474 where an error message is added but the corresponding text being parsed is not. This was reported as https://github.com/microsoft/vcpkg/issues/41143 --- azure-pipelines/end-to-end-tests-dir/cli.ps1 | 17 ++++++++++++++++- include/vcpkg/base/message-data.inc.h | 14 +++++++++----- include/vcpkg/base/parse.h | 4 ++++ locales/messages.json | 11 ++++++----- src/vcpkg/base/parse.cpp | 15 +++++++++++---- src/vcpkg/input.cpp | 19 ++++++++++++------- 6 files changed, 58 insertions(+), 22 deletions(-) diff --git a/azure-pipelines/end-to-end-tests-dir/cli.ps1 b/azure-pipelines/end-to-end-tests-dir/cli.ps1 index 4aeb479df7..1e7268b238 100644 --- a/azure-pipelines/end-to-end-tests-dir/cli.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/cli.ps1 @@ -50,7 +50,7 @@ $out = Run-VcpkgAndCaptureOutput -TestArgs @('install', 'this-is-super-not-a-#po Throw-IfNotFailed [string]$expected = @" -error: expected the end of input parsing a package spec; this usually means the indicated character is not allowed to be in a package spec. Port, triplet, and feature names are all lowercase alphanumeric+hypens. +error: expected the end of input parsing a package spec; this usually means the indicated character is not allowed to be in a package spec. Port, triplet, and feature names are all lowercase alphanumeric+hyphens. on expression: this-is-super-not-a-#port ^ @@ -76,6 +76,21 @@ if (-Not ($out.Replace("`r`n", "`n").EndsWith($expected))) throw 'Bad malformed --binarysource output; it was: ' + $out } +$out = Run-VcpkgAndCaptureOutput -TestArgs @('install', 'zlib', '--triplet', 'ARM-windows') +Throw-IfNotFailed + +$expected = @" +error: Invalid triplet name. Triplet names are all lowercase alphanumeric+hyphens. + on expression: ARM-windows + ^ +Built-in Triplets: +"@ + +if (-Not ($out.Replace("`r`n", "`n").StartsWith($expected))) +{ + throw 'Bad malformed triplet output. It was: ' + $out +} + $out = Run-VcpkgAndCaptureStdErr -TestArgs @('x-package-info', 'zlib#notaport', '--x-json', '--x-installed') Throw-IfNotFailed $expected = @" diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 0f6b1dcdea..effc1651ef 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -2207,25 +2207,25 @@ DECLARE_MESSAGE( (msg::package_name, msg::url), "", "\"{package_name}\" is not a valid feature name. " - "Feature names must be lowercase alphanumeric+hypens and not reserved (see {url} for more information).") + "Feature names must be lowercase alphanumeric+hyphens and not reserved (see {url} for more information).") DECLARE_MESSAGE(ParseIdentifierError, (msg::value, msg::url), "{value} is a lowercase identifier like 'boost'", "\"{value}\" is not a valid identifier. " - "Identifiers must be lowercase alphanumeric+hypens and not reserved (see {url} for more information).") + "Identifiers must be lowercase alphanumeric+hyphens and not reserved (see {url} for more information).") DECLARE_MESSAGE( ParsePackageNameNotEof, (msg::url), "", "expected the end of input parsing a package name; this usually means the indicated character is not allowed to be " - "in a port name. Port names are all lowercase alphanumeric+hypens and not reserved (see {url} for more " + "in a port name. Port names are all lowercase alphanumeric+hyphens and not reserved (see {url} for more " "information).") DECLARE_MESSAGE( ParsePackageNameError, (msg::package_name, msg::url), "", "\"{package_name}\" is not a valid package name. " - "Package names must be lowercase alphanumeric+hypens and not reserved (see {url} for more information).") + "Package names must be lowercase alphanumeric+hyphens and not reserved (see {url} for more information).") DECLARE_MESSAGE(ParsePackagePatternError, (msg::package_name, msg::url), "", @@ -2237,11 +2237,15 @@ DECLARE_MESSAGE( (), "", "expected the end of input parsing a package spec; this usually means the indicated character is not allowed to be " - "in a package spec. Port, triplet, and feature names are all lowercase alphanumeric+hypens.") + "in a package spec. Port, triplet, and feature names are all lowercase alphanumeric+hyphens.") DECLARE_MESSAGE(ParseQualifiedSpecifierNotEofSquareBracket, (msg::version_spec), "", "expected the end of input parsing a package spec; did you mean {version_spec} instead?") +DECLARE_MESSAGE(ParseTripletNotEof, + (), + "", + "Invalid triplet name. Triplet names are all lowercase alphanumeric+hyphens.") DECLARE_MESSAGE(PathMustBeAbsolute, (msg::path), "", diff --git a/include/vcpkg/base/parse.h b/include/vcpkg/base/parse.h index 37263813c4..5ddd329adc 100644 --- a/include/vcpkg/base/parse.h +++ b/include/vcpkg/base/parse.h @@ -21,6 +21,10 @@ namespace vcpkg int column; }; + void append_caret_line(LocalizedString& res, + const Unicode::Utf8Decoder& it, + const Unicode::Utf8Decoder& start_of_line); + struct ParseMessage { SourceLoc location = {}; diff --git a/locales/messages.json b/locales/messages.json index 6284e559c8..afa5ba7e41 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -1252,19 +1252,20 @@ "ParagraphExpectedColonAfterField": "expected ':' after field name", "ParagraphExpectedFieldName": "expected field name", "ParagraphUnexpectedEndOfLine": "unexpected end of line, to span a blank line use \" .\"", - "ParseFeatureNameError": "\"{package_name}\" is not a valid feature name. Feature names must be lowercase alphanumeric+hypens and not reserved (see {url} for more information).", + "ParseFeatureNameError": "\"{package_name}\" is not a valid feature name. Feature names must be lowercase alphanumeric+hyphens and not reserved (see {url} for more information).", "_ParseFeatureNameError.comment": "An example of {package_name} is zlib. An example of {url} is https://github.com/microsoft/vcpkg.", - "ParseIdentifierError": "\"{value}\" is not a valid identifier. Identifiers must be lowercase alphanumeric+hypens and not reserved (see {url} for more information).", + "ParseIdentifierError": "\"{value}\" is not a valid identifier. Identifiers must be lowercase alphanumeric+hyphens and not reserved (see {url} for more information).", "_ParseIdentifierError.comment": "{value} is a lowercase identifier like 'boost' An example of {url} is https://github.com/microsoft/vcpkg.", - "ParsePackageNameError": "\"{package_name}\" is not a valid package name. Package names must be lowercase alphanumeric+hypens and not reserved (see {url} for more information).", + "ParsePackageNameError": "\"{package_name}\" is not a valid package name. Package names must be lowercase alphanumeric+hyphens and not reserved (see {url} for more information).", "_ParsePackageNameError.comment": "An example of {package_name} is zlib. An example of {url} is https://github.com/microsoft/vcpkg.", - "ParsePackageNameNotEof": "expected the end of input parsing a package name; this usually means the indicated character is not allowed to be in a port name. Port names are all lowercase alphanumeric+hypens and not reserved (see {url} for more information).", + "ParsePackageNameNotEof": "expected the end of input parsing a package name; this usually means the indicated character is not allowed to be in a port name. Port names are all lowercase alphanumeric+hyphens and not reserved (see {url} for more information).", "_ParsePackageNameNotEof.comment": "An example of {url} is https://github.com/microsoft/vcpkg.", "ParsePackagePatternError": "\"{package_name}\" is not a valid package pattern. Package patterns must use only one wildcard character (*) and it must be the last character in the pattern (see {url} for more information).", "_ParsePackagePatternError.comment": "An example of {package_name} is zlib. An example of {url} is https://github.com/microsoft/vcpkg.", - "ParseQualifiedSpecifierNotEof": "expected the end of input parsing a package spec; this usually means the indicated character is not allowed to be in a package spec. Port, triplet, and feature names are all lowercase alphanumeric+hypens.", + "ParseQualifiedSpecifierNotEof": "expected the end of input parsing a package spec; this usually means the indicated character is not allowed to be in a package spec. Port, triplet, and feature names are all lowercase alphanumeric+hyphens.", "ParseQualifiedSpecifierNotEofSquareBracket": "expected the end of input parsing a package spec; did you mean {version_spec} instead?", "_ParseQualifiedSpecifierNotEofSquareBracket.comment": "An example of {version_spec} is zlib:x64-windows@1.0.0.", + "ParseTripletNotEof": "Invalid triplet name. Triplet names are all lowercase alphanumeric+hyphens.", "PathMustBeAbsolute": "Value of environment variable X_VCPKG_REGISTRIES_CACHE is not absolute: {path}", "_PathMustBeAbsolute.comment": "An example of {path} is /foo/bar.", "PerformingPostBuildValidation": "Performing post-build validation", diff --git a/src/vcpkg/base/parse.cpp b/src/vcpkg/base/parse.cpp index a4d997ba4b..ddf90931cd 100644 --- a/src/vcpkg/base/parse.cpp +++ b/src/vcpkg/base/parse.cpp @@ -22,11 +22,13 @@ namespace vcpkg } } - static void append_caret_line(LocalizedString& res, const SourceLoc& loc) + void append_caret_line(LocalizedString& res, + const Unicode::Utf8Decoder& cursor, + const Unicode::Utf8Decoder& start_of_line) { - auto line_end = Util::find_if(loc.it, ParserBase::is_lineend); + auto line_end = Util::find_if(cursor, ParserBase::is_lineend); StringView line = StringView{ - loc.start_of_line.pointer_to_current(), + start_of_line.pointer_to_current(), line_end.pointer_to_current(), }; @@ -42,7 +44,7 @@ namespace vcpkg std::string caret_string; caret_string.append(line_prefix_space, ' '); // note *it is excluded because it is where the ^ goes - for (auto it = loc.start_of_line; it != loc.it; ++it) + for (auto it = start_of_line; it != cursor; ++it) { if (*it == '\t') caret_string.push_back('\t'); @@ -57,6 +59,11 @@ namespace vcpkg res.append_indent().append_raw(caret_string); } + static void append_caret_line(LocalizedString& res, const SourceLoc& loc) + { + append_caret_line(res, loc.it, loc.start_of_line); + } + LocalizedString ParseMessage::format(StringView origin, MessageKind kind) const { LocalizedString res; diff --git a/src/vcpkg/input.cpp b/src/vcpkg/input.cpp index a8e85255c2..7345223884 100644 --- a/src/vcpkg/input.cpp +++ b/src/vcpkg/input.cpp @@ -24,17 +24,22 @@ namespace vcpkg [[nodiscard]] ExpectedL check_triplet(StringView name, const TripletDatabase& database) { - // Intentionally show the lowercased string - auto as_lower = Strings::ascii_to_lowercase(name); - - if (std::find_if_not(name.begin(), name.end(), ParserBase::is_package_name_char) != name.end()) + Unicode::Utf8Decoder start_of_line{name}; + for (auto cursor = start_of_line; !cursor.is_eof(); ++cursor) { - return msg::format_error(msgParseQualifiedSpecifierNotEof); + if (!ParserBase::is_package_name_char(*cursor)) + { + auto result = msg::format_error(msgParseTripletNotEof).append_raw('\n'); + append_caret_line(result, cursor, start_of_line); + result.append_raw('\n'); + append_help_topic_valid_triplet(result, database); + return result; + } } - if (!database.is_valid_triplet_canonical_name(as_lower)) + if (!database.is_valid_triplet_canonical_name(name)) { - LocalizedString result = msg::format_error(msgInvalidTriplet, msg::triplet = as_lower); + LocalizedString result = msg::format_error(msgInvalidTriplet, msg::triplet = name); result.append_raw('\n'); append_help_topic_valid_triplet(result, database); return result;