Skip to content

Commit a5528f3

Browse files
authored
Emit an error for duplicate overrides. (#1573)
Also makes Json::IDeserializer no longer need a virtual dtor. Before (first one wins): PS D:\test> type vcpkg.json { "dependencies": [ "zlib" ], "overrides": [{"name": "zlib", "version": "1.2.13"}, {"name": "zlib", "version": "1.3.1"}] } Installing 2/2 zlib:[email protected]... Building zlib:[email protected]... C:\Users\bion\AppData\Local\vcpkg\registries\git-trees\ad5a49006f73b45b715299515f31164131b51982: info: installing overlay port from here -- Using cached madler-zlib-v1.2.13.tar.gz. -- Extracting source D:/vcpkg-downloads/madler-zlib-v1.2.13.tar.gz -- Applying patch 0001-Prevent-invalid-inclusions-when-HAVE_-is-set-to-0.patch -- Applying patch 0002-skip-building-examples.patch -- Applying patch 0003-build-static-or-shared-not-both.patch -- Applying patch 0004-android-and-mingw-fixes.patch -- Using source at D:/vcpkg/buildtrees/zlib/src/v1.2.13-f30d2a168d.clean -- Found external ninja('1.12.1'). -- Configuring x64-windows -- Building x64-windows-dbg -- Building x64-windows-rel -- Installing: D:/vcpkg/packages/zlib_x64-windows/share/zlib/vcpkg-cmake-wrapper.cmake -- Fixing pkgconfig file: D:/vcpkg/packages/zlib_x64-windows/lib/pkgconfig/zlib.pc -- Using cached msys2-mingw-w64-x86_64-pkgconf-1~2.3.0-1-any.pkg.tar.zst. -- Using cached msys2-msys2-runtime-3.5.4-2-x86_64.pkg.tar.zst. -- Using msys root at D:/vcpkg-downloads/tools/msys2/21caed2f81ec917b -- Fixing pkgconfig file: D:/vcpkg/packages/zlib_x64-windows/debug/lib/pkgconfig/zlib.pc -- Installing: D:/vcpkg/packages/zlib_x64-windows/share/zlib/copyright -- Performing post-build validation Stored binaries in 1 destinations in 93.9 ms. Elapsed time to handle zlib:x64-windows: 3.7 s zlib:x64-windows package ABI: a858cb84557b70b9fa3b3934233ce9667bef3fcf11c99b00070f799cc44bff14 Total install time: 3.7 s The package zlib is compatible with built-in CMake targets: find_package(ZLIB REQUIRED) target_link_libraries(main PRIVATE ZLIB::ZLIB) After: (an error) D:\test\vcpkg.json: error: $.overrides[1] (an override): zlib already has a declared override note: Extended documentation available at 'https://learn.microsoft.com/vcpkg/users/manifests?WT.mc_id=vcpkg_inproduct_cli'. Resolves https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1665249
1 parent f8052c7 commit a5528f3

File tree

15 files changed

+250
-220
lines changed

15 files changed

+250
-220
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "broken-duplicate-overrides",
3+
"version": "1",
4+
"dependencies": [
5+
"zlib"
6+
],
7+
"overrides": [
8+
{
9+
"name": "zlib",
10+
"version": "1.2.13"
11+
},
12+
{
13+
"name": "zlib",
14+
"version": "1.3.1"
15+
}
16+
]
17+
}

azure-pipelines/end-to-end-tests-dir/build-test-ports.ps1

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ Throw-IfFailed
2828
Run-Vcpkg @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports" --overlay-ports="$PSScriptRoot/../e2e-ports/broken-manifests" install control-file
2929
Throw-IfFailed
3030

