From 68122ce93325edf6be6760e3c6a6eebb641c6711 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 28 Sep 2023 00:04:57 -0700 Subject: [PATCH 1/5] Fix crash while parsing malformed manifest files. Alternative to https://github.com/microsoft/vcpkg-tool/pull/1211 Fixes microsoft/vcpkg#33973 I'm not entirely happy with this because it emits extra 'mismatched type' warnings like $.dependencies[0].features[0]: mismatched type: expected a feature in a dependency . --- .../dependency-core-feature-name.json | 8 ++++ .../dependency-default-feature-name.json | 8 ++++ .../dependency-empty-feature-name.json | 8 ++++ .../dependency-empty-name.json | 3 ++ .../dependency-empty-object-name.json | 7 ++++ .../end-to-end-tests-dir/format-manifest.ps1 | 21 ++++++++++ include/vcpkg/base/message-data.inc.h | 14 +++++++ include/vcpkg/sourceparagraph.h | 8 ++-- locales/messages.json | 6 +++ src/vcpkg-test/plan.cpp | 2 +- src/vcpkg/commands.add.cpp | 2 +- src/vcpkg/commands.install.cpp | 1 + src/vcpkg/sourceparagraph.cpp | 39 ++++++++++++++----- 13 files changed, 112 insertions(+), 15 deletions(-) create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-core-feature-name.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-default-feature-name.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-feature-name.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-name.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-object-name.json diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-core-feature-name.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-core-feature-name.json new file mode 100644 index 0000000000..2e62e0c4ed --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-core-feature-name.json @@ -0,0 +1,8 @@ +{ + "dependencies": [ + { + "name": "icu", + "features": ["core"] + } + ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-default-feature-name.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-default-feature-name.json new file mode 100644 index 0000000000..9cd5f8a3f9 --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-default-feature-name.json @@ -0,0 +1,8 @@ +{ + "dependencies": [ + { + "name": "icu", + "features": ["default"] + } + ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-feature-name.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-feature-name.json new file mode 100644 index 0000000000..95601a0394 --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-feature-name.json @@ -0,0 +1,8 @@ +{ + "dependencies": [ + { + "name": "icu", + "features": [""] + } + ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-name.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-name.json new file mode 100644 index 0000000000..1d3b0858d5 --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-name.json @@ -0,0 +1,3 @@ +{ + "dependencies": [""] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-object-name.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-object-name.json new file mode 100644 index 0000000000..b97ebc46e8 --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-object-name.json @@ -0,0 +1,7 @@ +{ + "dependencies": [ + { + "name": "" + } + ] +} diff --git a/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 b/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 index 76d59e0540..35b5aa4db9 100644 --- a/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 @@ -1,5 +1,6 @@ . "$PSScriptRoot/../end-to-end-tests-prelude.ps1" +Write-Trace "test successfully parsing good inputs" $formatManifestAssets = (Get-Item "$PSScriptRoot/../e2e-assets/format-manifest").FullName $testProjects = Get-ChildItem "$formatManifestAssets/*.json" -File $testProjects | % { @@ -18,6 +19,26 @@ $testProjects | % { } } +Write-Trace "test not crashing parsing malformed inputs" +$formatManifestEvilAssets = (Get-Item "$PSScriptRoot/../e2e-assets/format-manifest-bad").FullName +$testEvilProjects = Get-ChildItem "$formatManifestEvilAssets/*.json" -File +$testEvilProjects | % { + $asItem = Get-Item $_ + $full = $asItem.FullName + Write-Trace "test that format-manifest on $full produces an error" + $output = Run-VcpkgAndCaptureOutput format-manifest $full + Throw-IfNotFailed + if ($output -match 'vcpkg has crashed') { + throw "vcpkg crashed parsing $full" + } + + $fullEscaped = [System.Text.RegularExpressions.Regex]::Escape($full) + if ($output -notmatch 'error: while loading ' + $fullEscaped ` + -or $output -notmatch 'error: Failed to parse manifest file: ' + $fullEscaped) { + throw "error not detected in $full" + } +} + Write-Trace "test re-serializing every manifest" $manifestDir = "$TestingRoot/manifest-dir" Copy-Item -Path "$env:VCPKG_ROOT/ports" -Destination $manifestDir -recurse -Force -Filter vcpkg.json diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 168d21f128..1da3723176 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -5,6 +5,7 @@ DECLARE_MESSAGE(ABuiltinRegistry, (), "", "a builtin registry") DECLARE_MESSAGE(AConfigurationObject, (), "", "a configuration object") DECLARE_MESSAGE(ADependency, (), "", "a dependency") DECLARE_MESSAGE(ADependencyFeature, (), "", "a feature in a dependency") +DECLARE_MESSAGE(ADependencyFeatureName, (), "", "the name of a feature of a dependency") DECLARE_MESSAGE(ADemandObject, (), "'demands' are a concept in the schema of a JSON file the user can edit", @@ -994,6 +995,19 @@ DECLARE_MESSAGE(DeleteVcpkgConfigFromManifest, (msg::path), "", "-- Or remove \"vcpkg-configuration\" from the manifest file {path}.") +DECLARE_MESSAGE(DependencyCoreFeature, + (), + "The word 'core' is an on-disk name that must not be localized. The 'default-features' part is JSON " + "syntax that must be copied verbatim into the user's file.", + "The feature 'core' cannot be in a dependency's feature list. To turn off default features, add " + "\"default-features\": false instead.") +DECLARE_MESSAGE(DependencyDefaultFeature, + (), + "The word 'default' is an on-disk name that must not be localized. The 'default-features' part is JSON " + "syntax that must be copied verbatim into the user's file.", + "The feature 'default' cannot be in a dependency's feature list. To turn on default features, add " + "\"default-features\": true instead.") +DECLARE_MESSAGE(DependencyEmptyFeature, (), "", "the name of a dependent feature can't be empty.") DECLARE_MESSAGE(DependencyGraphCalculation, (), "", "Dependency graph submission enabled.") DECLARE_MESSAGE(DependencyGraphFailure, (), "", "Dependency graph submission failed.") DECLARE_MESSAGE(DependencyGraphSuccess, (), "", "Dependency graph submission successful.") diff --git a/include/vcpkg/sourceparagraph.h b/include/vcpkg/sourceparagraph.h index fd2d0c3eae..fbbd9bf43f 100644 --- a/include/vcpkg/sourceparagraph.h +++ b/include/vcpkg/sourceparagraph.h @@ -41,12 +41,12 @@ namespace vcpkg { std::string name; PlatformExpression::Expr platform; - DependencyRequestedFeature(std::string name) - : DependencyRequestedFeature(std::move(name), PlatformExpression::Expr::Empty()) + DependencyRequestedFeature(const std::string& name) + : DependencyRequestedFeature(name, PlatformExpression::Expr::Empty()) { } - DependencyRequestedFeature(std::string name, PlatformExpression::Expr platform) - : name(std::move(name)), platform(std::move(platform)) + DependencyRequestedFeature(const std::string& name, PlatformExpression::Expr&& platform) + : name(name), platform(std::move(platform)) { Checks::check_exit(VCPKG_LINE_INFO, !this->name.empty() && this->name != "core" && this->name != "default"); } diff --git a/locales/messages.json b/locales/messages.json index a5d60e5f45..77dd57c32f 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -9,6 +9,7 @@ "_ADemandObject.comment": "'demands' are a concept in the schema of a JSON file the user can edit", "ADependency": "a dependency", "ADependencyFeature": "a feature in a dependency", + "ADependencyFeatureName": "the name of a feature of a dependency", "ADictionaryOfContacts": "a dictionary of contacts", "AFeature": "a feature", "AFilesystemRegistry": "a filesystem registry", @@ -581,6 +582,11 @@ "_DefaultTripletChanged.comment": "The parts naming --triplet are command line switches that should be unlocalized. The space after the last 'triplet' and the period is intended to avoid the period looking like it's part of the command line switch An example of {triplet} is x64-windows.", "DeleteVcpkgConfigFromManifest": "-- Or remove \"vcpkg-configuration\" from the manifest file {path}.", "_DeleteVcpkgConfigFromManifest.comment": "An example of {path} is /foo/bar.", + "DependencyCoreFeature": "The feature 'core' cannot be in a dependency's feature list. To turn off default features, add \"default-features\": false instead.", + "_DependencyCoreFeature.comment": "The word 'core' is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", + "DependencyDefaultFeature": "The feature 'default' cannot be in a dependency's feature list. To turn on default features, add \"default-features\": true instead.", + "_DependencyDefaultFeature.comment": "The word 'default' is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", + "DependencyEmptyFeature": "the name of a dependent feature can't be empty.", "DependencyGraphCalculation": "Dependency graph submission enabled.", "DependencyGraphFailure": "Dependency graph submission failed.", "DependencyGraphSuccess": "Dependency graph submission successful.", diff --git a/src/vcpkg-test/plan.cpp b/src/vcpkg-test/plan.cpp index 2666931345..f5e9759d1f 100644 --- a/src/vcpkg-test/plan.cpp +++ b/src/vcpkg-test/plan.cpp @@ -459,7 +459,7 @@ TEST_CASE ("install platform dependent default features", "[plan]") using MBO = PlatformExpression::MultipleBinaryOperators; auto linux_expr = PlatformExpression::parse_platform_expression("linux", MBO::Deny).value_or_exit(VCPKG_LINE_INFO); spec_map.map["a"].source_control_file->core_paragraph->default_features = { - DependencyRequestedFeature{"1", linux_expr}}; + DependencyRequestedFeature{"1", std::move(linux_expr)}}; MapPortFileProvider map_port{spec_map.map}; MockCMakeVarProvider var_provider; diff --git a/src/vcpkg/commands.add.cpp b/src/vcpkg/commands.add.cpp index c3244a2d1e..e860bba668 100644 --- a/src/vcpkg/commands.add.cpp +++ b/src/vcpkg/commands.add.cpp @@ -110,7 +110,7 @@ namespace vcpkg return dep.name == spec.name && !dep.host && structurally_equal(spec.platform.value_or(PlatformExpression::Expr()), dep.platform); }); - const auto features = Util::fmap(spec.features.value_or({}), [](auto& feature) { + const auto features = Util::fmap(spec.features.value_or({}), [](const std::string& feature) { return DependencyRequestedFeature{feature, PlatformExpression::Expr::Empty()}; }); if (dep == manifest_scf.core_paragraph->dependencies.end()) diff --git a/src/vcpkg/commands.install.cpp b/src/vcpkg/commands.install.cpp index 6c333d2c1f..62f213a52a 100644 --- a/src/vcpkg/commands.install.cpp +++ b/src/vcpkg/commands.install.cpp @@ -1105,6 +1105,7 @@ namespace vcpkg if (!maybe_manifest_scf) { print_error_message(maybe_manifest_scf.error()); + msg::println(); msg::println(msgExtendedDocumentationAtUrl, msg::url = docs::manifests_url); Checks::exit_fail(VCPKG_LINE_INFO); } diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 3cab387036..655dd1e95c 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -81,10 +81,7 @@ namespace vcpkg bool operator==(const DependencyRequestedFeature& lhs, const DependencyRequestedFeature& rhs) { - if (lhs.name != rhs.name) return false; - if (!structurally_equal(lhs.platform, rhs.platform)) return false; - - return true; + return lhs.name == rhs.name && structurally_equal(lhs.platform, rhs.platform); } bool operator!=(const DependencyRequestedFeature& lhs, const DependencyRequestedFeature& rhs) @@ -374,8 +371,8 @@ namespace vcpkg auto maybe_default_features = parse_default_features_list(buf, origin, textrowcol); if (const auto default_features = maybe_default_features.get()) { - spgh->default_features = - Util::fmap(*default_features, [](const auto& name) { return DependencyRequestedFeature{name}; }); + spgh->default_features = Util::fmap( + *default_features, [](const std::string& feature) { return DependencyRequestedFeature{feature}; }); } else { @@ -494,6 +491,30 @@ namespace vcpkg }; const PlatformExprDeserializer PlatformExprDeserializer::instance; + struct DependencyFeatureNameDeserializer : Json::IDeserializer + { + virtual LocalizedString type_name() const override { return msg::format(msgADependencyFeatureName); } + virtual Optional visit_string(Json::Reader& r, StringView sv) const override + { + if (sv == "core") + { + r.add_generic_error(type_name(), msg::format(msgDependencyCoreFeature)); + return nullopt; + } + + if (sv == "default") + { + r.add_generic_error(type_name(), msg::format(msgDependencyDefaultFeature)); + return nullopt; + } + + return Json::IdentifierDeserializer::instance.visit_string(r, sv); + } + static const DependencyFeatureNameDeserializer instance; + }; + + const DependencyFeatureNameDeserializer DependencyFeatureNameDeserializer::instance; + struct DependencyFeatureDeserializer : Json::IDeserializer { LocalizedString type_name() const override { return msg::format(msgADependencyFeature); } @@ -512,15 +533,15 @@ namespace vcpkg Optional visit_string(Json::Reader& r, StringView sv) const override { - return Json::IdentifierDeserializer::instance.visit_string(r, sv).map( - [](std::string&& name) { return std::move(name); }); + return DependencyFeatureNameDeserializer::instance.visit_string(r, sv).map( + [](std::string&& name) -> DependencyRequestedFeature { return std::move(name); }); } Optional visit_object(Json::Reader& r, const Json::Object& obj) const override { std::string name; PlatformExpression::Expr platform; - r.required_object_field(type_name(), obj, NAME, name, Json::IdentifierDeserializer::instance); + r.required_object_field(type_name(), obj, NAME, name, DependencyFeatureNameDeserializer::instance); r.optional_object_field(obj, PLATFORM, platform, PlatformExprDeserializer::instance); if (name.empty()) return nullopt; return DependencyRequestedFeature{std::move(name), std::move(platform)}; From b04a5b2146171a766ad0c41986874da22c04bfe9 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 28 Sep 2023 17:19:13 -0700 Subject: [PATCH 2/5] Remove semantic constraints on the deserialized type and add specific errors. --- .../default-feature-core-object.json | 3 + .../default-feature-core.json | 3 + .../default-feature-default-object.json | 3 + .../default-feature-default.json | 3 + .../default-feature-empty-object.json | 3 + .../default-feature-empty.json | 3 + .../dependency-core-feature-name.json | 8 -- .../dependency-default-feature-name.json | 8 -- .../dependency-empty-feature-name.json | 8 -- .../dependency-empty-name.json | 3 - .../dependency-empty-object-name.json | 7 -- .../dependency-feature-name-core-object.json | 12 ++ .../dependency-feature-name-core.json | 8 ++ ...ependency-feature-name-default-object.json | 8 ++ .../dependency-feature-name-default.json | 8 ++ .../dependency-feature-name-empty-object.json | 8 ++ .../dependency-feature-name-empty.json | 8 ++ .../dependency-name-empty-object.json | 7 ++ .../dependency-name-empty.json | 3 + .../end-to-end-tests-dir/format-manifest.ps1 | 4 + include/vcpkg/base/message-data.inc.h | 17 ++- include/vcpkg/base/messages.h | 29 +++-- include/vcpkg/sourceparagraph.h | 1 - locales/messages.json | 14 ++- src/vcpkg/base/messages.cpp | 23 +++- src/vcpkg/commands.add.cpp | 1 + src/vcpkg/sourceparagraph.cpp | 105 ++++++++++++++++-- 27 files changed, 245 insertions(+), 63 deletions(-) create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core-object.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default-object.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty-object.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-core-feature-name.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-default-feature-name.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-feature-name.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-name.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-object-name.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core-object.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default-object.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty-object.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty-object.json create mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty.json diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core-object.json new file mode 100644 index 0000000000..c03140f6d1 --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core-object.json @@ -0,0 +1,3 @@ +{ + "default-features": [ { "name": "core" } ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core.json new file mode 100644 index 0000000000..f282a980da --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core.json @@ -0,0 +1,3 @@ +{ + "default-features": ["core"] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default-object.json new file mode 100644 index 0000000000..2ab3418fb9 --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default-object.json @@ -0,0 +1,3 @@ +{ + "default-features": [ { "name": "default" } ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default.json new file mode 100644 index 0000000000..dff94b4653 --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default.json @@ -0,0 +1,3 @@ +{ + "default-features": [ "default" ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty-object.json new file mode 100644 index 0000000000..1be2afc05a --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty-object.json @@ -0,0 +1,3 @@ +{ + "default-features": [ { "name": "" } ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty.json new file mode 100644 index 0000000000..039729c4e3 --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty.json @@ -0,0 +1,3 @@ +{ + "default-features": [ "" ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-core-feature-name.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-core-feature-name.json deleted file mode 100644 index 2e62e0c4ed..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-core-feature-name.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "dependencies": [ - { - "name": "icu", - "features": ["core"] - } - ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-default-feature-name.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-default-feature-name.json deleted file mode 100644 index 9cd5f8a3f9..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-default-feature-name.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "dependencies": [ - { - "name": "icu", - "features": ["default"] - } - ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-feature-name.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-feature-name.json deleted file mode 100644 index 95601a0394..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-feature-name.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "dependencies": [ - { - "name": "icu", - "features": [""] - } - ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-name.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-name.json deleted file mode 100644 index 1d3b0858d5..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-name.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "dependencies": [""] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-object-name.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-object-name.json deleted file mode 100644 index b97ebc46e8..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-empty-object-name.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": [ - { - "name": "" - } - ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core-object.json new file mode 100644 index 0000000000..1053f4142d --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core-object.json @@ -0,0 +1,12 @@ +{ + "dependencies": [ + { + "name": "icu", + "features": [ + { + "name": "core" + } + ] + } + ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core.json new file mode 100644 index 0000000000..4bcfa72295 --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core.json @@ -0,0 +1,8 @@ +{ + "dependencies": [ + { + "name": "icu", + "features": [ "core" ] + } + ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default-object.json new file mode 100644 index 0000000000..4bc6ef701e --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default-object.json @@ -0,0 +1,8 @@ +{ + "dependencies": [ + { + "name": "icu", + "features": [ { "name": "default" } ] + } + ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default.json new file mode 100644 index 0000000000..2b11a8e76a --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default.json @@ -0,0 +1,8 @@ +{ + "dependencies": [ + { + "name": "icu", + "features": [ "default" ] + } + ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty-object.json new file mode 100644 index 0000000000..2df194319e --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty-object.json @@ -0,0 +1,8 @@ +{ + "dependencies": [ + { + "name": "icu", + "features": [ { "name": "" } ] + } + ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty.json new file mode 100644 index 0000000000..633075ddd0 --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty.json @@ -0,0 +1,8 @@ +{ + "dependencies": [ + { + "name": "icu", + "features": [ "" ] + } + ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty-object.json new file mode 100644 index 0000000000..ad60fea9be --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty-object.json @@ -0,0 +1,7 @@ +{ + "dependencies": [ + { + "name": "" + } + ] +} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty.json new file mode 100644 index 0000000000..c55282c391 --- /dev/null +++ b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty.json @@ -0,0 +1,3 @@ +{ + "dependencies": [ "" ] +} diff --git a/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 b/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 index 35b5aa4db9..67e6d71c1c 100644 --- a/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 @@ -37,6 +37,10 @@ $testEvilProjects | % { -or $output -notmatch 'error: Failed to parse manifest file: ' + $fullEscaped) { throw "error not detected in $full" } + + if ($output -match 'mismatched type:') { + throw "duplicate mismatched type error" + } } Write-Trace "test re-serializing every manifest" diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 1da3723176..61c9b9463e 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -1,5 +1,6 @@ DECLARE_MESSAGE(ABaseline, (), "", "a baseline") DECLARE_MESSAGE(ABaselineObject, (), "", "a baseline object") +DECLARE_MESSAGE(ADefaultFeature, (), "", "a default feature") DECLARE_MESSAGE(ABoolean, (), "", "a boolean") DECLARE_MESSAGE(ABuiltinRegistry, (), "", "a builtin registry") DECLARE_MESSAGE(AConfigurationObject, (), "", "a configuration object") @@ -124,6 +125,7 @@ DECLARE_MESSAGE(AmbiguousConfigDeleteConfigFile, "configuration file {path}") DECLARE_MESSAGE(AnArtifactsGitRegistryUrl, (), "", "an artifacts git registry URL") DECLARE_MESSAGE(AnArtifactsRegistry, (), "", "an artifacts registry") +DECLARE_MESSAGE(AnArrayOfDefaultFeatures, (), "", "an array of default features") DECLARE_MESSAGE(AnArrayOfDependencies, (), "", "an array of dependencies") DECLARE_MESSAGE(AnArrayOfDependencyOverrides, (), "", "an array of dependency overrides") DECLARE_MESSAGE(AnArrayOfFeatures, (), "", "an array of features") @@ -981,6 +983,16 @@ DECLARE_MESSAGE(DefaultBinaryCacheRequiresDirectory, (msg::path), "", "Environment variable VCPKG_DEFAULT_BINARY_CACHE must be a directory (was: {path})") +DECLARE_MESSAGE(DefaultFeatureCore, + (), + "The word 'core' is an on-disk name that must not be localized.", + "the feature 'core' turns off default features and thus can't be in the default features list") +DECLARE_MESSAGE( + DefaultFeatureDefault, + (), + "The word 'default' is an on-disk name that must not be localized.", + "the feature 'default' refers to the set of default features and thus can't be in the default features list") +DECLARE_MESSAGE(DefaultFeatureIdentifier, (), "", "the names of default features must be identifiers") DECLARE_MESSAGE(DefaultFlag, (msg::option), "", "Defaulting to --{option} being on.") DECLARE_MESSAGE(DefaultRegistryIsArtifact, (), "", "The default registry cannot be an artifact registry.") DECLARE_MESSAGE( @@ -995,19 +1007,18 @@ DECLARE_MESSAGE(DeleteVcpkgConfigFromManifest, (msg::path), "", "-- Or remove \"vcpkg-configuration\" from the manifest file {path}.") -DECLARE_MESSAGE(DependencyCoreFeature, +DECLARE_MESSAGE(DependencyFeatureCore, (), "The word 'core' is an on-disk name that must not be localized. The 'default-features' part is JSON " "syntax that must be copied verbatim into the user's file.", "The feature 'core' cannot be in a dependency's feature list. To turn off default features, add " "\"default-features\": false instead.") -DECLARE_MESSAGE(DependencyDefaultFeature, +DECLARE_MESSAGE(DependencyFeatureDefault, (), "The word 'default' is an on-disk name that must not be localized. The 'default-features' part is JSON " "syntax that must be copied verbatim into the user's file.", "The feature 'default' cannot be in a dependency's feature list. To turn on default features, add " "\"default-features\": true instead.") -DECLARE_MESSAGE(DependencyEmptyFeature, (), "", "the name of a dependent feature can't be empty.") DECLARE_MESSAGE(DependencyGraphCalculation, (), "", "Dependency graph submission enabled.") DECLARE_MESSAGE(DependencyGraphFailure, (), "", "Dependency graph submission failed.") DECLARE_MESSAGE(DependencyGraphSuccess, (), "", "Dependency graph submission successful.") diff --git a/include/vcpkg/base/messages.h b/include/vcpkg/base/messages.h index 5260b09dbc..980df1b6d7 100644 --- a/include/vcpkg/base/messages.h +++ b/include/vcpkg/base/messages.h @@ -84,27 +84,42 @@ namespace vcpkg static LocalizedString from_raw(std::basic_string&& s) noexcept; static LocalizedString from_raw(StringView s); - LocalizedString& append_raw(char c); - LocalizedString& append_raw(StringView s); + LocalizedString& append_raw(char c) &; + LocalizedString&& append_raw(char c) &&; + LocalizedString& append_raw(StringView s) &; + LocalizedString&& append_raw(StringView s) &&; template().to_string(std::declval()))> - LocalizedString& append_raw(const T& s) + LocalizedString& append_raw(const T& s) & { s.to_string(m_data); return *this; } - LocalizedString& append(const LocalizedString& s); + template().to_string(std::declval()))> + LocalizedString&& append_raw(const T& s) && + { + return std::move(append_raw(s)); + } + LocalizedString& append(const LocalizedString& s) &; + LocalizedString&& append(const LocalizedString& s) &&; template - LocalizedString& append(VCPKG_DECL_MSG_ARGS) + LocalizedString& append(VCPKG_DECL_MSG_ARGS) & { msg::format_to(*this, VCPKG_EXPAND_MSG_ARGS); return *this; } - LocalizedString& append_indent(size_t indent = 1); + template + LocalizedString&& append(VCPKG_DECL_MSG_ARGS) && + { + return std::move(append(VCPKG_EXPAND_MSG_ARGS)); + } + LocalizedString& append_indent(size_t indent = 1) &; + LocalizedString&& append_indent(size_t indent = 1) &&; // 0 items - Does nothing // 1 item - .append_raw(' ').append(item) // 2+ items - foreach: .append_raw('\n').append_indent(indent).append(item) - LocalizedString& append_floating_list(int indent, View items); + LocalizedString& append_floating_list(int indent, View items) &; + LocalizedString&& append_floating_list(int indent, View items) &&; friend bool operator==(const LocalizedString& lhs, const LocalizedString& rhs) noexcept; friend bool operator!=(const LocalizedString& lhs, const LocalizedString& rhs) noexcept; friend bool operator<(const LocalizedString& lhs, const LocalizedString& rhs) noexcept; diff --git a/include/vcpkg/sourceparagraph.h b/include/vcpkg/sourceparagraph.h index fbbd9bf43f..2f6524c751 100644 --- a/include/vcpkg/sourceparagraph.h +++ b/include/vcpkg/sourceparagraph.h @@ -48,7 +48,6 @@ namespace vcpkg DependencyRequestedFeature(const std::string& name, PlatformExpression::Expr&& platform) : name(name), platform(std::move(platform)) { - Checks::check_exit(VCPKG_LINE_INFO, !this->name.empty() && this->name != "core" && this->name != "default"); } friend bool operator==(const DependencyRequestedFeature& lhs, const DependencyRequestedFeature& rhs); friend bool operator!=(const DependencyRequestedFeature& lhs, const DependencyRequestedFeature& rhs); diff --git a/locales/messages.json b/locales/messages.json index 77dd57c32f..2039451fb8 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -575,6 +575,11 @@ "_DefaultBinaryCacheRequiresAbsolutePath.comment": "An example of {path} is /foo/bar.", "DefaultBinaryCacheRequiresDirectory": "Environment variable VCPKG_DEFAULT_BINARY_CACHE must be a directory (was: {path})", "_DefaultBinaryCacheRequiresDirectory.comment": "An example of {path} is /foo/bar.", + "DefaultFeatureCore": "the feature 'core' turns off default features and thus can't be in the default features list", + "_DefaultFeatureCore.comment": "The word 'core' is an on-disk name that must not be localized.", + "DefaultFeatureDefault": "the feature 'default' refers to the set of default features and thus can't be in the default features list", + "_DefaultFeatureDefault.comment": "The word 'default' is an on-disk name that must not be localized.", + "DefaultFeatureIdentifier": "the names of default features must be identifiers", "DefaultFlag": "Defaulting to --{option} being on.", "_DefaultFlag.comment": "An example of {option} is editable.", "DefaultRegistryIsArtifact": "The default registry cannot be an artifact registry.", @@ -582,11 +587,10 @@ "_DefaultTripletChanged.comment": "The parts naming --triplet are command line switches that should be unlocalized. The space after the last 'triplet' and the period is intended to avoid the period looking like it's part of the command line switch An example of {triplet} is x64-windows.", "DeleteVcpkgConfigFromManifest": "-- Or remove \"vcpkg-configuration\" from the manifest file {path}.", "_DeleteVcpkgConfigFromManifest.comment": "An example of {path} is /foo/bar.", - "DependencyCoreFeature": "The feature 'core' cannot be in a dependency's feature list. To turn off default features, add \"default-features\": false instead.", - "_DependencyCoreFeature.comment": "The word 'core' is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", - "DependencyDefaultFeature": "The feature 'default' cannot be in a dependency's feature list. To turn on default features, add \"default-features\": true instead.", - "_DependencyDefaultFeature.comment": "The word 'default' is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", - "DependencyEmptyFeature": "the name of a dependent feature can't be empty.", + "DependencyFeatureCore": "The feature 'core' cannot be in a dependency's feature list. To turn off default features, add \"default-features\": false instead.", + "_DependencyFeatureCore.comment": "The word 'core' is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", + "DependencyFeatureDefault": "The feature 'default' cannot be in a dependency's feature list. To turn on default features, add \"default-features\": true instead.", + "_DependencyFeatureDefault.comment": "The word 'default' is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", "DependencyGraphCalculation": "Dependency graph submission enabled.", "DependencyGraphFailure": "Dependency graph submission failed.", "DependencyGraphSuccess": "Dependency graph submission successful.", diff --git a/src/vcpkg/base/messages.cpp b/src/vcpkg/base/messages.cpp index f7fba88f65..c2ca00e5d3 100644 --- a/src/vcpkg/base/messages.cpp +++ b/src/vcpkg/base/messages.cpp @@ -28,31 +28,39 @@ namespace vcpkg template LocalizedString LocalizedString::from_raw(std::basic_string&& s) noexcept; LocalizedString LocalizedString::from_raw(StringView s) { return LocalizedString(s); } - LocalizedString& LocalizedString::append_raw(char c) + LocalizedString& LocalizedString::append_raw(char c) & { m_data.push_back(c); return *this; } - LocalizedString& LocalizedString::append_raw(StringView s) + LocalizedString&& LocalizedString::append_raw(char c) && { return std::move(append_raw(c)); } + + LocalizedString& LocalizedString::append_raw(StringView s) & { m_data.append(s.begin(), s.size()); return *this; } - LocalizedString& LocalizedString::append(const LocalizedString& s) + LocalizedString&& LocalizedString::append_raw(StringView s) && { return std::move(append_raw(s)); } + + LocalizedString& LocalizedString::append(const LocalizedString& s) & { m_data.append(s.m_data); return *this; } - LocalizedString& LocalizedString::append_indent(size_t indent) + LocalizedString&& LocalizedString::append(const LocalizedString& s) && { return std::move(append(s)); } + + LocalizedString& LocalizedString::append_indent(size_t indent) & { m_data.append(indent * 2, ' '); return *this; } - LocalizedString& LocalizedString::append_floating_list(int indent, View items) + LocalizedString&& LocalizedString::append_indent(size_t indent) && { return std::move(append_indent(indent)); } + + LocalizedString& LocalizedString::append_floating_list(int indent, View items) & { switch (items.size()) { @@ -70,6 +78,11 @@ namespace vcpkg return *this; } + LocalizedString&& LocalizedString::append_floating_list(int indent, View items) && + { + return std::move(append_floating_list(indent, items)); + } + bool operator==(const LocalizedString& lhs, const LocalizedString& rhs) noexcept { return lhs.data() == rhs.data(); diff --git a/src/vcpkg/commands.add.cpp b/src/vcpkg/commands.add.cpp index e860bba668..62d0c5a109 100644 --- a/src/vcpkg/commands.add.cpp +++ b/src/vcpkg/commands.add.cpp @@ -111,6 +111,7 @@ namespace vcpkg structurally_equal(spec.platform.value_or(PlatformExpression::Expr()), dep.platform); }); const auto features = Util::fmap(spec.features.value_or({}), [](const std::string& feature) { + Checks::check_exit(VCPKG_LINE_INFO, !feature.empty() && feature != "core" && feature != "default"); return DependencyRequestedFeature{feature, PlatformExpression::Expr::Empty()}; }); if (dep == manifest_scf.core_paragraph->dependencies.end()) diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 655dd1e95c..07e810939c 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -371,8 +371,31 @@ namespace vcpkg auto maybe_default_features = parse_default_features_list(buf, origin, textrowcol); if (const auto default_features = maybe_default_features.get()) { - spgh->default_features = Util::fmap( - *default_features, [](const std::string& feature) { return DependencyRequestedFeature{feature}; }); + for (auto&& default_feature : *default_features) + { + if (default_feature == "core") + { + return ParseControlErrorInfo::from_error(origin, msg::format_error(msgDefaultFeatureCore)); + } + + if (default_feature == "default") + { + return ParseControlErrorInfo::from_error(origin, msg::format_error(msgDefaultFeatureDefault)); + } + + if (!Json::IdentifierDeserializer::is_ident(default_feature)) + { + return ParseControlErrorInfo::from_error(origin, + msg::format_error(msgDefaultFeatureIdentifier) + .append_raw('\n') + .append(msgNoteMessage) + .append(msgParseIdentifierError, + msg::value = default_feature, + msg::url = docs::manifests_url)); + } + + spgh->default_features.emplace_back(std::move(default_feature)); + } } else { @@ -491,6 +514,73 @@ namespace vcpkg }; const PlatformExprDeserializer PlatformExprDeserializer::instance; + struct DefaultFeatureNameDeserializer : Json::IDeserializer + { + virtual LocalizedString type_name() const override { return msg::format(msgADefaultFeature); } + virtual Optional visit_string(Json::Reader& r, StringView sv) const override + { + if (sv == "core") + { + r.add_generic_error(type_name(), msg::format(msgDefaultFeatureCore)); + return sv.to_string(); + } + + if (sv == "default") + { + r.add_generic_error(type_name(), msg::format(msgDefaultFeatureDefault)); + return sv.to_string(); + } + + return Json::IdentifierDeserializer::instance.visit_string(r, sv); + } + static const DefaultFeatureNameDeserializer instance; + }; + + const DefaultFeatureNameDeserializer DefaultFeatureNameDeserializer::instance; + + struct DefaultFeatureDeserializer : Json::IDeserializer + { + LocalizedString type_name() const override { return msg::format(msgADefaultFeature); } + + constexpr static StringLiteral NAME = "name"; + constexpr static StringLiteral PLATFORM = "platform"; + + Span valid_fields() const override + { + static const StringView t[] = { + NAME, + PLATFORM, + }; + return t; + } + + Optional visit_string(Json::Reader& r, StringView sv) const override + { + return DefaultFeatureNameDeserializer::instance.visit_string(r, sv).map( + [](std::string&& name) -> DependencyRequestedFeature { return std::move(name); }); + } + + Optional visit_object(Json::Reader& r, const Json::Object& obj) const override + { + std::string name; + PlatformExpression::Expr platform; + r.required_object_field(type_name(), obj, NAME, name, DefaultFeatureNameDeserializer::instance); + r.optional_object_field(obj, PLATFORM, platform, PlatformExprDeserializer::instance); + return DependencyRequestedFeature{std::move(name), std::move(platform)}; + } + + const static DefaultFeatureDeserializer instance; + }; + const DefaultFeatureDeserializer DefaultFeatureDeserializer::instance; + + struct DefaultFeatureArrayDeserializer : Json::ArrayDeserializer + { + LocalizedString type_name() const override { return msg::format(msgAnArrayOfDefaultFeatures); } + + static const DefaultFeatureArrayDeserializer instance; + }; + const DefaultFeatureArrayDeserializer DefaultFeatureArrayDeserializer::instance; + struct DependencyFeatureNameDeserializer : Json::IDeserializer { virtual LocalizedString type_name() const override { return msg::format(msgADependencyFeatureName); } @@ -498,14 +588,14 @@ namespace vcpkg { if (sv == "core") { - r.add_generic_error(type_name(), msg::format(msgDependencyCoreFeature)); - return nullopt; + r.add_generic_error(type_name(), msg::format(msgDependencyFeatureCore)); + return sv.to_string(); } if (sv == "default") { - r.add_generic_error(type_name(), msg::format(msgDependencyDefaultFeature)); - return nullopt; + r.add_generic_error(type_name(), msg::format(msgDependencyFeatureDefault)); + return sv.to_string(); } return Json::IdentifierDeserializer::instance.visit_string(r, sv); @@ -543,7 +633,6 @@ namespace vcpkg PlatformExpression::Expr platform; r.required_object_field(type_name(), obj, NAME, name, DependencyFeatureNameDeserializer::instance); r.optional_object_field(obj, PLATFORM, platform, PlatformExprDeserializer::instance); - if (name.empty()) return nullopt; return DependencyRequestedFeature{std::move(name), std::move(platform)}; } @@ -1196,7 +1285,7 @@ namespace vcpkg r.optional_object_field(obj, SUPPORTS, spgh.supports_expression, PlatformExprDeserializer::instance); r.optional_object_field( - obj, DEFAULT_FEATURES, spgh.default_features, DependencyFeatureArrayDeserializer::instance); + obj, DEFAULT_FEATURES, spgh.default_features, DefaultFeatureArrayDeserializer::instance); FeaturesObject features_tmp; r.optional_object_field(obj, FEATURES, features_tmp, FeaturesFieldDeserializer::instance); From 80fa91380acc966bbc8aaea4b2f1748073250889 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 28 Sep 2023 19:45:33 -0700 Subject: [PATCH 3/5] Make the e2e tests into unit tests and make the errors a bit prettier. --- .../default-feature-core-object.json | 3 - .../default-feature-core.json | 3 - .../default-feature-default-object.json | 3 - .../default-feature-default.json | 3 - .../default-feature-empty-object.json | 3 - .../default-feature-empty.json | 3 - .../dependency-feature-name-core-object.json | 12 - .../dependency-feature-name-core.json | 8 - ...ependency-feature-name-default-object.json | 8 - .../dependency-feature-name-default.json | 8 - .../dependency-feature-name-empty-object.json | 8 - .../dependency-feature-name-empty.json | 8 - .../dependency-name-empty-object.json | 7 - .../dependency-name-empty.json | 3 - .../end-to-end-tests-dir/format-manifest.ps1 | 25 -- include/vcpkg/base/jsonreader.h | 7 + include/vcpkg/base/message-data.inc.h | 54 +++-- include/vcpkg/sourceparagraph.h | 9 +- locales/messages.json | 31 +-- src/vcpkg-test/dependencies.cpp | 18 +- src/vcpkg-test/manifests.cpp | 213 ++++++++++++++++++ src/vcpkg-test/registries.cpp | 6 +- src/vcpkg/base/json.cpp | 15 ++ src/vcpkg/paragraphs.cpp | 2 +- src/vcpkg/sourceparagraph.cpp | 46 ++-- 25 files changed, 314 insertions(+), 192 deletions(-) delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core-object.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default-object.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty-object.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core-object.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default-object.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty-object.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty-object.json delete mode 100644 azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty.json diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core-object.json deleted file mode 100644 index c03140f6d1..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core-object.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "default-features": [ { "name": "core" } ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core.json deleted file mode 100644 index f282a980da..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-core.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "default-features": ["core"] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default-object.json deleted file mode 100644 index 2ab3418fb9..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default-object.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "default-features": [ { "name": "default" } ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default.json deleted file mode 100644 index dff94b4653..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-default.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "default-features": [ "default" ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty-object.json deleted file mode 100644 index 1be2afc05a..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty-object.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "default-features": [ { "name": "" } ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty.json b/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty.json deleted file mode 100644 index 039729c4e3..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/default-feature-empty.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "default-features": [ "" ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core-object.json deleted file mode 100644 index 1053f4142d..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core-object.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dependencies": [ - { - "name": "icu", - "features": [ - { - "name": "core" - } - ] - } - ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core.json deleted file mode 100644 index 4bcfa72295..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-core.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "dependencies": [ - { - "name": "icu", - "features": [ "core" ] - } - ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default-object.json deleted file mode 100644 index 4bc6ef701e..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default-object.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "dependencies": [ - { - "name": "icu", - "features": [ { "name": "default" } ] - } - ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default.json deleted file mode 100644 index 2b11a8e76a..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-default.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "dependencies": [ - { - "name": "icu", - "features": [ "default" ] - } - ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty-object.json deleted file mode 100644 index 2df194319e..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty-object.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "dependencies": [ - { - "name": "icu", - "features": [ { "name": "" } ] - } - ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty.json deleted file mode 100644 index 633075ddd0..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-feature-name-empty.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "dependencies": [ - { - "name": "icu", - "features": [ "" ] - } - ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty-object.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty-object.json deleted file mode 100644 index ad60fea9be..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty-object.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": [ - { - "name": "" - } - ] -} diff --git a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty.json b/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty.json deleted file mode 100644 index c55282c391..0000000000 --- a/azure-pipelines/e2e-assets/format-manifest-bad/dependency-name-empty.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "dependencies": [ "" ] -} diff --git a/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 b/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 index 67e6d71c1c..76d59e0540 100644 --- a/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 +++ b/azure-pipelines/end-to-end-tests-dir/format-manifest.ps1 @@ -1,6 +1,5 @@ . "$PSScriptRoot/../end-to-end-tests-prelude.ps1" -Write-Trace "test successfully parsing good inputs" $formatManifestAssets = (Get-Item "$PSScriptRoot/../e2e-assets/format-manifest").FullName $testProjects = Get-ChildItem "$formatManifestAssets/*.json" -File $testProjects | % { @@ -19,30 +18,6 @@ $testProjects | % { } } -Write-Trace "test not crashing parsing malformed inputs" -$formatManifestEvilAssets = (Get-Item "$PSScriptRoot/../e2e-assets/format-manifest-bad").FullName -$testEvilProjects = Get-ChildItem "$formatManifestEvilAssets/*.json" -File -$testEvilProjects | % { - $asItem = Get-Item $_ - $full = $asItem.FullName - Write-Trace "test that format-manifest on $full produces an error" - $output = Run-VcpkgAndCaptureOutput format-manifest $full - Throw-IfNotFailed - if ($output -match 'vcpkg has crashed') { - throw "vcpkg crashed parsing $full" - } - - $fullEscaped = [System.Text.RegularExpressions.Regex]::Escape($full) - if ($output -notmatch 'error: while loading ' + $fullEscaped ` - -or $output -notmatch 'error: Failed to parse manifest file: ' + $fullEscaped) { - throw "error not detected in $full" - } - - if ($output -match 'mismatched type:') { - throw "duplicate mismatched type error" - } -} - Write-Trace "test re-serializing every manifest" $manifestDir = "$TestingRoot/manifest-dir" Copy-Item -Path "$env:VCPKG_ROOT/ports" -Destination $manifestDir -recurse -Force -Filter vcpkg.json diff --git a/include/vcpkg/base/jsonreader.h b/include/vcpkg/base/jsonreader.h index 24fda8d19e..e948ff3961 100644 --- a/include/vcpkg/base/jsonreader.h +++ b/include/vcpkg/base/jsonreader.h @@ -350,4 +350,11 @@ namespace vcpkg::Json virtual Optional visit_string(Json::Reader&, StringView sv) const override; static const PackageNameDeserializer instance; }; + + struct FeatureNameDeserializer final : Json::IDeserializer + { + virtual LocalizedString type_name() const override; + virtual Optional visit_string(Json::Reader&, StringView sv) const override; + static const FeatureNameDeserializer instance; + }; } diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 61c9b9463e..07e7499832 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -5,8 +5,7 @@ DECLARE_MESSAGE(ABoolean, (), "", "a boolean") DECLARE_MESSAGE(ABuiltinRegistry, (), "", "a builtin registry") DECLARE_MESSAGE(AConfigurationObject, (), "", "a configuration object") DECLARE_MESSAGE(ADependency, (), "", "a dependency") -DECLARE_MESSAGE(ADependencyFeature, (), "", "a feature in a dependency") -DECLARE_MESSAGE(ADependencyFeatureName, (), "", "the name of a feature of a dependency") +DECLARE_MESSAGE(ADependencyFeature, (), "", "a feature of a dependency") DECLARE_MESSAGE(ADemandObject, (), "'demands' are a concept in the schema of a JSON file the user can edit", @@ -96,6 +95,7 @@ DECLARE_MESSAGE(AddVersionVersionAlreadyInFile, (msg::version, msg::path), "", " DECLARE_MESSAGE(AddVersionVersionIs, (msg::version), "", "version: {version}") DECLARE_MESSAGE(ADictionaryOfContacts, (), "", "a dictionary of contacts") DECLARE_MESSAGE(AFeature, (), "", "a feature") +DECLARE_MESSAGE(AFeatureName, (), "", "a feature name") DECLARE_MESSAGE(AFilesystemRegistry, (), "", "a filesystem registry") DECLARE_MESSAGE(AGitObjectSha, (), "", "a git object SHA") DECLARE_MESSAGE(AGitReference, (), "", "a git reference (for example, a branch)") @@ -985,13 +985,13 @@ DECLARE_MESSAGE(DefaultBinaryCacheRequiresDirectory, "Environment variable VCPKG_DEFAULT_BINARY_CACHE must be a directory (was: {path})") DECLARE_MESSAGE(DefaultFeatureCore, (), - "The word 'core' is an on-disk name that must not be localized.", - "the feature 'core' turns off default features and thus can't be in the default features list") + "The word \"core\" is an on-disk name that must not be localized.", + "the feature \"core\" turns off default features and thus can't be in the default features list") DECLARE_MESSAGE( DefaultFeatureDefault, (), - "The word 'default' is an on-disk name that must not be localized.", - "the feature 'default' refers to the set of default features and thus can't be in the default features list") + "The word \"default\" is an on-disk name that must not be localized.", + "the feature \"default\" refers to the set of default features and thus can't be in the default features list") DECLARE_MESSAGE(DefaultFeatureIdentifier, (), "", "the names of default features must be identifiers") DECLARE_MESSAGE(DefaultFlag, (msg::option), "", "Defaulting to --{option} being on.") DECLARE_MESSAGE(DefaultRegistryIsArtifact, (), "", "The default registry cannot be an artifact registry.") @@ -1009,16 +1009,17 @@ DECLARE_MESSAGE(DeleteVcpkgConfigFromManifest, "-- Or remove \"vcpkg-configuration\" from the manifest file {path}.") DECLARE_MESSAGE(DependencyFeatureCore, (), - "The word 'core' is an on-disk name that must not be localized. The 'default-features' part is JSON " + "The word \"core\" is an on-disk name that must not be localized. The 'default-features' part is JSON " "syntax that must be copied verbatim into the user's file.", - "The feature 'core' cannot be in a dependency's feature list. To turn off default features, add " + "the feature \"core\" cannot be in a dependency's feature list. To turn off default features, add " "\"default-features\": false instead.") -DECLARE_MESSAGE(DependencyFeatureDefault, - (), - "The word 'default' is an on-disk name that must not be localized. The 'default-features' part is JSON " - "syntax that must be copied verbatim into the user's file.", - "The feature 'default' cannot be in a dependency's feature list. To turn on default features, add " - "\"default-features\": true instead.") +DECLARE_MESSAGE( + DependencyFeatureDefault, + (), + "The word \"default\" is an on-disk name that must not be localized. The 'default-features' part is JSON " + "syntax that must be copied verbatim into the user's file.", + "the feature \"default\" cannot be in a dependency's feature list. To turn on default features, add " + "\"default-features\": true instead.") DECLARE_MESSAGE(DependencyGraphCalculation, (), "", "Dependency graph submission enabled.") DECLARE_MESSAGE(DependencyGraphFailure, (), "", "Dependency graph submission failed.") DECLARE_MESSAGE(DependencyGraphSuccess, (), "", "Dependency graph submission successful.") @@ -1928,10 +1929,6 @@ DECLARE_MESSAGE(InvalidCommentStyle, "comments.") DECLARE_MESSAGE(InvalidCommitId, (msg::commit_sha), "", "Invalid commit id: {commit_sha}") DECLARE_MESSAGE(InvalidDefaultFeatureName, (), "", "'default' is a reserved feature name") -DECLARE_MESSAGE(InvalidDependency, - (), - "", - "dependencies must be lowercase alphanumeric+hyphens, and not one of the reserved names") DECLARE_MESSAGE(InvalidFeature, (), "", @@ -2294,22 +2291,29 @@ DECLARE_MESSAGE(ParseControlErrorInfoWhileLoading, "Error messages are is printed after this.", "while loading {path}:") DECLARE_MESSAGE(ParseControlErrorInfoWrongTypeFields, (), "", "The following fields had the wrong types:") +DECLARE_MESSAGE( + ParseFeatureNameError, + (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).") 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)") -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)") + "Identifiers must be lowercase alphanumeric+hypens 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).") DECLARE_MESSAGE(ParsePackagePatternError, (msg::package_name, msg::url), "", "\"{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)") + "the pattern (see {url} for more information).") DECLARE_MESSAGE(PathMustBeAbsolute, (msg::path), "", diff --git a/include/vcpkg/sourceparagraph.h b/include/vcpkg/sourceparagraph.h index 2f6524c751..004da79113 100644 --- a/include/vcpkg/sourceparagraph.h +++ b/include/vcpkg/sourceparagraph.h @@ -41,14 +41,7 @@ namespace vcpkg { std::string name; PlatformExpression::Expr platform; - DependencyRequestedFeature(const std::string& name) - : DependencyRequestedFeature(name, PlatformExpression::Expr::Empty()) - { - } - DependencyRequestedFeature(const std::string& name, PlatformExpression::Expr&& platform) - : name(name), platform(std::move(platform)) - { - } + friend bool operator==(const DependencyRequestedFeature& lhs, const DependencyRequestedFeature& rhs); friend bool operator!=(const DependencyRequestedFeature& lhs, const DependencyRequestedFeature& rhs); }; diff --git a/locales/messages.json b/locales/messages.json index 2039451fb8..fbc50143d7 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -5,13 +5,14 @@ "ABuiltinRegistry": "a builtin registry", "AConfigurationObject": "a configuration object", "ADateVersionString": "a date version string", + "ADefaultFeature": "a default feature", "ADemandObject": "a demand object", "_ADemandObject.comment": "'demands' are a concept in the schema of a JSON file the user can edit", "ADependency": "a dependency", - "ADependencyFeature": "a feature in a dependency", - "ADependencyFeatureName": "the name of a feature of a dependency", + "ADependencyFeature": "a feature of a dependency", "ADictionaryOfContacts": "a dictionary of contacts", "AFeature": "a feature", + "AFeatureName": "a feature name", "AFilesystemRegistry": "a filesystem registry", "AGitObjectSha": "a git object SHA", "AGitReference": "a git reference (for example, a branch)", @@ -116,6 +117,7 @@ "_AlreadyInstalledNotHead.comment": "'HEAD' means the most recent version of source code An example of {spec} is zlib:x64-windows.", "AmbiguousConfigDeleteConfigFile": "Ambiguous vcpkg configuration provided by both manifest and configuration file.\n-- Delete configuration file {path}", "_AmbiguousConfigDeleteConfigFile.comment": "An example of {path} is /foo/bar.", + "AnArrayOfDefaultFeatures": "an array of default features", "AnArrayOfDependencies": "an array of dependencies", "AnArrayOfDependencyOverrides": "an array of dependency overrides", "AnArrayOfFeatures": "an array of features", @@ -575,10 +577,10 @@ "_DefaultBinaryCacheRequiresAbsolutePath.comment": "An example of {path} is /foo/bar.", "DefaultBinaryCacheRequiresDirectory": "Environment variable VCPKG_DEFAULT_BINARY_CACHE must be a directory (was: {path})", "_DefaultBinaryCacheRequiresDirectory.comment": "An example of {path} is /foo/bar.", - "DefaultFeatureCore": "the feature 'core' turns off default features and thus can't be in the default features list", - "_DefaultFeatureCore.comment": "The word 'core' is an on-disk name that must not be localized.", - "DefaultFeatureDefault": "the feature 'default' refers to the set of default features and thus can't be in the default features list", - "_DefaultFeatureDefault.comment": "The word 'default' is an on-disk name that must not be localized.", + "DefaultFeatureCore": "the feature \"core\" turns off default features and thus can't be in the default features list", + "_DefaultFeatureCore.comment": "The word \"core\" is an on-disk name that must not be localized.", + "DefaultFeatureDefault": "the feature \"default\" refers to the set of default features and thus can't be in the default features list", + "_DefaultFeatureDefault.comment": "The word \"default\" is an on-disk name that must not be localized.", "DefaultFeatureIdentifier": "the names of default features must be identifiers", "DefaultFlag": "Defaulting to --{option} being on.", "_DefaultFlag.comment": "An example of {option} is editable.", @@ -587,10 +589,10 @@ "_DefaultTripletChanged.comment": "The parts naming --triplet are command line switches that should be unlocalized. The space after the last 'triplet' and the period is intended to avoid the period looking like it's part of the command line switch An example of {triplet} is x64-windows.", "DeleteVcpkgConfigFromManifest": "-- Or remove \"vcpkg-configuration\" from the manifest file {path}.", "_DeleteVcpkgConfigFromManifest.comment": "An example of {path} is /foo/bar.", - "DependencyFeatureCore": "The feature 'core' cannot be in a dependency's feature list. To turn off default features, add \"default-features\": false instead.", - "_DependencyFeatureCore.comment": "The word 'core' is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", - "DependencyFeatureDefault": "The feature 'default' cannot be in a dependency's feature list. To turn on default features, add \"default-features\": true instead.", - "_DependencyFeatureDefault.comment": "The word 'default' is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", + "DependencyFeatureCore": "the feature \"core\" cannot be in a dependency's feature list. To turn off default features, add \"default-features\": false instead.", + "_DependencyFeatureCore.comment": "The word \"core\" is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", + "DependencyFeatureDefault": "the feature \"default\" cannot be in a dependency's feature list. To turn on default features, add \"default-features\": true instead.", + "_DependencyFeatureDefault.comment": "The word \"default\" is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", "DependencyGraphCalculation": "Dependency graph submission enabled.", "DependencyGraphFailure": "Dependency graph submission failed.", "DependencyGraphSuccess": "Dependency graph submission successful.", @@ -1086,7 +1088,6 @@ "InvalidCommitId": "Invalid commit id: {commit_sha}", "_InvalidCommitId.comment": "An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949.", "InvalidDefaultFeatureName": "'default' is a reserved feature name", - "InvalidDependency": "dependencies must be lowercase alphanumeric+hyphens, and not one of the reserved names", "InvalidFeature": "features must be lowercase alphanumeric+hyphens, and not one of the reserved names", "InvalidFileType": "failed: {path} cannot handle file type", "_InvalidFileType.comment": "An example of {path} is /foo/bar.", @@ -1322,11 +1323,13 @@ "ParseControlErrorInfoWhileLoading": "while loading {path}:", "_ParseControlErrorInfoWhileLoading.comment": "Error messages are is printed after this. An example of {path} is /foo/bar.", "ParseControlErrorInfoWrongTypeFields": "The following fields had the wrong types:", - "ParseIdentifierError": "\"{value}\" is not a valid identifier. Identifiers 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+hypens 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.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+hypens 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.", - "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": "\"{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.", "PathMustBeAbsolute": "Value of environment variable X_VCPKG_REGISTRIES_CACHE is not absolute: {path}", "_PathMustBeAbsolute.comment": "An example of {path} is /foo/bar.", diff --git a/src/vcpkg-test/dependencies.cpp b/src/vcpkg-test/dependencies.cpp index eef42ad3a7..e25623e8a6 100644 --- a/src/vcpkg-test/dependencies.cpp +++ b/src/vcpkg-test/dependencies.cpp @@ -1619,7 +1619,7 @@ TEST_CASE ("version install default features", "[versionplan]") auto a_x = make_fpgh("x"); auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; - a_scf->core_paragraph->default_features.emplace_back("x"); + a_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"x"}); a_scf->feature_paragraphs.push_back(std::move(a_x)); MockCMakeVarProvider var_provider; @@ -1640,7 +1640,7 @@ TEST_CASE ("version dont install default features", "[versionplan]") auto a_x = make_fpgh("x"); auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; - a_scf->core_paragraph->default_features.emplace_back("x"); + a_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"x"}); a_scf->feature_paragraphs.push_back(std::move(a_x)); MockCMakeVarProvider var_provider; @@ -1661,7 +1661,7 @@ TEST_CASE ("version install transitive default features", "[versionplan]") auto a_x = make_fpgh("x"); auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; - a_scf->core_paragraph->default_features.emplace_back("x"); + a_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"x"}); a_scf->feature_paragraphs.push_back(std::move(a_x)); auto& b_scf = vp.emplace("b", {"1", 0}, VersionScheme::Relaxed).source_control_file; @@ -1752,7 +1752,7 @@ TEST_CASE ("version install qualified default suppression", "[versionplan]") MockVersionedPortfileProvider vp; auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; - a_scf->core_paragraph->default_features.emplace_back("x"); + a_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"x"}); a_scf->feature_paragraphs.push_back(make_fpgh("x")); vp.emplace("b", {"1", 0}, VersionScheme::Relaxed) @@ -1837,17 +1837,17 @@ TEST_CASE ("version install qualified features", "[versionplan]") MockVersionedPortfileProvider vp; auto& b_scf = vp.emplace("b", {"1", 0}, VersionScheme::Relaxed).source_control_file; - b_scf->core_paragraph->default_features.emplace_back("x"); + b_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"x"}); b_scf->feature_paragraphs.push_back(make_fpgh("x")); b_scf->feature_paragraphs.back()->dependencies.push_back({"a", {}, parse_platform("!linux")}); auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; - a_scf->core_paragraph->default_features.emplace_back("y"); + a_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"y"}); a_scf->feature_paragraphs.push_back(make_fpgh("y")); a_scf->feature_paragraphs.back()->dependencies.push_back({"c", {}, parse_platform("linux")}); auto& c_scf = vp.emplace("c", {"1", 0}, VersionScheme::Relaxed).source_control_file; - c_scf->core_paragraph->default_features.emplace_back("z"); + c_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"z"}); c_scf->feature_paragraphs.push_back(make_fpgh("z")); c_scf->feature_paragraphs.back()->dependencies.push_back({"d", {}, parse_platform("linux")}); @@ -2313,8 +2313,8 @@ TEST_CASE ("respect platform expressions in default features", "[versionplan]") a_x->name = "x"; auto& scf = vp.emplace("a", {"1", 0}).source_control_file; scf->feature_paragraphs.push_back(std::move(a_x)); - scf->core_paragraph->default_features.emplace_back( - "x", parse_platform_expression("linux", MultipleBinaryOperators::Deny).value_or_exit(VCPKG_LINE_INFO)); + scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{ + "x", parse_platform_expression("linux", MultipleBinaryOperators::Deny).value_or_exit(VCPKG_LINE_INFO)}); } MockCMakeVarProvider var_provider; diff --git a/src/vcpkg-test/manifests.cpp b/src/vcpkg-test/manifests.cpp index 696a9fc88e..9411dfb071 100644 --- a/src/vcpkg-test/manifests.cpp +++ b/src/vcpkg-test/manifests.cpp @@ -1263,3 +1263,216 @@ TEST_CASE ("license error messages", "[manifests][license]") on expression: MIT AND unknownlicense ^)"); } + +TEST_CASE ("default-feature-core errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "default-features": ["core"] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == "error: while loading :\n" + "$.default-features[0] (a default feature): the feature \"core\" turns off " + "default features and thus can't be in the default features list"); +} + +TEST_CASE ("default-feature-core-object errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "default-features": [ { "name": "core" } ] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == "error: while loading :\n" + "$.default-features[0].name (a default feature): the feature \"core\" turns " + "off default features and thus can't be in the default features list"); +} + +TEST_CASE ("default-feature-default errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "default-features": ["default"] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == + "error: while loading :\n" + "$.default-features[0] (a default feature): the feature \"default\" refers to " + "the set of default features and thus can't be in the default features list"); +} + +TEST_CASE ("default-feature-default-object errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "default-features": [ { "name": "default" } ] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == + "error: while loading :\n" + "$.default-features[0].name (a default feature): the feature \"default\" refers to the set of default " + "features and thus can't be in the default features list"); +} + +TEST_CASE ("default-feature-empty errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "default-features": [""] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == "error: while loading :\n" + "$.default-features[0] (a feature name): \"\" is not a valid feature name. " + "Feature names must be lowercase alphanumeric+hypens and not reserved (see " + "https://learn.microsoft.com/vcpkg/users/manifests for more information)."); +} + +TEST_CASE ("default-feature-empty-object errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "default-features": [ { "name": "" } ] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == + "error: while loading :\n" + "$.default-features[0].name (a feature name): \"\" is not a valid feature name. " + "Feature names must be lowercase alphanumeric+hypens and not reserved (see " + "https://learn.microsoft.com/vcpkg/users/manifests for more information)."); +} + +TEST_CASE ("dependency-name-empty errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "dependencies": [ "" ] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == "error: while loading :\n" + "$.dependencies[0] (a package name): \"\" is not a valid package name. " + "Package names must be lowercase alphanumeric+hypens and not reserved (see " + "https://learn.microsoft.com/vcpkg/users/manifests for more information)."); +} + +TEST_CASE ("dependency-name-empty-object errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "dependencies": [ { "name": "" } ] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == "error: while loading :\n" + "$.dependencies[0].name (a package name): \"\" is not a valid package name. " + "Package names must be lowercase alphanumeric+hypens and not reserved (see " + "https://learn.microsoft.com/vcpkg/users/manifests for more information)."); +} + +TEST_CASE ("dependency-feature-name-core errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "dependencies": [ + { + "name": "icu", + "features": [ "core" ] + } + ] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == + "error: while loading :\n" + "$.dependencies[0].features[0] (a feature name): the feature \"core\" cannot be in a dependency's feature " + "list. To turn off default features, add \"default-features\": false instead."); +} + +TEST_CASE ("dependency-feature-name-core-object errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "dependencies": [ + { + "name": "icu", + "features": [ { "name": "core" } ] + } + ] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE( + m_pgh.error()->to_string() == + "error: while loading :\n" + "$.dependencies[0].features[0].name (a feature name): the feature \"core\" cannot be in a dependency's feature " + "list. To turn off default features, add \"default-features\": false instead."); +} + +TEST_CASE ("dependency-feature-name-default errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "dependencies": [ + { + "name": "icu", + "features": [ "default" ] + } + ] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == + "error: while loading :\n" + "$.dependencies[0].features[0] (a feature name): the feature \"default\" cannot be in a dependency's " + "feature list. To turn on default features, add \"default-features\": true instead."); +} + +TEST_CASE ("dependency-feature-name-default-object errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "dependencies": [ + { + "name": "icu", + "features": [ { "name": "default" } ] + } + ] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == + "error: while loading :\n" + "$.dependencies[0].features[0].name (a feature name): the feature \"default\" cannot be in a dependency's " + "feature list. To turn on default features, add \"default-features\": true instead."); +} +TEST_CASE ("dependency-feature-name-empty errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "dependencies": [ + { + "name": "icu", + "features": [ "" ] + } + ] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == + "error: while loading :\n" + "$.dependencies[0].features[0] (a feature name): \"\" is not a valid feature name. Feature names must be " + "lowercase alphanumeric+hypens and not reserved (see https://learn.microsoft.com/vcpkg/users/manifests for " + "more information)."); +} + +TEST_CASE ("dependency-feature-name-empty-object errors", "[manifests]") +{ + auto m_pgh = test_parse_project_manifest(R"json({ + "dependencies": [ + { + "name": "icu", + "features": [ { "name": "" } ] + } + ] + })json", + PrintErrors::No); + REQUIRE(!m_pgh.has_value()); + REQUIRE(m_pgh.error()->to_string() == + "error: while loading :\n" + "$.dependencies[0].features[0].name (a feature name): \"\" is not a valid feature name. Feature names must " + "be lowercase alphanumeric+hypens and not reserved (see https://learn.microsoft.com/vcpkg/users/manifests " + "for more information)."); +} diff --git a/src/vcpkg-test/registries.cpp b/src/vcpkg-test/registries.cpp index 9c81680f24..e5fd422825 100644 --- a/src/vcpkg-test/registries.cpp +++ b/src/vcpkg-test/registries.cpp @@ -422,15 +422,15 @@ TEST_CASE ("registries report pattern errors", "[registries]") CHECK(errors[0] == "$.registries[0].packages[1] (a package pattern): \"\" 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 " - "https://learn.microsoft.com/vcpkg/users/registries for more information)"); + "https://learn.microsoft.com/vcpkg/users/registries for more information)."); CHECK(errors[1] == "$.registries[0].packages[2] (a package pattern): \"a*a\" 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 " - "https://learn.microsoft.com/vcpkg/users/registries for more information)"); + "https://learn.microsoft.com/vcpkg/users/registries for more information)."); CHECK(errors[2] == "$.registries[0].packages[3] (a package pattern): \"*a\" 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 " - "https://learn.microsoft.com/vcpkg/users/registries for more information)"); + "https://learn.microsoft.com/vcpkg/users/registries for more information)."); } TEST_CASE ("registries ignored patterns warning", "[registries]") diff --git a/src/vcpkg/base/json.cpp b/src/vcpkg/base/json.cpp index 3020f365ce..6ca47f27db 100644 --- a/src/vcpkg/base/json.cpp +++ b/src/vcpkg/base/json.cpp @@ -1518,4 +1518,19 @@ namespace vcpkg::Json } const PackageNameDeserializer PackageNameDeserializer::instance; + + LocalizedString FeatureNameDeserializer::type_name() const { return msg::format(msgAFeatureName); } + + Optional FeatureNameDeserializer::visit_string(Json::Reader& r, StringView sv) const + { + if (!IdentifierDeserializer::is_ident(sv)) + { + r.add_generic_error( + type_name(), + msg::format(msgParseFeatureNameError, msg::package_name = sv, msg::url = docs::manifests_url)); + } + return sv.to_string(); + } + + const FeatureNameDeserializer FeatureNameDeserializer::instance; } diff --git a/src/vcpkg/paragraphs.cpp b/src/vcpkg/paragraphs.cpp index 8166b9adc3..49c48776b2 100644 --- a/src/vcpkg/paragraphs.cpp +++ b/src/vcpkg/paragraphs.cpp @@ -215,7 +215,7 @@ namespace vcpkg } else { - dependency.features.emplace_back(feature); + dependency.features.push_back(DependencyRequestedFeature{feature}); } } return dependency; diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 07e810939c..75b40598ae 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -394,7 +394,7 @@ namespace vcpkg msg::url = docs::manifests_url)); } - spgh->default_features.emplace_back(std::move(default_feature)); + spgh->default_features.push_back(DependencyRequestedFeature{std::move(default_feature)}); } } else @@ -531,7 +531,7 @@ namespace vcpkg return sv.to_string(); } - return Json::IdentifierDeserializer::instance.visit_string(r, sv); + return Json::FeatureNameDeserializer::instance.visit_string(r, sv); } static const DefaultFeatureNameDeserializer instance; }; @@ -557,16 +557,15 @@ namespace vcpkg Optional visit_string(Json::Reader& r, StringView sv) const override { return DefaultFeatureNameDeserializer::instance.visit_string(r, sv).map( - [](std::string&& name) -> DependencyRequestedFeature { return std::move(name); }); + [](std::string&& name) { return DependencyRequestedFeature{std::move(name)}; }); } Optional visit_object(Json::Reader& r, const Json::Object& obj) const override { - std::string name; - PlatformExpression::Expr platform; - r.required_object_field(type_name(), obj, NAME, name, DefaultFeatureNameDeserializer::instance); - r.optional_object_field(obj, PLATFORM, platform, PlatformExprDeserializer::instance); - return DependencyRequestedFeature{std::move(name), std::move(platform)}; + DependencyRequestedFeature answer; + r.required_object_field(type_name(), obj, NAME, answer.name, DefaultFeatureNameDeserializer::instance); + r.optional_object_field(obj, PLATFORM, answer.platform, PlatformExprDeserializer::instance); + return answer; } const static DefaultFeatureDeserializer instance; @@ -583,7 +582,7 @@ namespace vcpkg struct DependencyFeatureNameDeserializer : Json::IDeserializer { - virtual LocalizedString type_name() const override { return msg::format(msgADependencyFeatureName); } + virtual LocalizedString type_name() const override { return msg::format(msgAFeatureName); } virtual Optional visit_string(Json::Reader& r, StringView sv) const override { if (sv == "core") @@ -598,7 +597,7 @@ namespace vcpkg return sv.to_string(); } - return Json::IdentifierDeserializer::instance.visit_string(r, sv); + return Json::FeatureNameDeserializer::instance.visit_string(r, sv); } static const DependencyFeatureNameDeserializer instance; }; @@ -624,16 +623,15 @@ namespace vcpkg Optional visit_string(Json::Reader& r, StringView sv) const override { return DependencyFeatureNameDeserializer::instance.visit_string(r, sv).map( - [](std::string&& name) -> DependencyRequestedFeature { return std::move(name); }); + [](std::string&& name) { return DependencyRequestedFeature{std::move(name)}; }); } Optional visit_object(Json::Reader& r, const Json::Object& obj) const override { - std::string name; - PlatformExpression::Expr platform; - r.required_object_field(type_name(), obj, NAME, name, DependencyFeatureNameDeserializer::instance); - r.optional_object_field(obj, PLATFORM, platform, PlatformExprDeserializer::instance); - return DependencyRequestedFeature{std::move(name), std::move(platform)}; + DependencyRequestedFeature result; + r.required_object_field(type_name(), obj, NAME, result.name, DependencyFeatureNameDeserializer::instance); + r.optional_object_field(obj, PLATFORM, result.platform, PlatformExprDeserializer::instance); + return result; } const static DependencyFeatureDeserializer instance; @@ -675,14 +673,8 @@ namespace vcpkg virtual Optional visit_string(Json::Reader& r, StringView sv) const override { - if (!Json::IdentifierDeserializer::is_ident(sv)) - { - r.add_generic_error(type_name(), msg::format(msgInvalidDependency)); - } - - Dependency dep; - dep.name = sv.to_string(); - return dep; + return Json::PackageNameDeserializer::instance.visit_string(r, sv).map( + [](std::string&& name) { return Dependency{std::move(name)}; }); } virtual Optional visit_object(Json::Reader& r, const Json::Object& obj) const override @@ -776,7 +768,7 @@ namespace vcpkg VersionScheme& version_scheme, int& port_version) { - r.required_object_field(type_name, obj, NAME, name, Json::IdentifierDeserializer::instance); + r.required_object_field(type_name, obj, NAME, name, Json::PackageNameDeserializer::instance); auto schemed_version = visit_required_schemed_deserializer(type_name, r, obj, true); version = schemed_version.version.text(); @@ -1338,7 +1330,7 @@ namespace vcpkg auto& spgh = *control_file->core_paragraph; - r.optional_object_field(obj, NAME, spgh.name, Json::IdentifierDeserializer::instance); + r.optional_object_field(obj, NAME, spgh.name, Json::PackageNameDeserializer::instance); auto maybe_schemed_version = visit_optional_schemed_deserializer(type_name(), r, obj, false); if (auto p = maybe_schemed_version.get()) { @@ -1369,7 +1361,7 @@ namespace vcpkg auto& spgh = *control_file->core_paragraph; - r.required_object_field(type_name(), obj, NAME, spgh.name, Json::IdentifierDeserializer::instance); + r.required_object_field(type_name(), obj, NAME, spgh.name, Json::PackageNameDeserializer::instance); auto schemed_version = visit_required_schemed_deserializer(type_name(), r, obj, false); spgh.raw_version = schemed_version.version.text(); spgh.version_scheme = schemed_version.scheme; From 918269b50fe955e5e2b61dd7827f8109b8b94ed9 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 28 Sep 2023 19:56:21 -0700 Subject: [PATCH 4/5] Burninate Expr::Empty --- include/vcpkg/platform-expression.h | 5 +---- src/vcpkg/commands.add.cpp | 2 +- src/vcpkg/sourceparagraph.cpp | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/vcpkg/platform-expression.h b/include/vcpkg/platform-expression.h index 6d93abc7b4..25a66bdb71 100644 --- a/include/vcpkg/platform-expression.h +++ b/include/vcpkg/platform-expression.h @@ -24,11 +24,8 @@ namespace vcpkg::PlatformExpression static Expr And(std::vector&& exprs); static Expr Or(std::vector&& exprs); - // The empty expression is always true - static Expr Empty() { return Expr(); } - // since ExprImpl is not yet defined, we need to define the ctor and dtor in the C++ file - Expr(); + Expr(); // always true Expr(const Expr&); Expr(Expr&&); Expr& operator=(const Expr& e); diff --git a/src/vcpkg/commands.add.cpp b/src/vcpkg/commands.add.cpp index 62d0c5a109..fc1c7937c5 100644 --- a/src/vcpkg/commands.add.cpp +++ b/src/vcpkg/commands.add.cpp @@ -112,7 +112,7 @@ namespace vcpkg }); const auto features = Util::fmap(spec.features.value_or({}), [](const std::string& feature) { Checks::check_exit(VCPKG_LINE_INFO, !feature.empty() && feature != "core" && feature != "default"); - return DependencyRequestedFeature{feature, PlatformExpression::Expr::Empty()}; + return DependencyRequestedFeature{feature}; }); if (dep == manifest_scf.core_paragraph->dependencies.end()) { diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 75b40598ae..772cbb49fd 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -506,7 +506,7 @@ namespace vcpkg else { r.add_generic_error(type_name(), std::move(opt).error()); - return PlatformExpression::Expr::Empty(); + return PlatformExpression::Expr(); } } From 582382f172df936d3fa74d597ad5aeea450da577 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Fri, 29 Sep 2023 21:14:06 -0700 Subject: [PATCH 5/5] Code review feedback --- include/vcpkg/base/message-data.inc.h | 19 ++++++++++--------- locales/messages.json | 8 ++++---- src/vcpkg-test/dependencies.cpp | 18 +++++++++--------- src/vcpkg/paragraphs.cpp | 2 +- src/vcpkg/sourceparagraph.cpp | 2 +- 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 07e7499832..4c385a3af2 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -1007,16 +1007,17 @@ DECLARE_MESSAGE(DeleteVcpkgConfigFromManifest, (msg::path), "", "-- Or remove \"vcpkg-configuration\" from the manifest file {path}.") -DECLARE_MESSAGE(DependencyFeatureCore, - (), - "The word \"core\" is an on-disk name that must not be localized. The 'default-features' part is JSON " - "syntax that must be copied verbatim into the user's file.", - "the feature \"core\" cannot be in a dependency's feature list. To turn off default features, add " - "\"default-features\": false instead.") +DECLARE_MESSAGE( + DependencyFeatureCore, + (), + "The word \"core\" is an on-disk name that must not be localized. The \"default-features\" part is JSON " + "syntax that must be copied verbatim into the user's file.", + "the feature \"core\" cannot be in a dependency's feature list. To turn off default features, add " + "\"default-features\": false instead.") DECLARE_MESSAGE( DependencyFeatureDefault, (), - "The word \"default\" is an on-disk name that must not be localized. The 'default-features' part is JSON " + "The word \"default\" is an on-disk name that must not be localized. The \"default-features\" part is JSON " "syntax that must be copied verbatim into the user's file.", "the feature \"default\" cannot be in a dependency's feature list. To turn on default features, add " "\"default-features\": true instead.") @@ -2325,11 +2326,11 @@ DECLARE_MESSAGE(PECoffHeaderTooShort, DECLARE_MESSAGE(PEConfigCrossesSectionBoundary, (msg::path), "Portable executable is a term-of-art, see https://learn.microsoft.com/windows/win32/debug/pe-format", - "While parsing Portable Executable {path}, image config directory crosses a secion boundary.") + "While parsing Portable Executable {path}, image config directory crosses a section boundary.") DECLARE_MESSAGE(PEImportCrossesSectionBoundary, (msg::path), "Portable executable is a term-of-art, see https://learn.microsoft.com/windows/win32/debug/pe-format", - "While parsing Portable Executable {path}, import table crosses a secion boundary.") + "While parsing Portable Executable {path}, import table crosses a section boundary.") DECLARE_MESSAGE(PEPlusTagInvalid, (msg::path), "Portable executable is a term-of-art, see https://learn.microsoft.com/windows/win32/debug/pe-format", diff --git a/locales/messages.json b/locales/messages.json index fbc50143d7..145675625a 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -590,9 +590,9 @@ "DeleteVcpkgConfigFromManifest": "-- Or remove \"vcpkg-configuration\" from the manifest file {path}.", "_DeleteVcpkgConfigFromManifest.comment": "An example of {path} is /foo/bar.", "DependencyFeatureCore": "the feature \"core\" cannot be in a dependency's feature list. To turn off default features, add \"default-features\": false instead.", - "_DependencyFeatureCore.comment": "The word \"core\" is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", + "_DependencyFeatureCore.comment": "The word \"core\" is an on-disk name that must not be localized. The \"default-features\" part is JSON syntax that must be copied verbatim into the user's file.", "DependencyFeatureDefault": "the feature \"default\" cannot be in a dependency's feature list. To turn on default features, add \"default-features\": true instead.", - "_DependencyFeatureDefault.comment": "The word \"default\" is an on-disk name that must not be localized. The 'default-features' part is JSON syntax that must be copied verbatim into the user's file.", + "_DependencyFeatureDefault.comment": "The word \"default\" is an on-disk name that must not be localized. The \"default-features\" part is JSON syntax that must be copied verbatim into the user's file.", "DependencyGraphCalculation": "Dependency graph submission enabled.", "DependencyGraphFailure": "Dependency graph submission failed.", "DependencyGraphSuccess": "Dependency graph submission successful.", @@ -1282,9 +1282,9 @@ "_OverwritingFile.comment": "An example of {path} is /foo/bar.", "PECoffHeaderTooShort": "While parsing Portable Executable {path}, size of COFF header too small to contain a valid PE header.", "_PECoffHeaderTooShort.comment": "Portable executable is a term-of-art, see https://learn.microsoft.com/windows/win32/debug/pe-format An example of {path} is /foo/bar.", - "PEConfigCrossesSectionBoundary": "While parsing Portable Executable {path}, image config directory crosses a secion boundary.", + "PEConfigCrossesSectionBoundary": "While parsing Portable Executable {path}, image config directory crosses a section boundary.", "_PEConfigCrossesSectionBoundary.comment": "Portable executable is a term-of-art, see https://learn.microsoft.com/windows/win32/debug/pe-format An example of {path} is /foo/bar.", - "PEImportCrossesSectionBoundary": "While parsing Portable Executable {path}, import table crosses a secion boundary.", + "PEImportCrossesSectionBoundary": "While parsing Portable Executable {path}, import table crosses a section boundary.", "_PEImportCrossesSectionBoundary.comment": "Portable executable is a term-of-art, see https://learn.microsoft.com/windows/win32/debug/pe-format An example of {path} is /foo/bar.", "PEPlusTagInvalid": "While parsing Portable Executable {path}, optional header was neither PE32 nor PE32+.", "_PEPlusTagInvalid.comment": "Portable executable is a term-of-art, see https://learn.microsoft.com/windows/win32/debug/pe-format An example of {path} is /foo/bar.", diff --git a/src/vcpkg-test/dependencies.cpp b/src/vcpkg-test/dependencies.cpp index e25623e8a6..359e4233ae 100644 --- a/src/vcpkg-test/dependencies.cpp +++ b/src/vcpkg-test/dependencies.cpp @@ -1619,7 +1619,7 @@ TEST_CASE ("version install default features", "[versionplan]") auto a_x = make_fpgh("x"); auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; - a_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"x"}); + a_scf->core_paragraph->default_features.push_back({"x"}); a_scf->feature_paragraphs.push_back(std::move(a_x)); MockCMakeVarProvider var_provider; @@ -1640,7 +1640,7 @@ TEST_CASE ("version dont install default features", "[versionplan]") auto a_x = make_fpgh("x"); auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; - a_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"x"}); + a_scf->core_paragraph->default_features.push_back({"x"}); a_scf->feature_paragraphs.push_back(std::move(a_x)); MockCMakeVarProvider var_provider; @@ -1661,7 +1661,7 @@ TEST_CASE ("version install transitive default features", "[versionplan]") auto a_x = make_fpgh("x"); auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; - a_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"x"}); + a_scf->core_paragraph->default_features.push_back({"x"}); a_scf->feature_paragraphs.push_back(std::move(a_x)); auto& b_scf = vp.emplace("b", {"1", 0}, VersionScheme::Relaxed).source_control_file; @@ -1752,7 +1752,7 @@ TEST_CASE ("version install qualified default suppression", "[versionplan]") MockVersionedPortfileProvider vp; auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; - a_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"x"}); + a_scf->core_paragraph->default_features.push_back({"x"}); a_scf->feature_paragraphs.push_back(make_fpgh("x")); vp.emplace("b", {"1", 0}, VersionScheme::Relaxed) @@ -1837,17 +1837,17 @@ TEST_CASE ("version install qualified features", "[versionplan]") MockVersionedPortfileProvider vp; auto& b_scf = vp.emplace("b", {"1", 0}, VersionScheme::Relaxed).source_control_file; - b_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"x"}); + b_scf->core_paragraph->default_features.push_back({"x"}); b_scf->feature_paragraphs.push_back(make_fpgh("x")); b_scf->feature_paragraphs.back()->dependencies.push_back({"a", {}, parse_platform("!linux")}); auto& a_scf = vp.emplace("a", {"1", 0}, VersionScheme::Relaxed).source_control_file; - a_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"y"}); + a_scf->core_paragraph->default_features.push_back({"y"}); a_scf->feature_paragraphs.push_back(make_fpgh("y")); a_scf->feature_paragraphs.back()->dependencies.push_back({"c", {}, parse_platform("linux")}); auto& c_scf = vp.emplace("c", {"1", 0}, VersionScheme::Relaxed).source_control_file; - c_scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{"z"}); + c_scf->core_paragraph->default_features.push_back({"z"}); c_scf->feature_paragraphs.push_back(make_fpgh("z")); c_scf->feature_paragraphs.back()->dependencies.push_back({"d", {}, parse_platform("linux")}); @@ -2313,8 +2313,8 @@ TEST_CASE ("respect platform expressions in default features", "[versionplan]") a_x->name = "x"; auto& scf = vp.emplace("a", {"1", 0}).source_control_file; scf->feature_paragraphs.push_back(std::move(a_x)); - scf->core_paragraph->default_features.push_back(DependencyRequestedFeature{ - "x", parse_platform_expression("linux", MultipleBinaryOperators::Deny).value_or_exit(VCPKG_LINE_INFO)}); + scf->core_paragraph->default_features.push_back( + {"x", parse_platform_expression("linux", MultipleBinaryOperators::Deny).value_or_exit(VCPKG_LINE_INFO)}); } MockCMakeVarProvider var_provider; diff --git a/src/vcpkg/paragraphs.cpp b/src/vcpkg/paragraphs.cpp index 49c48776b2..14e58538b6 100644 --- a/src/vcpkg/paragraphs.cpp +++ b/src/vcpkg/paragraphs.cpp @@ -215,7 +215,7 @@ namespace vcpkg } else { - dependency.features.push_back(DependencyRequestedFeature{feature}); + dependency.features.push_back({feature}); } } return dependency; diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 772cbb49fd..7d8bcfbae1 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -394,7 +394,7 @@ namespace vcpkg msg::url = docs::manifests_url)); } - spgh->default_features.push_back(DependencyRequestedFeature{std::move(default_feature)}); + spgh->default_features.push_back({std::move(default_feature)}); } } else