31+
$output = Run-VcpkgAndCaptureOutput @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports/broken-manifests" install broken-duplicate-overrides
32+
Throw-IfNotFailed
33+
if ($output -notmatch "vcpkg\.json: error: \$\.overrides\[1\] \(an override\): zlib already has an override") {
34+
throw 'Did not detect duplicate override'
35+
}
36+
3137
$output = Run-VcpkgAndCaptureOutput @commonArgs --overlay-ports="$PSScriptRoot/../e2e-ports/broken-manifests" install broken-no-name
3238
Throw-IfNotFailed
3339
if ($output -notmatch "missing required field 'name'") {

include/vcpkg/base/jsonreader.h

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,8 @@ namespace vcpkg::Json
1818
using type = Type;
1919
virtual LocalizedString type_name() const = 0;
2020

21-
private:
22-
friend struct Reader;
2321
Optional<Type> visit(Reader&, const Value&) const;
2422
Optional<Type> visit(Reader&, const Object&) const;
25-
26-
public:
2723
virtual Optional<Type> visit_null(Reader&) const;
2824
virtual Optional<Type> visit_boolean(Reader&, bool) const;
2925
virtual Optional<Type> visit_integer(Reader& r, int64_t i) const;
@@ -33,14 +29,11 @@ namespace vcpkg::Json
3329
virtual Optional<Type> visit_object(Reader&, const Object&) const;
3430
virtual View<StringLiteral> valid_fields() const noexcept;
3531

36-
virtual ~IDeserializer() = default;
37-
3832
protected:
3933
IDeserializer() = default;
40-
IDeserializer(const IDeserializer&) = default;
41-
IDeserializer& operator=(const IDeserializer&) = default;
42-
IDeserializer(IDeserializer&&) = default;
43-
IDeserializer& operator=(IDeserializer&&) = default;
34+
IDeserializer(const IDeserializer&) = delete;
35+
IDeserializer& operator=(const IDeserializer&) = delete;
36+
~IDeserializer() = default;
4437
};
4538

4639
struct Reader
@@ -64,9 +57,6 @@ namespace vcpkg::Json
6457
StringView origin() const noexcept;
6558

6659
private:
67-
template<class Type>
68-
friend struct IDeserializer;
69-
7060
std::vector<LocalizedString> m_errors;
7161
std::vector<LocalizedString> m_warnings;
7262
struct JsonPathElement
@@ -168,19 +158,8 @@ namespace vcpkg::Json
168158
}
169159
}
170160

171-
template<class Type>
172-
Optional<Type> visit(const Value& value, const IDeserializer<Type>& visitor)
173-
{
174-
return visitor.visit(*this, value);
175-
}
176-
template<class Type>
177-
Optional<Type> visit(const Object& value, const IDeserializer<Type>& visitor)
178-
{
179-
return visitor.visit(*this, value);
180-
}
181-
182-
template<class Type>
183-
Optional<std::vector<Type>> array_elements(const Array& arr, const IDeserializer<Type>& visitor)
161+
template<class Type, class Fn>
162+
Optional<std::vector<Type>> array_elements_fn(const Array& arr, const IDeserializer<Type>& visitor, Fn callback)
184163
{
185164
Optional<std::vector<Type>> result{std::vector<Type>()};
186165
auto& result_vec = *result.get();
@@ -189,7 +168,7 @@ namespace vcpkg::Json
189168
for (size_t i = 0; i < arr.size(); ++i)
190169
{
191170
m_path.back().index = static_cast<int64_t>(i);
192-
auto opt = visitor.visit(*this, arr[i]);
171+
auto opt = callback(*this, visitor, arr[i]);
193172
if (auto parsed = opt.get())
194173
{
195174
if (success)
@@ -208,6 +187,15 @@ namespace vcpkg::Json
208187
return result;
209188
}
210189

190+
template<class Type>
191+
Optional<std::vector<Type>> array_elements(const Array& arr, const IDeserializer<Type>& visitor)
192+
{
193+
return array_elements_fn(
194+
arr, visitor, [](Reader& this_, const IDeserializer<Type>& visitor, const Json::Value& value) {
195+
return visitor.visit(this_, value);
196+
});
197+
}
198+
211199
static uint64_t get_reader_stats();
212200

213201
private:

include/vcpkg/base/message-data.inc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,7 @@ DECLARE_MESSAGE(DownloadWinHttpError,
11241124
(msg::system_api, msg::exit_code, msg::url),
11251125
"",
11261126
"{url}: {system_api} failed with exit code {exit_code}.")
1127+
DECLARE_MESSAGE(DuplicateDependencyOverride, (msg::package_name), "", "{package_name} already has an override")
11271128
DECLARE_MESSAGE(DuplicatedKeyInObj,
11281129
(msg::value),
11291130
"{value} is a json property/object",

include/vcpkg/configuration.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ namespace vcpkg
8989
Optional<Configuration> config;
9090
};
9191

92-
Json::IDeserializer<Configuration>& get_configuration_deserializer();
92+
extern const Json::IDeserializer<Configuration>& configuration_deserializer;
9393
// Parse configuration from a file containing a valid vcpkg-configuration.json file
9494
Optional<Configuration> parse_configuration(StringView contents,
9595
StringView origin,

include/vcpkg/registries-parsing.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#pragma once
2+
#include <vcpkg/base/jsonreader.h>
3+
4+
#include <vcpkg/registries.h>
5+
6+
namespace vcpkg
7+
{
8+
struct FilesystemVersionDbEntryDeserializer final : Json::IDeserializer<FilesystemVersionDbEntry>
9+
{
10+
LocalizedString type_name() const override;
11+
View<StringLiteral> valid_fields() const noexcept override;
12+
Optional<FilesystemVersionDbEntry> visit_object(Json::Reader& r, const Json::Object& obj) const override;
13+
FilesystemVersionDbEntryDeserializer(const Path& root) : registry_root(root) { }
14+
15+
private:
16+
Path registry_root;
17+
};
18+
19+
struct FilesystemVersionDbEntryArrayDeserializer final : Json::IDeserializer<std::vector<FilesystemVersionDbEntry>>
20+
{
21+
virtual LocalizedString type_name() const override;
22+
virtual Optional<std::vector<FilesystemVersionDbEntry>> visit_array(Json::Reader& r,
23+
const Json::Array& arr) const override;
24+
FilesystemVersionDbEntryArrayDeserializer(const Path& root) : underlying{root} { }
25+
26+
private:
27+
FilesystemVersionDbEntryDeserializer underlying;
28+
};
29+
30+
struct GitVersionDbEntryDeserializer final : Json::IDeserializer<GitVersionDbEntry>
31+
{
32+
LocalizedString type_name() const override;
33+
View<StringLiteral> valid_fields() const noexcept override;
34+
Optional<GitVersionDbEntry> visit_object(Json::Reader& r, const Json::Object& obj) const override;
35+
};
36+
37+
struct GitVersionDbEntryArrayDeserializer final : Json::IDeserializer<std::vector<GitVersionDbEntry>>
38+
{
39+
virtual LocalizedString type_name() const override;
40+
virtual Optional<std::vector<GitVersionDbEntry>> visit_array(Json::Reader& r,
41+
const Json::Array& arr) const override;
42+
};
43+
}

include/vcpkg/registries.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,4 @@ namespace vcpkg
217217
// No match is 0, exact match is SIZE_MAX, wildcard match is the length of the pattern.
218218
// Note that the * is included in the match size to distinguish from 0 == no match.
219219
size_t package_pattern_match(StringView name, StringView pattern);
220-
221-
std::unique_ptr<Json::IDeserializer<std::vector<GitVersionDbEntry>>> make_git_version_db_deserializer();
222-
std::unique_ptr<Json::IDeserializer<std::vector<FilesystemVersionDbEntry>>> make_filesystem_version_db_deserializer(
223-
const Path& root);
224220
}

locales/messages.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,8 @@
653653
"DownloadingVcpkgStandaloneBundle": "Downloading standalone bundle {version}.",
654654
"_DownloadingVcpkgStandaloneBundle.comment": "An example of {version} is 1.3.8.",
655655
"DownloadingVcpkgStandaloneBundleLatest": "Downloading latest standalone bundle.",
656+
"DuplicateDependencyOverride": "{package_name} already has an override",
657+
"_DuplicateDependencyOverride.comment": "An example of {package_name} is zlib.",
656658
"DuplicatePackagePattern": "Package \"{package_name}\" is duplicated.",
657659
"_DuplicatePackagePattern.comment": "An example of {package_name} is zlib.",
658660
"DuplicatePackagePatternFirstOcurrence": "First declared in:",

src/vcpkg-test/configmetadata.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ static Configuration parse_test_configuration(StringView text)
4040
auto object = Json::parse_object(text, origin).value_or_exit(VCPKG_LINE_INFO);
4141

4242
Json::Reader reader(origin);
43-
auto parsed_config_opt = reader.visit(object, get_configuration_deserializer());
43+
auto parsed_config_opt = configuration_deserializer.visit(reader, object);
4444
REQUIRE(reader.errors().empty());
4545

4646
return std::move(parsed_config_opt).value_or_exit(VCPKG_LINE_INFO);
@@ -60,7 +60,7 @@ static void check_errors(const std::string& config_text, const std::string& expe
6060
auto object = Json::parse_object(config_text, origin).value_or_exit(VCPKG_LINE_INFO);
6161

6262
Json::Reader reader(origin);
63-
auto parsed_config_opt = reader.visit(object, get_configuration_deserializer());
63+
auto parsed_config_opt = configuration_deserializer.visit(reader, object);
6464
REQUIRE(!reader.errors().empty());
6565

6666
CHECK_LINES(Strings::join("\n", reader.errors()), expected_errors);

src/vcpkg-test/registries.cpp

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
#include <vcpkg/configuration.h>
77
#include <vcpkg/documentation.h>
8-
#include <vcpkg/registries.h>
8+
#include <vcpkg/registries-parsing.h>
99

1010
using namespace vcpkg;
1111

@@ -276,7 +276,7 @@ static vcpkg::Optional<Configuration> visit_default_registry(Json::Reader& r, Js
276276
{
277277
Json::Object config;
278278
config.insert("default-registry", std::move(reg));
279-
return r.visit(config, get_configuration_deserializer());
279+
return configuration_deserializer.visit(r, config);
280280
}
281281

282282
TEST_CASE ("registry_parsing", "[registries]")
@@ -428,7 +428,7 @@ TEST_CASE ("registries report pattern errors", "[registries]")
428428
})json");
429429

430430
Json::Reader r{"test"};
431-
auto maybe_conf = r.visit(test_json, get_configuration_deserializer());
431+
auto maybe_conf = configuration_deserializer.visit(r, test_json);
432432
const auto& errors = r.errors();
433433
CHECK(!errors.empty());
434434
REQUIRE(errors.size() == 3);
@@ -474,7 +474,7 @@ TEST_CASE ("registries ignored patterns warning", "[registries]")
474474
})json");
475475

476476
Json::Reader r{"test"};
477-
auto maybe_conf = r.visit(test_json, get_configuration_deserializer());
477+
auto maybe_conf = configuration_deserializer.visit(r, test_json);
478478

479479
auto conf = maybe_conf.get();
480480
REQUIRE(conf);
@@ -550,7 +550,6 @@ TEST_CASE ("registries ignored patterns warning", "[registries]")
550550

551551
TEST_CASE ("git_version_db_parsing", "[registries]")
552552
{
553-
auto filesystem_version_db = make_git_version_db_deserializer();
554553
Json::Reader r{"test"};
555554
auto test_json = parse_json(R"json(
556555
[
@@ -572,7 +571,7 @@ TEST_CASE ("git_version_db_parsing", "[registries]")
572571
]
573572
)json");
574573

575-
auto results_opt = r.visit(test_json, *filesystem_version_db);
574+
auto results_opt = GitVersionDbEntryArrayDeserializer().visit(r, test_json);
576575
auto& results = results_opt.value_or_exit(VCPKG_LINE_INFO);
577576
CHECK(results[0].version == SchemedVersion{VersionScheme::Date, {"2021-06-26", 0}});
578577
CHECK(results[0].git_tree == "9b07f8a38bbc4d13f8411921e6734753e15f8d50");
@@ -585,7 +584,7 @@ TEST_CASE ("git_version_db_parsing", "[registries]")
585584

586585
TEST_CASE ("filesystem_version_db_parsing", "[registries]")
587586
{
588-
auto filesystem_version_db = make_filesystem_version_db_deserializer("a/b");
587+
FilesystemVersionDbEntryArrayDeserializer filesystem_version_db("a/b");
589588

590589
{
591590
Json::Reader r{"test"};
@@ -608,7 +607,7 @@ TEST_CASE ("filesystem_version_db_parsing", "[registries]")
608607
}
609608
]
610609
)json");
611-
auto results_opt = r.visit(test_json, *filesystem_version_db);
610+
auto results_opt = filesystem_version_db.visit(r, test_json);
612611
auto& results = results_opt.value_or_exit(VCPKG_LINE_INFO);
613612
CHECK(results[0].version == SchemedVersion{VersionScheme::String, {"puppies", 0}});
614613
CHECK(results[0].p == "a/b" VCPKG_PREFERRED_SEPARATOR "c/d");
@@ -630,7 +629,7 @@ TEST_CASE ("filesystem_version_db_parsing", "[registries]")
630629
}
631630
]
632631
)json");
633-
CHECK(r.visit(test_json, *filesystem_version_db).value_or_exit(VCPKG_LINE_INFO).empty());
632+
CHECK(filesystem_version_db.visit(r, test_json).value_or_exit(VCPKG_LINE_INFO).empty());
634633
CHECK(!r.errors().empty());
635634
}
636635

@@ -645,7 +644,7 @@ TEST_CASE ("filesystem_version_db_parsing", "[registries]")
645644
}
646645
]
647646
)json");
648-
CHECK(r.visit(test_json, *filesystem_version_db).value_or_exit(VCPKG_LINE_INFO).empty());
647+
CHECK(filesystem_version_db.visit(r, test_json).value_or_exit(VCPKG_LINE_INFO).empty());
649648
CHECK(!r.errors().empty());
650649
}
651650

@@ -660,7 +659,7 @@ TEST_CASE ("filesystem_version_db_parsing", "[registries]")
660659
}
661660
]
662661
)json");
663-
CHECK(r.visit(test_json, *filesystem_version_db).value_or_exit(VCPKG_LINE_INFO).empty());
662+
CHECK(filesystem_version_db.visit(r, test_json).value_or_exit(VCPKG_LINE_INFO).empty());
664663
CHECK(!r.errors().empty());
665664
}
666665

@@ -675,7 +674,7 @@ TEST_CASE ("filesystem_version_db_parsing", "[registries]")
675674
}
676675
]
677676
)json");
678-
CHECK(r.visit(test_json, *filesystem_version_db).value_or_exit(VCPKG_LINE_INFO).empty());
677+
CHECK(filesystem_version_db.visit(r, test_json).value_or_exit(VCPKG_LINE_INFO).empty());
679678
CHECK(!r.errors().empty());
680679
}
681680

@@ -690,7 +689,7 @@ TEST_CASE ("filesystem_version_db_parsing", "[registries]")
690689
}
691690
]
692691
)json");
693-
CHECK(r.visit(test_json, *filesystem_version_db).value_or_exit(VCPKG_LINE_INFO).empty());
692+
CHECK(filesystem_version_db.visit(r, test_json).value_or_exit(VCPKG_LINE_INFO).empty());
694693
CHECK(!r.errors().empty());
695694
}
696695

@@ -705,7 +704,7 @@ TEST_CASE ("filesystem_version_db_parsing", "[registries]")
705704
}
706705
]
707706
)json");
708-
CHECK(r.visit(test_json, *filesystem_version_db).value_or_exit(VCPKG_LINE_INFO).empty());
707+
CHECK(filesystem_version_db.visit(r, test_json).value_or_exit(VCPKG_LINE_INFO).empty());
709708
CHECK(!r.errors().empty());
710709
}
711710

@@ -720,7 +719,7 @@ TEST_CASE ("filesystem_version_db_parsing", "[registries]")
720719
}
721720
]
722721
)json");
723-
CHECK(r.visit(test_json, *filesystem_version_db).value_or_exit(VCPKG_LINE_INFO).empty());
722+
CHECK(filesystem_version_db.visit(r, test_json).value_or_exit(VCPKG_LINE_INFO).empty());
724723
CHECK(!r.errors().empty());
725724
}
726725

@@ -735,7 +734,7 @@ TEST_CASE ("filesystem_version_db_parsing", "[registries]")
735734
}
736735
]
737736
)json");
738-
CHECK(r.visit(test_json, *filesystem_version_db).value_or_exit(VCPKG_LINE_INFO).empty());
737+
CHECK(filesystem_version_db.visit(r, test_json).value_or_exit(VCPKG_LINE_INFO).empty());
739738
CHECK(!r.errors().empty());
740739
}
741740

@@ -750,7 +749,7 @@ TEST_CASE ("filesystem_version_db_parsing", "[registries]")
750749
}
751750
]
752751
)json");
753-
CHECK(r.visit(test_json, *filesystem_version_db).value_or_exit(VCPKG_LINE_INFO).empty());
752+
CHECK(filesystem_version_db.visit(r, test_json).value_or_exit(VCPKG_LINE_INFO).empty());
754753
CHECK(!r.errors().empty());
755754
}
756755
}

0 commit comments

Comments
 (0)