Refactor apart 'config data' from 'behavior object' for registries (#275)

* Refactor apart 'config data' from 'behavior object' for registries

* Fix relative path in filesystem registry config

* Address review comments

* Review comments
This commit is contained in:
Robert Schumacher 2021-11-29 15:56:50 -08:00 коммит произвёл GitHub
Родитель 48b94a6946
Коммит e7cb06347c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
25 изменённых файлов: 870 добавлений и 730 удалений

Просмотреть файл

@ -229,6 +229,52 @@ finally
Pop-Location
}
# test the filesystem registry with a relative path
Write-Trace "test the filesystem registry with a relative path"
$manifestDir = "$TestingRoot/filesystem-registry-test-manifest-dir"
Remove-Item -Recurse -Force $manifestDir -ErrorAction SilentlyContinue
New-Item -Path $manifestDir -ItemType Directory
$manifestDir = (Get-Item $manifestDir).FullName
Push-Location $manifestDir
try
{
$vcpkgJson = @{
"name" = "manifest-test";
"version-string" = "1.0.0";
"dependencies" = @(
"vcpkg-internal-e2e-test-port"
);
# Use versioning features without a builtin-baseline
"overrides" = @(@{
"name" = "unused";
"version" = "0";
})
}
$vcpkgConfigurationJson = @{
"default-registry" = $null;
"registries" = @(
@{
"kind" = "filesystem";
"path" = "../filesystem-registry";
"packages" = @( "vcpkg-internal-e2e-test-port" )
}
)
}
New-Item -Path 'vcpkg.json' -ItemType File `
-Value (ConvertTo-Json -Depth 5 -InputObject $vcpkgJson)
New-Item -Path 'vcpkg-configuration.json' -ItemType File `
-Value (ConvertTo-Json -Depth 5 -InputObject $vcpkgConfigurationJson)
Run-Vcpkg install @builtinRegistryArgs '--feature-flags=registries,manifests'
Throw-IfFailed
}
finally
{
Pop-Location
}
# test the git registry
Write-Trace "test the git registry"
$manifestDir = "$TestingRoot/git-registry-test-manifest-dir"

Просмотреть файл

@ -121,5 +121,9 @@ namespace vcpkg::Test
}
}
void check_json_eq(const Json::Value& l, const Json::Value& r);
void check_json_eq(const Json::Object& l, const Json::Object& r);
void check_json_eq(const Json::Array& l, const Json::Array& r);
const Path& base_temporary_directory() noexcept;
}

Просмотреть файл

@ -281,7 +281,7 @@ namespace vcpkg::Json
virtual StringView type_name() const override { return type_name_; }
virtual Optional<std::string> visit_string(Reader&, StringView sv) override { return sv.to_string(); }
explicit StringDeserializer(StringLiteral type_name_) : type_name_(type_name_) { }
constexpr explicit StringDeserializer(StringLiteral type_name_) : type_name_(type_name_) { }
private:
StringLiteral type_name_;
@ -327,7 +327,7 @@ namespace vcpkg::Json
virtual StringView type_name() const override { return m_type_name; }
ArrayDeserializer(StringLiteral type_name_, Underlying&& t = {})
constexpr ArrayDeserializer(StringLiteral type_name_, Underlying&& t = {})
: m_type_name(type_name_), m_underlying_visitor(static_cast<Underlying&&>(t))
{
}

Просмотреть файл

@ -253,6 +253,12 @@ namespace vcpkg
constexpr explicit operator bool() const { return this->m_base.has_value(); }
T& emplace()
{
this->m_base = T{};
return this->m_base.value();
}
constexpr bool has_value() const { return this->m_base.has_value(); }
template<class U>

Просмотреть файл

@ -10,21 +10,43 @@
namespace vcpkg
{
struct RegistryConfig
{
// Missing kind means "null"
Optional<std::string> kind;
Optional<std::string> baseline;
Optional<std::string> location;
Optional<std::string> name;
Optional<Path> path;
Optional<std::string> reference;
Optional<std::string> repo;
Optional<std::vector<std::string>> packages;
Json::Value serialize() const;
};
struct Configuration
{
// This member is set up via two different configuration options,
// `registries` and `default_registry`. The fall back logic is
// taken care of in RegistrySet.
RegistrySet registry_set;
Optional<RegistryConfig> default_reg;
std::vector<RegistryConfig> registries;
Json::Object ce_metadata;
Json::Object extra_info;
void validate_feature_flags(const FeatureFlagSettings& flags);
Json::Object serialize() const;
void validate_as_active();
std::unique_ptr<RegistrySet> instantiate_registry_set(const Path& config_dir) const;
static View<StringView> known_fields();
};
std::unique_ptr<Json::IDeserializer<Configuration>> make_configuration_deserializer(const Path& config_directory);
Json::Object serialize_configuration(const Configuration& config);
struct ManifestConfiguration
{
Optional<std::string> builtin_baseline;
Optional<Configuration> config;
};
Json::IDeserializer<Configuration>& get_configuration_deserializer();
Json::IDeserializer<ManifestConfiguration>& get_manifest_configuration_deserializer();
std::vector<std::string> find_unknown_fields(const Configuration& config);
}

Просмотреть файл

@ -0,0 +1,22 @@
#pragma once
#include <vcpkg/base/stringliteral.h>
namespace vcpkg
{
namespace docs
{
static constexpr StringLiteral registries_url =
"https://github.com/Microsoft/vcpkg/tree/master/docs/users/registries.md";
static constexpr StringLiteral manifests_url =
"https://github.com/Microsoft/vcpkg/tree/master/docs/users/manifest.md";
static constexpr StringLiteral assetcaching_url =
"https://github.com/Microsoft/vcpkg/tree/master/docs/users/assetcaching.md";
static constexpr StringLiteral binarycaching_url =
"https://github.com/Microsoft/vcpkg/tree/master/docs/users/binarycaching.md";
static constexpr StringLiteral versioning_url =
"https://github.com/Microsoft/vcpkg/tree/master/docs/users/versioning.md";
static constexpr StringLiteral vcpkg_visual_studio_path_url =
"https://github.com/microsoft/vcpkg/blob/master/docs/users/triplets.md#VCPKG_VISUAL_STUDIO_PATH";
}
}

Просмотреть файл

@ -3,4 +3,5 @@
namespace vcpkg
{
struct Configuration;
struct RegistryConfig;
}

Просмотреть файл

@ -73,8 +73,6 @@ namespace vcpkg
virtual Optional<Path> get_path_to_baseline_version(const VcpkgPaths& paths, StringView port_name) const;
virtual Json::Object serialize() const;
virtual ~RegistryImplementation() = default;
};
@ -104,7 +102,10 @@ namespace vcpkg
// configuration fields.
struct RegistrySet
{
RegistrySet();
RegistrySet(std::unique_ptr<RegistryImplementation>&& x, std::vector<Registry>&& y)
: default_registry_(std::move(x)), registries_(std::move(y))
{
}
// finds the correct registry for the port name
// Returns the null pointer if there is no registry set up for that name
@ -115,12 +116,7 @@ namespace vcpkg
const RegistryImplementation* default_registry() const { return default_registry_.get(); }
// TODO: figure out how to get this to return an error (or maybe it should be a warning?)
void add_registry(Registry&& r);
void set_default_registry(std::unique_ptr<RegistryImplementation>&& r);
void set_default_registry(std::nullptr_t r);
bool is_default_builtin_registry() const;
void set_default_builtin_registry_baseline(StringView baseline);
// returns whether the registry set has any modifications to the default
// (i.e., whether `default_registry` was set, or `registries` had any entries)
@ -132,13 +128,13 @@ namespace vcpkg
std::vector<Registry> registries_;
};
Json::Object serialize_registry_set(const RegistrySet& config);
std::unique_ptr<Json::IDeserializer<std::unique_ptr<RegistryImplementation>>>
get_registry_implementation_deserializer(const Path& configuration_directory);
std::unique_ptr<Json::IDeserializer<std::vector<Registry>>> get_registry_array_deserializer(
const Path& configuration_directory);
std::unique_ptr<RegistryImplementation> make_builtin_registry();
std::unique_ptr<RegistryImplementation> make_builtin_registry(std::string baseline);
std::unique_ptr<RegistryImplementation> make_git_registry(std::string repo,
std::string reference,
std::string baseline);
std::unique_ptr<RegistryImplementation> make_filesystem_registry(Path path, std::string baseline);
std::unique_ptr<RegistryImplementation> make_artifact_registry(std::string name, std::string location);
ExpectedS<std::vector<std::pair<SchemedVersion, std::string>>> get_builtin_versions(const VcpkgPaths& paths,
StringView port_name);

Просмотреть файл

@ -128,6 +128,9 @@ namespace vcpkg
Json::Object serialize_manifest(const SourceControlFile& scf);
Json::Object serialize_debug_manifest(const SourceControlFile& scf);
ExpectedS<struct ManifestConfiguration> parse_manifest_configuration(StringView origin,
const Json::Object& manifest);
/// <summary>
/// Named pair of a SourceControlFile and the location of this file
/// </summary>

Просмотреть файл

@ -109,7 +109,6 @@ namespace vcpkg
Path original_cwd;
Path root;
Path manifest_root_dir;
Path config_root_dir;
Path downloads;
Path triplets;
Path community_triplets;
@ -159,8 +158,7 @@ namespace vcpkg
Optional<const Json::Object&> get_manifest() const;
Optional<const Path&> get_manifest_path() const;
const Configuration& get_configuration() const;
void set_builtin_baseline(const std::string& baseline) const;
const RegistrySet& get_registry_set() const;
// Retrieve a toolset matching the requirements in prebuildinfo
const Toolset& get_toolset(const Build::PreBuildInfo& prebuildinfo) const;

Просмотреть файл

@ -56,8 +56,7 @@ static Configuration parse_test_configuration(StringView text)
auto object = parse_json_object(text);
Json::Reader reader;
auto deserializer = make_configuration_deserializer("");
auto parsed_config_opt = reader.visit(object, *deserializer);
auto parsed_config_opt = reader.visit(object, get_configuration_deserializer());
REQUIRE(reader.errors().empty());
return std::move(parsed_config_opt).value_or_exit(VCPKG_LINE_INFO);
@ -71,19 +70,12 @@ static void check_string(const Json::Object& obj, StringView key, StringView exp
REQUIRE(value->string() == expected);
}
static void compare_json_objects(const Json::Object& expected, const Json::Object& actual)
{
REQUIRE(Json::stringify(expected, Json::JsonStyle::with_spaces(4)) ==
Json::stringify(actual, Json::JsonStyle::with_spaces(4)));
}
static void check_errors(const std::string& config_text, const std::string& expected_errors)
{
auto object = parse_json_object(config_text);
Json::Reader reader;
auto deserializer = make_configuration_deserializer("");
auto parsed_config_opt = reader.visit(object, *deserializer);
auto parsed_config_opt = reader.visit(object, get_configuration_deserializer());
REQUIRE(!reader.errors().empty());
CHECK_LINES(Strings::join("\n", reader.errors()), expected_errors);
@ -114,6 +106,11 @@ TEST_CASE ("config registries only", "[ce-metadata]")
"kind": "artifact",
"name": "vcpkg-artifacts",
"location": "https://github.com/microsoft/vcpkg-artifacts"
},
{
"kind": "filesystem",
"path": "path/to/registry",
"packages": [ ]
}
]
})json";
@ -121,39 +118,46 @@ TEST_CASE ("config registries only", "[ce-metadata]")
auto config = parse_test_configuration(raw_config);
REQUIRE(config.ce_metadata.is_empty());
REQUIRE(config.extra_info.is_empty());
REQUIRE(config.registry_set.default_registry() != nullptr);
auto default_registry = config.registry_set.default_registry()->serialize();
REQUIRE(config.default_reg.has_value());
auto default_registry = config.default_reg.get()->serialize().object();
check_string(default_registry, KIND, "builtin");
check_string(default_registry, BASELINE, "843e0ba0d8f9c9c572e45564263eedfc7745e74f");
REQUIRE(config.registry_set.registries().size() == 3);
REQUIRE(config.registries.size() == 4);
const auto& git_registry = config.registry_set.registries()[0];
auto serialized_git_registry = git_registry.implementation().serialize();
const auto& git_registry = config.registries[0];
auto serialized_git_registry = git_registry.serialize().object();
check_string(serialized_git_registry, KIND, "git");
check_string(serialized_git_registry, REPOSITORY, "https://github.com/northwindtraders/vcpkg-registry");
check_string(serialized_git_registry, BASELINE, "dacf4de488094a384ca2c202b923ccc097956e0c");
REQUIRE(git_registry.packages().size() == 2);
REQUIRE(git_registry.packages()[0] == "beicode");
REQUIRE(git_registry.packages()[1] == "beison");
REQUIRE(git_registry.packages);
auto&& p = *git_registry.packages.get();
REQUIRE(p.size() == 2);
REQUIRE(p[0] == "beicode");
REQUIRE(p[1] == "beison");
const auto& fs_registry = config.registry_set.registries()[1];
auto serialized_fs_registry = fs_registry.implementation().serialize();
const auto& fs_registry = config.registries[1];
auto serialized_fs_registry = fs_registry.serialize().object();
check_string(serialized_fs_registry, KIND, "filesystem");
check_string(serialized_fs_registry, PATH, "path/to/registry");
REQUIRE(fs_registry.packages().size() == 1);
REQUIRE(fs_registry.packages()[0] == "zlib");
REQUIRE(fs_registry.packages);
REQUIRE(fs_registry.packages.get()->size() == 1);
REQUIRE((*fs_registry.packages.get())[0] == "zlib");
const auto& artifact_registry = config.registry_set.registries()[2];
auto serialized_art_registry = artifact_registry.implementation().serialize();
const auto& artifact_registry = config.registries[2];
auto serialized_art_registry = artifact_registry.serialize().object();
check_string(serialized_art_registry, KIND, "artifact");
check_string(serialized_art_registry, NAME, "vcpkg-artifacts");
check_string(serialized_art_registry, LOCATION, "https://github.com/microsoft/vcpkg-artifacts");
REQUIRE(!artifact_registry.packages);
REQUIRE(config.registries[3].packages);
auto raw_obj = parse_json_object(raw_config);
auto serialized_obj = serialize_configuration(config);
compare_json_objects(raw_obj, serialized_obj);
auto serialized_obj = config.serialize();
Test::check_json_eq(raw_obj, serialized_obj);
}
SECTION ("default invalid json")
@ -165,7 +169,6 @@ TEST_CASE ("config registries only", "[ce-metadata]")
})json";
check_errors(raw_no_baseline, R"(
$.default-registry (a builtin registry): missing required field 'baseline' (a baseline)
$.default-registry (a builtin registry): The baseline field of builtin registries must be a git commit SHA (40 lowercase hex characters)
)");
std::string raw_with_packages = R"json({
@ -187,7 +190,7 @@ $.default-registry (a registry): unexpected field 'packages', did you mean 'path
}
})json";
check_errors(raw_default_artifact, R"(
$ (a configuration object): default-registry cannot be of "artifact" kind
$ (a configuration object): default-registry cannot be of kind "artifact"
)");
std::string raw_bad_kind = R"json({
"registries": [{
@ -223,9 +226,9 @@ $.registries[0] (a registry): missing required field 'packages' (an array of pac
})json";
check_errors(raw_bad_git_registry, R"(
$.registries[0] (a registry): unexpected field 'no-repository', did you mean 'repository'?
$.registries[0] (a git registry): unexpected field 'no-repository', did you mean 'repository'?
$.registries[0] (a git registry): missing required field 'repository' (a git repository URL)
$.registries[0].reference: mismatched type: expected a git reference (for example, a branch)
$.registries[0] (a git registry): unexpected field 'no-repository', did you mean 'repository'?
$.registries[0].packages: mismatched type: expected an array of package names
)");
@ -239,11 +242,11 @@ $.registries[0].packages: mismatched type: expected an array of package names
})json";
check_errors(raw_bad_artifact_registry, R"(
$.registries[0] (a registry): unexpected field 'no-location', did you mean 'location'?
$.registries[0] (an artifacts registry): missing required field 'name' (an identifier)
$.registries[0] (an artifacts registry): missing required field 'location' (an artifacts git repository URL)
$.registries[0] (an artifacts registry): unexpected field 'no-location', did you mean 'location'?
$.registries[0] (an artifacts registry): unexpected field 'baseline', did you mean 'kind'?
$.registries[0] (an artifacts registry): unexpected field 'packages', did you mean 'name'?
$.registries[0] (an artifact registry): missing required field 'name' (an identifier)
$.registries[0] (an artifacts registry): missing required field 'location' (an artifacts git repository URL)
)");
}
}
@ -268,8 +271,8 @@ TEST_CASE ("config ce metadata only", "[ce-metadata]")
})json";
auto config = parse_test_configuration(raw_config);
REQUIRE(!config.registry_set.registries().size());
REQUIRE(config.registry_set.is_default_builtin_registry());
REQUIRE(!config.registries.size());
REQUIRE(config.instantiate_registry_set({})->is_default_builtin_registry());
REQUIRE(!config.extra_info.is_empty());
REQUIRE(config.extra_info.size() == 1);
@ -299,8 +302,8 @@ TEST_CASE ("config ce metadata only", "[ce-metadata]")
REQUIRE(nested.contains("unexpected"));
auto raw_obj = parse_json_object(raw_config);
auto serialized_obj = serialize_configuration(config);
compare_json_objects(raw_obj, serialized_obj);
auto serialized_obj = config.serialize();
Test::check_json_eq(raw_obj, serialized_obj);
}
TEST_CASE ("metadata strings", "[ce-metadata]")
@ -320,7 +323,7 @@ TEST_CASE ("metadata strings", "[ce-metadata]")
check_string(valid_config.ce_metadata, CE_ERROR, "this is a valid error");
auto raw_obj = parse_json_object(valid_raw);
compare_json_objects(raw_obj, serialize_configuration(valid_config));
Test::check_json_eq(raw_obj, valid_config.serialize());
}
SECTION ("invalid json")
@ -383,7 +386,7 @@ TEST_CASE ("metadata dictionaries", "[ce-metadata]")
check_string(settings, "SETTING_2", "value2");
auto raw_obj = parse_json_object(valid_raw);
compare_json_objects(raw_obj, serialize_configuration(valid_config));
Test::check_json_eq(raw_obj, valid_config.serialize());
}
SECTION ("invalid json")
@ -466,7 +469,7 @@ TEST_CASE ("metadata demands", "[ce-metadata]")
check_string(level1, CE_MESSAGE, "this is level 1");
auto raw_obj = parse_json_object(simple_raw);
compare_json_objects(raw_obj, serialize_configuration(config));
Test::check_json_eq(raw_obj, config.serialize());
}
SECTION ("invalid json")
@ -517,7 +520,7 @@ TEST_CASE ("serialize configuration", "[ce-metadata]")
})json";
// parsing of configuration is tested elsewhere
auto config = parse_test_configuration(raw);
compare_json_objects(parse_json_object(raw), serialize_configuration(config));
Test::check_json_eq(parse_json_object(raw), config.serialize());
}
SECTION ("overriden default registry and registries")
@ -538,7 +541,7 @@ TEST_CASE ("serialize configuration", "[ce-metadata]")
})json";
// parsing of configuration is tested elsewhere
auto config = parse_test_configuration(raw);
compare_json_objects(parse_json_object(raw), serialize_configuration(config));
Test::check_json_eq(parse_json_object(raw), config.serialize());
}
SECTION ("only registries")
@ -555,7 +558,7 @@ TEST_CASE ("serialize configuration", "[ce-metadata]")
})json";
// parsing of configuration is tested elsewhere
auto config = parse_test_configuration(raw);
compare_json_objects(parse_json_object(raw), serialize_configuration(config));
Test::check_json_eq(parse_json_object(raw), config.serialize());
}
SECTION ("preserve comments and unexpected fields")
@ -580,7 +583,7 @@ TEST_CASE ("serialize configuration", "[ce-metadata]")
})json";
auto config = parse_test_configuration(raw);
compare_json_objects(parse_json_object(raw), serialize_configuration(config));
Test::check_json_eq(parse_json_object(raw), config.serialize());
auto extra_fields = find_unknown_fields(config);
CHECK(extra_fields.size() == 4);
@ -681,7 +684,7 @@ TEST_CASE ("serialize configuration", "[ce-metadata]")
// demands
// Object values in `demands` are also sorted recursively.
auto config = parse_test_configuration(raw);
compare_json_objects(parse_json_object(formatted), serialize_configuration(config));
Test::check_json_eq(parse_json_object(formatted), config.serialize());
}
}
@ -749,21 +752,22 @@ TEST_CASE ("config with ce metadata full example", "[ce-metadata]")
"}");
auto config = parse_test_configuration(raw_config);
REQUIRE(config.registry_set.default_registry() != nullptr);
REQUIRE(config.default_reg.has_value());
auto default_registry = config.registry_set.default_registry()->serialize();
auto default_registry = config.default_reg.get()->serialize().object();
check_string(default_registry, KIND, "builtin");
check_string(default_registry, BASELINE, "843e0ba0d8f9c9c572e45564263eedfc7745e74f");
REQUIRE(config.registry_set.registries().size() == 1);
const auto& registry = *config.registry_set.registries().begin();
auto serialized_registry = registry.implementation().serialize();
REQUIRE(config.registries.size() == 1);
const auto& registry = *config.registries.begin();
auto serialized_registry = registry.serialize().object();
check_string(serialized_registry, KIND, "git");
check_string(serialized_registry, REPOSITORY, "https://github.com/northwindtraders/vcpkg-registry");
check_string(serialized_registry, BASELINE, "dacf4de488094a384ca2c202b923ccc097956e0c");
REQUIRE(registry.packages().size() == 2);
REQUIRE(registry.packages()[0] == "beicode");
REQUIRE(registry.packages()[1] == "beison");
REQUIRE(registry.packages);
REQUIRE(registry.packages.get()->size() == 2);
REQUIRE(registry.packages.get()->at(0) == "beicode");
REQUIRE(registry.packages.get()->at(1) == "beison");
REQUIRE(!config.extra_info.is_empty());
REQUIRE(config.extra_info.size() == 2);
@ -913,6 +917,6 @@ TEST_CASE ("config with ce metadata full example", "[ce-metadata]")
// finally test serialization is OK
auto raw_obj = parse_json_object(raw_config);
auto serialized_obj = serialize_configuration(config);
compare_json_objects(raw_obj, serialized_obj);
auto serialized_obj = config.serialize();
Test::check_json_eq(raw_obj, serialized_obj);
}

Просмотреть файл

@ -681,10 +681,7 @@ TEST_CASE ("manifest embed configuration", "[manifests]")
auto maybe_as_json = Json::parse(raw);
REQUIRE(maybe_as_json.has_value());
auto as_json = *maybe_as_json.get();
REQUIRE(as_json.first.is_object());
auto as_json_obj = as_json.first.object();
REQUIRE(Json::stringify(serialize_manifest(pgh), Json::JsonStyle::with_spaces(4)) ==
Json::stringify(as_json_obj, Json::JsonStyle::with_spaces(4)));
check_json_eq(Json::Value::object(serialize_manifest(pgh)), as_json.first);
REQUIRE(pgh.core_paragraph->builtin_baseline == "089fa4de7dca22c67dcab631f618d5cd0697c8d4");
REQUIRE(pgh.core_paragraph->dependencies.size() == 3);

Просмотреть файл

@ -2,6 +2,7 @@
#include <vcpkg/base/jsonreader.h>
#include <vcpkg/configuration.h>
#include <vcpkg/registries.h>
using namespace vcpkg;
@ -46,37 +47,48 @@ namespace
TEST_CASE ("registry_set_selects_registry", "[registries]")
{
RegistrySet set;
set.set_default_registry(std::make_unique<TestRegistryImplementation>(0));
{
std::vector<Registry> rs;
rs.push_back(make_registry(1, {"p1", "q1", "r1"}));
rs.push_back(make_registry(2, {"p2", "q2", "r2"}));
RegistrySet set(std::make_unique<TestRegistryImplementation>(0), std::move(rs));
set.add_registry(make_registry(1, {"p1", "q1", "r1"}));
set.add_registry(make_registry(2, {"p2", "q2", "r2"}));
auto reg = set.registry_for_port("p1");
REQUIRE(reg);
CHECK(get_tri_num(*reg) == 1);
reg = set.registry_for_port("r2");
REQUIRE(reg);
CHECK(get_tri_num(*reg) == 2);
reg = set.registry_for_port("a");
REQUIRE(reg);
CHECK(get_tri_num(*reg) == 0);
}
{
std::vector<Registry> rs;
rs.push_back(make_registry(1, {"p1", "q1", "r1"}));
rs.push_back(make_registry(2, {"p2", "q2", "r2"}));
RegistrySet set(nullptr, std::move(rs));
auto reg = set.registry_for_port("p1");
REQUIRE(reg);
CHECK(get_tri_num(*reg) == 1);
reg = set.registry_for_port("r2");
REQUIRE(reg);
CHECK(get_tri_num(*reg) == 2);
reg = set.registry_for_port("a");
REQUIRE(reg);
CHECK(get_tri_num(*reg) == 0);
auto reg = set.registry_for_port("q1");
REQUIRE(reg);
CHECK(get_tri_num(*reg) == 1);
reg = set.registry_for_port("p2");
REQUIRE(reg);
CHECK(get_tri_num(*reg) == 2);
reg = set.registry_for_port("a");
CHECK_FALSE(reg);
}
}
set.set_default_registry(nullptr);
reg = set.registry_for_port("q1");
REQUIRE(reg);
CHECK(get_tri_num(*reg) == 1);
reg = set.registry_for_port("p2");
REQUIRE(reg);
CHECK(get_tri_num(*reg) == 2);
reg = set.registry_for_port("a");
CHECK_FALSE(reg);
static vcpkg::Optional<Configuration> visit_default_registry(Json::Reader& r, Json::Value&& reg)
{
Json::Object config;
config.insert("default-registry", std::move(reg));
return r.visit(config, get_configuration_deserializer());
}
TEST_CASE ("registry_parsing", "[registries]")
{
auto registry_impl_des = get_registry_implementation_deserializer({});
{
Json::Reader r;
auto test_json = parse_json(R"json(
@ -84,7 +96,7 @@ TEST_CASE ("registry_parsing", "[registries]")
"kind": "builtin"
}
)json");
r.visit(test_json, *registry_impl_des);
visit_default_registry(r, std::move(test_json));
CHECK(!r.errors().empty());
}
{
@ -95,8 +107,9 @@ TEST_CASE ("registry_parsing", "[registries]")
"baseline": "hi"
}
)json");
r.visit(test_json, *registry_impl_des);
CHECK(!r.errors().empty());
visit_default_registry(r, std::move(test_json));
// Non-SHA strings are allowed and will be diagnosed later
CHECK(r.errors().empty());
}
{
Json::Reader r;
@ -106,9 +119,8 @@ TEST_CASE ("registry_parsing", "[registries]")
"baseline": "1234567890123456789012345678901234567890"
}
)json");
auto registry_impl = r.visit(test_json, *registry_impl_des);
auto registry_impl = visit_default_registry(r, std::move(test_json));
REQUIRE(registry_impl);
CHECK(*registry_impl.get());
CHECK(r.errors().empty());
}
{
@ -120,7 +132,7 @@ TEST_CASE ("registry_parsing", "[registries]")
"path": "a/b"
}
)json");
r.visit(test_json, *registry_impl_des);
visit_default_registry(r, std::move(test_json));
CHECK(!r.errors().empty());
}
{
@ -131,9 +143,8 @@ TEST_CASE ("registry_parsing", "[registries]")
"path": "a/b/c"
}
)json");
auto registry_impl = r.visit(test_json, *registry_impl_des);
auto registry_impl = visit_default_registry(r, std::move(test_json));
REQUIRE(registry_impl);
CHECK(*registry_impl.get());
CHECK(r.errors().empty());
test_json = parse_json(R"json(
@ -142,9 +153,8 @@ TEST_CASE ("registry_parsing", "[registries]")
"path": "/a/b/c"
}
)json");
registry_impl = r.visit(test_json, *registry_impl_des);
registry_impl = visit_default_registry(r, std::move(test_json));
REQUIRE(registry_impl);
CHECK(*registry_impl.get());
CHECK(r.errors().empty());
}
@ -155,7 +165,7 @@ TEST_CASE ("registry_parsing", "[registries]")
)json");
{
Json::Reader r;
r.visit(test_json, *registry_impl_des);
visit_default_registry(r, std::move(test_json));
CHECK(!r.errors().empty());
}
test_json = parse_json(R"json(
@ -166,7 +176,7 @@ TEST_CASE ("registry_parsing", "[registries]")
)json");
{
Json::Reader r;
r.visit(test_json, *registry_impl_des);
visit_default_registry(r, std::move(test_json));
CHECK(!r.errors().empty());
}
@ -178,7 +188,7 @@ TEST_CASE ("registry_parsing", "[registries]")
)json");
{
Json::Reader r;
r.visit(test_json, *registry_impl_des);
visit_default_registry(r, std::move(test_json));
CHECK(!r.errors().empty());
}
@ -192,9 +202,8 @@ TEST_CASE ("registry_parsing", "[registries]")
)json");
{
Json::Reader r;
auto registry_impl = r.visit(test_json, *registry_impl_des);
auto registry_impl = visit_default_registry(r, std::move(test_json));
REQUIRE(registry_impl);
CHECK(*registry_impl.get());
INFO(Strings::join("\n", r.errors()));
CHECK(r.errors().empty());
}
@ -207,9 +216,8 @@ TEST_CASE ("registry_parsing", "[registries]")
}
)json");
Json::Reader r;
auto registry_impl = r.visit(test_json, *registry_impl_des);
auto registry_impl = visit_default_registry(r, std::move(test_json));
REQUIRE(registry_impl);
CHECK(*registry_impl.get());
INFO(Strings::join("\n", r.errors()));
CHECK(r.errors().empty());
}

Просмотреть файл

@ -10,6 +10,7 @@
#include <iostream>
#include <memory>
#include <set>
#include <vector>
#include <vcpkg-test/util.h>
@ -105,4 +106,84 @@ namespace vcpkg::Test
const static Path BASE_TEMPORARY_DIRECTORY = internal_base_temporary_directory();
return BASE_TEMPORARY_DIRECTORY;
}
static void check_json_eq(const Json::Value& l, const Json::Value& r, std::string& path);
static void check_json_eq(const Json::Object& l, const Json::Object& r, std::string& path)
{
std::set<std::string> keys_l;
for (auto&& kv : l)
{
keys_l.insert(kv.first.to_string());
}
std::set<std::string> keys_r;
for (auto&& kv : r)
{
keys_r.insert(kv.first.to_string());
}
{
INFO(path)
CHECK(keys_l == keys_r);
}
const size_t orig_path_len = path.size();
for (auto&& key : keys_l)
{
auto vl = l.get(key);
auto vr = r.get(key);
if (vl && vr)
{
path.push_back('.');
path.append(key);
check_json_eq(*vl, *vr, path);
path.resize(orig_path_len);
}
}
}
static void check_json_eq(const Json::Array& l, const Json::Array& r, std::string& path)
{
{
INFO(path)
CHECK(l.size() == r.size());
}
const size_t orig_path_len = path.size();
for (size_t i = 0; i < l.size() && i < r.size(); ++i)
{
Strings::append(path, '[', i, ']');
check_json_eq(r[i], l[i], path);
path.resize(orig_path_len);
}
}
static void check_json_eq(const Json::Value& l, const Json::Value& r, std::string& path)
{
if (l.is_object() && r.is_object())
{
check_json_eq(l.object(), r.object(), path);
}
else if (l.is_array() && r.is_array())
{
check_json_eq(l.array(), r.array(), path);
}
else
{
INFO(path);
REQUIRE(l == r);
}
}
void check_json_eq(const Json::Value& l, const Json::Value& r)
{
std::string path = "$";
check_json_eq(l, r, path);
}
void check_json_eq(const Json::Object& l, const Json::Object& r)
{
std::string path = "$";
check_json_eq(l, r, path);
}
void check_json_eq(const Json::Array& l, const Json::Array& r)
{
std::string path = "$";
check_json_eq(l, r, path);
}
}

Просмотреть файл

@ -5,6 +5,8 @@
#include <vcpkg/base/system.print.h>
#include <vcpkg/base/unicode.h>
#include <vcpkg/documentation.h>
#include <inttypes.h>
namespace vcpkg::Json
@ -1425,9 +1427,9 @@ namespace vcpkg::Json
if (!is_ident(sv))
{
r.add_generic_error(type_name(),
"must be lowercase alphanumeric+hyphens and not reserved (see "
"https://github.com/Microsoft/vcpkg/tree/master/docs/specifications/manifests.md for "
"more information)");
Strings::concat("must be lowercase alphanumeric+hyphens and not reserved (see ",
vcpkg::docs::manifests_url,
" for more information)"));
}
return sv.to_string();
}

Просмотреть файл

@ -12,6 +12,7 @@
#include <vcpkg/binarycaching.private.h>
#include <vcpkg/build.h>
#include <vcpkg/dependencies.h>
#include <vcpkg/documentation.h>
#include <vcpkg/metrics.h>
#include <vcpkg/tools.h>
@ -21,11 +22,6 @@ using namespace vcpkg;
namespace
{
static constexpr StringLiteral s_assetcaching_doc_url =
"https://github.com/Microsoft/vcpkg/tree/master/docs/users/assetcaching.md";
static constexpr StringLiteral s_binarycaching_doc_url =
"https://github.com/Microsoft/vcpkg/tree/master/docs/users/binarycaching.md";
struct ConfigSegmentsParser : Parse::ParserBase
{
using Parse::ParserBase::ParserBase;
@ -633,9 +629,9 @@ namespace
res.exit_code != 0)
{
print2(Color::warning,
"One or more NuGet credential providers failed to authenticate. See "
"https://github.com/Microsoft/vcpkg/tree/master/docs/users/binarycaching.md for "
"more details on how to provide credentials.\n");
"One or more NuGet credential providers failed to authenticate. See ",
docs::binarycaching_url,
" for more details on how to provide credentials.\n");
}
else if (res.output.find("for example \"-ApiKey AzureDevOps\"") != std::string::npos)
{
@ -1802,21 +1798,21 @@ ExpectedS<Downloads::DownloadManagerConfig> vcpkg::parse_download_configuration(
parser.parse();
if (auto err = parser.get_error())
{
return Strings::concat(err->format(), "For more information, see ", s_assetcaching_doc_url, "\n");
return Strings::concat(err->format(), "For more information, see ", docs::assetcaching_url, "\n");
}
if (s.azblob_templates_to_put.size() > 1)
{
return Strings::concat("Error: a maximum of one asset write url can be specified\n"
"For more information, see ",
s_assetcaching_doc_url,
docs::assetcaching_url,
"\n");
}
if (s.url_templates_to_get.size() > 1)
{
return Strings::concat("Error: a maximum of one asset read url can be specified\n"
"For more information, see ",
s_assetcaching_doc_url,
docs::assetcaching_url,
"\n");
}
@ -2108,7 +2104,7 @@ void vcpkg::help_topic_asset_caching(const VcpkgPaths&)
tbl.blank();
print2(tbl.m_str);
print2("\nExtended documentation is available at ", s_assetcaching_doc_url, "\n");
print2("\nExtended documentation is available at ", docs::assetcaching_url, "\n");
}
void vcpkg::help_topic_binary_caching(const VcpkgPaths&)
@ -2175,7 +2171,7 @@ void vcpkg::help_topic_binary_caching(const VcpkgPaths&)
"\nThis consults %LOCALAPPDATA%/%APPDATA% on Windows and $XDG_CACHE_HOME or $HOME on other platforms.\n");
}
print2("\nExtended documentation is available at ", s_binarycaching_doc_url, "\n");
print2("\nExtended documentation is available at ", docs::binarycaching_url, "\n");
}
std::string vcpkg::generate_nuget_packages_config(const Dependencies::ActionPlan& action)

Просмотреть файл

@ -18,6 +18,7 @@
#include <vcpkg/commands.h>
#include <vcpkg/commands.version.h>
#include <vcpkg/dependencies.h>
#include <vcpkg/documentation.h>
#include <vcpkg/globalstate.h>
#include <vcpkg/help.h>
#include <vcpkg/input.h>
@ -352,10 +353,7 @@ namespace vcpkg::Build
msg::value = target_architecture,
msg::path = toolset.visual_studio_root_path,
msg::list = toolset_list);
msg::println(
msg::msgSeeURL,
msg::url = StringLiteral(
"https://github.com/microsoft/vcpkg/blob/master/docs/users/triplets.md#VCPKG_VISUAL_STUDIO_PATH"));
msg::println(msg::msgSeeURL, msg::url = docs::vcpkg_visual_studio_path_url);
Checks::exit_maybe_upgrade(VCPKG_LINE_INFO);
}
#endif

Просмотреть файл

@ -9,6 +9,204 @@ namespace
{
using namespace vcpkg;
struct RegistryConfigDeserializer : Json::IDeserializer<RegistryConfig>
{
constexpr static StringLiteral KIND = "kind";
constexpr static StringLiteral BASELINE = "baseline";
constexpr static StringLiteral PATH = "path";
constexpr static StringLiteral REPO = "repository";
constexpr static StringLiteral REFERENCE = "reference";
constexpr static StringLiteral NAME = "name";
constexpr static StringLiteral LOCATION = "location";
constexpr static StringLiteral KIND_BUILTIN = "builtin";
constexpr static StringLiteral KIND_FILESYSTEM = "filesystem";
constexpr static StringLiteral KIND_GIT = "git";
constexpr static StringLiteral KIND_ARTIFACT = "artifact";
virtual StringView type_name() const override { return "a registry"; }
virtual View<StringView> valid_fields() const override;
virtual Optional<RegistryConfig> visit_null(Json::Reader&) override;
virtual Optional<RegistryConfig> visit_object(Json::Reader&, const Json::Object&) override;
static RegistryConfigDeserializer instance;
};
RegistryConfigDeserializer RegistryConfigDeserializer::instance;
constexpr StringLiteral RegistryConfigDeserializer::KIND;
constexpr StringLiteral RegistryConfigDeserializer::BASELINE;
constexpr StringLiteral RegistryConfigDeserializer::PATH;
constexpr StringLiteral RegistryConfigDeserializer::REPO;
constexpr StringLiteral RegistryConfigDeserializer::REFERENCE;
constexpr StringLiteral RegistryConfigDeserializer::NAME;
constexpr StringLiteral RegistryConfigDeserializer::LOCATION;
constexpr StringLiteral RegistryConfigDeserializer::KIND_BUILTIN;
constexpr StringLiteral RegistryConfigDeserializer::KIND_FILESYSTEM;
constexpr StringLiteral RegistryConfigDeserializer::KIND_GIT;
constexpr StringLiteral RegistryConfigDeserializer::KIND_ARTIFACT;
struct RegistryDeserializer final : Json::IDeserializer<RegistryConfig>
{
constexpr static StringLiteral PACKAGES = "packages";
virtual StringView type_name() const override { return "a registry"; }
virtual View<StringView> valid_fields() const override;
virtual Optional<RegistryConfig> visit_object(Json::Reader&, const Json::Object&) override;
static RegistryDeserializer instance;
};
RegistryDeserializer RegistryDeserializer::instance;
constexpr StringLiteral RegistryDeserializer::PACKAGES;
View<StringView> RegistryConfigDeserializer::valid_fields() const
{
static const StringView t[] = {KIND, BASELINE, PATH, REPO, REFERENCE, NAME, LOCATION};
return t;
}
View<StringView> valid_builtin_fields()
{
static const StringView t[] = {
RegistryConfigDeserializer::KIND,
RegistryConfigDeserializer::BASELINE,
RegistryDeserializer::PACKAGES,
};
return t;
}
View<StringView> valid_filesystem_fields()
{
static const StringView t[] = {
RegistryConfigDeserializer::KIND,
RegistryConfigDeserializer::BASELINE,
RegistryConfigDeserializer::PATH,
RegistryDeserializer::PACKAGES,
};
return t;
}
View<StringView> valid_git_fields()
{
static const StringView t[] = {
RegistryConfigDeserializer::KIND,
RegistryConfigDeserializer::BASELINE,
RegistryConfigDeserializer::REPO,
RegistryConfigDeserializer::REFERENCE,
RegistryDeserializer::PACKAGES,
};
return t;
}
View<StringView> valid_artifact_fields()
{
static const StringView t[] = {
RegistryConfigDeserializer::KIND,
RegistryConfigDeserializer::NAME,
RegistryConfigDeserializer::LOCATION,
};
return t;
}
Optional<RegistryConfig> RegistryConfigDeserializer::visit_null(Json::Reader&) { return RegistryConfig(); }
Optional<RegistryConfig> RegistryConfigDeserializer::visit_object(Json::Reader& r, const Json::Object& obj)
{
static Json::StringDeserializer kind_deserializer{"a registry implementation kind"};
static Json::StringDeserializer baseline_deserializer{"a baseline"};
RegistryConfig res;
auto& kind = res.kind.emplace();
r.required_object_field(type_name(), obj, KIND, kind, kind_deserializer);
if (kind == KIND_BUILTIN)
{
auto& baseline = res.baseline.emplace();
r.required_object_field("a builtin registry", obj, BASELINE, baseline, baseline_deserializer);
r.check_for_unexpected_fields(obj, valid_builtin_fields(), "a builtin registry");
}
else if (kind == KIND_FILESYSTEM)
{
std::string baseline;
if (r.optional_object_field(obj, BASELINE, baseline, baseline_deserializer))
{
res.baseline = std::move(baseline);
}
r.required_object_field(
"a filesystem registry", obj, PATH, res.path.emplace(), Json::PathDeserializer::instance);
r.check_for_unexpected_fields(obj, valid_filesystem_fields(), "a filesystem registry");
}
else if (kind == KIND_GIT)
{
static Json::StringDeserializer repo_des{"a git repository URL"};
r.required_object_field("a git registry", obj, REPO, res.repo.emplace(), repo_des);
static Json::StringDeserializer ref_des{"a git reference (for example, a branch)"};
if (!r.optional_object_field(obj, REFERENCE, res.reference.emplace(), ref_des))
{
res.reference = nullopt;
}
r.required_object_field("a git registry", obj, BASELINE, res.baseline.emplace(), baseline_deserializer);
r.check_for_unexpected_fields(obj, valid_git_fields(), "a git registry");
}
else if (kind == KIND_ARTIFACT)
{
r.required_object_field(
"an artifacts registry", obj, NAME, res.name.emplace(), Json::IdentifierDeserializer::instance);
static Json::StringDeserializer location_des{"an artifacts git repository URL"};
r.required_object_field("an artifacts registry", obj, LOCATION, res.location.emplace(), location_des);
r.check_for_unexpected_fields(obj, valid_artifact_fields(), "an artifacts registry");
}
else
{
StringLiteral valid_kinds[] = {KIND_BUILTIN, KIND_FILESYSTEM, KIND_GIT, KIND_ARTIFACT};
r.add_generic_error(type_name(),
"Field \"kind\" did not have an expected value (expected one of: \"",
Strings::join("\", \"", valid_kinds),
"\"; found \"",
kind,
"\")");
return nullopt;
}
return std::move(res); // gcc-7 bug workaround redundant move
}
View<StringView> RegistryDeserializer::valid_fields() const
{
static const StringView t[] = {
RegistryConfigDeserializer::KIND,
RegistryConfigDeserializer::BASELINE,
RegistryConfigDeserializer::PATH,
RegistryConfigDeserializer::REPO,
RegistryConfigDeserializer::REFERENCE,
RegistryConfigDeserializer::NAME,
RegistryConfigDeserializer::LOCATION,
PACKAGES,
};
return t;
}
Optional<RegistryConfig> RegistryDeserializer::visit_object(Json::Reader& r, const Json::Object& obj)
{
auto impl = RegistryConfigDeserializer::instance.visit_object(r, obj);
if (auto config = impl.get())
{
static Json::ArrayDeserializer<Json::PackageNameDeserializer> package_names_deserializer{
"an array of package names"};
if (config->kind && *config->kind.get() != RegistryConfigDeserializer::KIND_ARTIFACT)
{
r.required_object_field(
type_name(), obj, PACKAGES, config->packages.emplace(), package_names_deserializer);
}
}
return impl;
}
struct DictionaryDeserializer final : Json::IDeserializer<Json::Object>
{
virtual StringView type_name() const override { return "a `string: string` dictionary"; }
@ -66,11 +264,9 @@ namespace
virtual Optional<Configuration> visit_object(Json::Reader& r, const Json::Object& obj) override;
ConfigurationDeserializer(const Path& configuration_directory);
private:
Path configuration_directory;
static ConfigurationDeserializer instance;
};
ConfigurationDeserializer ConfigurationDeserializer::instance;
constexpr StringLiteral ConfigurationDeserializer::DEFAULT_REGISTRY;
constexpr StringLiteral ConfigurationDeserializer::REGISTRIES;
@ -186,9 +382,8 @@ namespace
Optional<Configuration> ConfigurationDeserializer::visit_object(Json::Reader& r, const Json::Object& obj)
{
static const StringView ARTIFACT = "artifact";
Json::Object extra_info;
Configuration ret;
Json::Object& extra_info = ret.extra_info;
std::vector<std::string> comment_keys;
for (const auto& el : obj)
@ -201,30 +396,24 @@ namespace
}
}
RegistrySet registries;
auto impl_des = get_registry_implementation_deserializer(configuration_directory);
std::unique_ptr<RegistryImplementation> default_registry;
if (r.optional_object_field(obj, DEFAULT_REGISTRY, default_registry, *impl_des))
RegistryConfig default_registry;
if (r.optional_object_field(obj, DEFAULT_REGISTRY, default_registry, RegistryConfigDeserializer::instance))
{
if (default_registry && default_registry->kind() == ARTIFACT)
if (default_registry.kind.value_or("") == RegistryConfigDeserializer::KIND_ARTIFACT)
{
r.add_generic_error(type_name(), DEFAULT_REGISTRY, " cannot be of \"", ARTIFACT, "\" kind");
r.add_generic_error(type_name(),
DEFAULT_REGISTRY,
" cannot be of kind \"",
RegistryConfigDeserializer::KIND_ARTIFACT,
"\"");
}
registries.set_default_registry(std::move(default_registry));
ret.default_reg = std::move(default_registry);
}
auto reg_des = get_registry_array_deserializer(configuration_directory);
std::vector<Registry> regs;
r.optional_object_field(obj, REGISTRIES, regs, *reg_des);
static Json::ArrayDeserializer<RegistryDeserializer> regs_des("an array of registries");
r.optional_object_field(obj, REGISTRIES, ret.registries, regs_des);
for (Registry& reg : regs)
{
registries.add_registry(std::move(reg));
}
Json::Object ce_metadata_obj;
Json::Object& ce_metadata_obj = ret.ce_metadata;
auto maybe_ce_metadata = r.visit(obj, CeMetadataDeserializer::instance);
if (maybe_ce_metadata.has_value())
{
@ -243,12 +432,7 @@ namespace
ce_metadata_obj.remove(comment_key);
}
return Configuration{std::move(registries), ce_metadata_obj, extra_info};
}
ConfigurationDeserializer::ConfigurationDeserializer(const Path& configuration_directory)
: configuration_directory(configuration_directory)
{
return std::move(ret);
}
static void serialize_ce_metadata(const Json::Object& ce_metadata, Json::Object& put_into)
@ -307,56 +491,6 @@ namespace
serialize_demands(ce_metadata, put_into);
}
static Json::Object serialize_configuration_impl(const Configuration& config)
{
constexpr static StringLiteral REGISTRY_PACKAGES = "packages";
Json::Object obj;
for (const auto& el : config.extra_info)
{
obj.insert(el.first.to_string(), el.second);
}
if (!config.registry_set.is_default_builtin_registry())
{
if (auto default_registry = config.registry_set.default_registry())
{
obj.insert(ConfigurationDeserializer::DEFAULT_REGISTRY, default_registry->serialize());
}
else
{
obj.insert(ConfigurationDeserializer::DEFAULT_REGISTRY, Json::Value::null(nullptr));
}
}
auto reg_view = config.registry_set.registries();
if (reg_view.size() > 0)
{
auto& reg_arr = obj.insert(ConfigurationDeserializer::REGISTRIES, Json::Array());
for (const auto& reg : reg_view)
{
auto reg_obj = reg.implementation().serialize();
if (reg.packages().size())
{
auto& packages = reg_obj.insert(REGISTRY_PACKAGES, Json::Array{});
for (const auto& pkg : reg.packages())
{
packages.push_back(Json::Value::string(pkg));
}
}
reg_arr.push_back(std::move(reg_obj));
}
}
if (!config.ce_metadata.is_empty())
{
serialize_ce_metadata(config.ce_metadata, obj);
}
return obj;
}
static void find_unknown_fields_impl(const Json::Object& obj, std::vector<std::string>& out, StringView path)
{
std::vector<StringView> ret;
@ -420,19 +554,8 @@ namespace vcpkg
return known_fields;
}
void Configuration::validate_feature_flags(const FeatureFlagSettings& flags)
void Configuration::validate_as_active()
{
if (!flags.registries && registry_set.has_modifications())
{
LockGuardPtr<Metrics>(g_metrics)->track_property(
"registries-error-registry-modification-without-feature-flag", "defined");
vcpkg::printf(Color::warning,
"Warning: configuration specified the \"registries\" or \"default-registries\" field, but "
"the %s feature flag was not enabled.\n",
VcpkgCmdArguments::REGISTRIES_FEATURE);
registry_set = RegistrySet();
}
if (!ce_metadata.is_empty())
{
auto unknown_fields = find_unknown_fields(*this);
@ -447,12 +570,114 @@ namespace vcpkg
}
}
std::unique_ptr<Json::IDeserializer<Configuration>> make_configuration_deserializer(const Path& config_directory)
Json::IDeserializer<Configuration>& get_configuration_deserializer() { return ConfigurationDeserializer::instance; }
static std::unique_ptr<RegistryImplementation> instantiate_rconfig(const RegistryConfig& config,
const Path& config_dir)
{
return std::make_unique<ConfigurationDeserializer>(config_directory);
if (auto k = config.kind.get())
{
if (*k == RegistryConfigDeserializer::KIND_BUILTIN)
{
return make_builtin_registry(config.baseline.value_or_exit(VCPKG_LINE_INFO));
}
else if (*k == RegistryConfigDeserializer::KIND_GIT)
{
return make_git_registry(config.repo.value_or_exit(VCPKG_LINE_INFO),
config.reference.value_or("HEAD"),
config.baseline.value_or_exit(VCPKG_LINE_INFO));
}
else if (*k == RegistryConfigDeserializer::KIND_ARTIFACT)
{
return make_artifact_registry(config.name.value_or_exit(VCPKG_LINE_INFO),
config.location.value_or_exit(VCPKG_LINE_INFO));
}
else if (*k == RegistryConfigDeserializer::KIND_FILESYSTEM)
{
return make_filesystem_registry(config_dir / config.path.value_or_exit(VCPKG_LINE_INFO),
config.baseline.value_or(""));
}
else
{
Checks::unreachable(VCPKG_LINE_INFO);
}
}
else
{
return nullptr;
}
}
Json::Object serialize_configuration(const Configuration& config) { return serialize_configuration_impl(config); }
std::unique_ptr<RegistrySet> Configuration::instantiate_registry_set(const Path& config_dir) const
{
std::vector<Registry> r_impls;
for (auto&& reg : registries)
{
// packages will be null for artifact registries
if (auto p = reg.packages.get())
{
r_impls.emplace_back(std::vector<std::string>(*p), instantiate_rconfig(reg, config_dir));
}
}
auto reg1 = default_reg ? instantiate_rconfig(*default_reg.get(), config_dir) : make_builtin_registry();
return std::make_unique<RegistrySet>(std::move(reg1), std::move(r_impls));
}
Json::Object Configuration::serialize() const
{
Json::Object obj;
for (const auto& el : extra_info)
{
obj.insert(el.first.to_string(), el.second);
}
if (auto default_registry = default_reg.get())
{
obj.insert(ConfigurationDeserializer::DEFAULT_REGISTRY, default_registry->serialize());
}
if (!registries.empty())
{
auto& reg_arr = obj.insert(ConfigurationDeserializer::REGISTRIES, Json::Array());
for (const auto& reg : registries)
{
reg_arr.push_back(reg.serialize());
}
}
if (!ce_metadata.is_empty())
{
serialize_ce_metadata(ce_metadata, obj);
}
return obj;
}
Json::Value RegistryConfig::serialize() const
{
if (!kind)
{
return Json::Value::null(nullptr);
}
Json::Object obj;
obj.insert(RegistryConfigDeserializer::KIND, Json::Value::string(*kind.get()));
if (auto p = baseline.get()) obj.insert(RegistryConfigDeserializer::BASELINE, Json::Value::string(*p));
if (auto p = location.get()) obj.insert(RegistryConfigDeserializer::LOCATION, Json::Value::string(*p));
if (auto p = name.get()) obj.insert(RegistryConfigDeserializer::NAME, Json::Value::string(*p));
if (auto p = path.get()) obj.insert(RegistryConfigDeserializer::PATH, Json::Value::string(p->native()));
if (auto p = reference.get()) obj.insert(RegistryConfigDeserializer::REFERENCE, Json::Value::string(*p));
if (auto p = repo.get()) obj.insert(RegistryConfigDeserializer::REPO, Json::Value::string(*p));
if (packages)
{
auto& arr = obj.insert(RegistryDeserializer::PACKAGES, Json::Array());
for (auto&& p : *packages.get())
{
arr.push_back(Json::Value::string(p));
}
}
return Json::Value::object(std::move(obj));
}
std::vector<std::string> find_unknown_fields(const Configuration& config)
{

Просмотреть файл

@ -9,6 +9,7 @@
#include <vcpkg/commands.list.h>
#include <vcpkg/commands.owns.h>
#include <vcpkg/commands.search.h>
#include <vcpkg/documentation.h>
#include <vcpkg/export.h>
#include <vcpkg/help.h>
#include <vcpkg/install.h>
@ -112,9 +113,7 @@ namespace vcpkg::Help
{ "name": "rapidjson", "version": "2020-09-14" }
]
})");
print2(tbl.m_str,
"\nExtended documentation is available at "
"https://github.com/Microsoft/vcpkg/tree/master/docs/users/versioning.md\n");
print2(tbl.m_str, "\nExtended documentation is available at ", docs::versioning_url, "\n");
}
static constexpr std::array<Topic, 17> topics = {{

Просмотреть файл

@ -10,6 +10,7 @@
#include <vcpkg/commands.setinstalled.h>
#include <vcpkg/configuration.h>
#include <vcpkg/dependencies.h>
#include <vcpkg/documentation.h>
#include <vcpkg/globalstate.h>
#include <vcpkg/help.h>
#include <vcpkg/input.h>
@ -851,17 +852,14 @@ namespace vcpkg::Install
if (!maybe_manifest_scf)
{
print_error_message(maybe_manifest_scf.error());
print2("See https://github.com/Microsoft/vcpkg/tree/master/docs/users/manifests.md for "
"more information.\n");
print2("See ", docs::manifests_url, " for more information.\n");
Checks::exit_fail(VCPKG_LINE_INFO);
}
auto& manifest_scf = *maybe_manifest_scf.value_or_exit(VCPKG_LINE_INFO);
if (auto maybe_error = manifest_scf.check_against_feature_flags(
manifest_path,
paths.get_feature_flags(),
paths.get_configuration().registry_set.is_default_builtin_registry()))
manifest_path, paths.get_feature_flags(), paths.get_registry_set().is_default_builtin_registry()))
{
Checks::exit_with_message(VCPKG_LINE_INFO, maybe_error.value_or_exit(VCPKG_LINE_INFO));
}
@ -928,8 +926,7 @@ namespace vcpkg::Install
extended_overlay_ports.reserve(args.overlay_ports.size() + 2);
extended_overlay_ports.push_back(manifest_path.parent_path().to_string());
Util::Vectors::append(&extended_overlay_ports, args.overlay_ports);
if (paths.get_configuration().registry_set.is_default_builtin_registry() &&
!paths.use_git_default_registry())
if (paths.get_registry_set().is_default_builtin_registry() && !paths.use_git_default_registry())
{
extended_overlay_ports.push_back(paths.builtin_ports_directory().native());
}

Просмотреть файл

@ -412,7 +412,7 @@ namespace vcpkg::Paragraphs
std::vector<std::string> ports;
const auto& registries = paths.get_configuration().registry_set;
const auto& registries = paths.get_registry_set();
for (const auto& registry : registries.registries())
{

Просмотреть файл

@ -107,7 +107,7 @@ namespace vcpkg::PortFileProvider
}
else
{
auto version = paths.get_configuration().registry_set.baseline_for_port(paths, port_name);
auto version = paths.get_registry_set().baseline_for_port(paths, port_name);
m_baseline_cache.emplace(port_name.to_string(), version);
return version;
}
@ -129,7 +129,7 @@ namespace vcpkg::PortFileProvider
auto entry_it = m_entry_cache.find(name);
if (entry_it == m_entry_cache.end())
{
if (auto reg = paths.get_configuration().registry_set.registry_for_port(name))
if (auto reg = paths.get_registry_set().registry_for_port(name))
{
if (auto entry = reg->get_port_entry(paths, name))
{

Просмотреть файл

@ -64,8 +64,6 @@ namespace
Optional<VersionT> get_baseline_version(const VcpkgPaths&, StringView) const override;
Json::Object serialize() const override;
private:
friend struct GitRegistryEntry;
@ -231,8 +229,6 @@ namespace
return paths.builtin_ports_directory() / port_name;
}
Json::Object serialize() const override;
~BuiltinFilesRegistry() = default;
DelayedInit<Baseline> m_baseline;
@ -266,8 +262,6 @@ namespace
Optional<VersionT> get_baseline_version(const VcpkgPaths& paths, StringView port_name) const override;
Json::Object serialize() const override;
~BuiltinGitRegistry() = default;
std::string m_baseline_identifier;
@ -292,7 +286,7 @@ namespace
struct FilesystemRegistry final : RegistryImplementation
{
FilesystemRegistry(Path&& path, std::string&& baseline)
: m_path(std::move(path)), m_baseline_identifier(baseline)
: m_path(std::move(path)), m_baseline_identifier(std::move(baseline))
{
}
@ -304,8 +298,6 @@ namespace
Optional<VersionT> get_baseline_version(const VcpkgPaths&, StringView) const override;
Json::Object serialize() const override;
private:
Path m_path;
std::string m_baseline_identifier;
@ -336,8 +328,6 @@ namespace
Checks::exit_fail(VCPKG_LINE_INFO);
}
Json::Object serialize() const override;
~ArtifactRegistry() = default;
private:
@ -922,228 +912,6 @@ namespace
};
BaselineDeserializer BaselineDeserializer::instance;
struct RegistryImplDeserializer : Json::IDeserializer<std::unique_ptr<RegistryImplementation>>
{
constexpr static StringLiteral KIND = "kind";
constexpr static StringLiteral BASELINE = "baseline";
constexpr static StringLiteral PATH = "path";
constexpr static StringLiteral REPO = "repository";
constexpr static StringLiteral REFERENCE = "reference";
constexpr static StringLiteral NAME = "name";
constexpr static StringLiteral LOCATION = "location";
constexpr static StringLiteral KIND_BUILTIN = "builtin";
constexpr static StringLiteral KIND_FILESYSTEM = "filesystem";
constexpr static StringLiteral KIND_GIT = "git";
constexpr static StringLiteral KIND_ARTIFACT = "artifact";
virtual StringView type_name() const override { return "a registry"; }
virtual View<StringView> valid_fields() const override;
virtual Optional<std::unique_ptr<RegistryImplementation>> visit_null(Json::Reader&) override;
virtual Optional<std::unique_ptr<RegistryImplementation>> visit_object(Json::Reader&,
const Json::Object&) override;
RegistryImplDeserializer(const Path& configuration_directory) : config_directory(configuration_directory) { }
Path config_directory;
};
constexpr StringLiteral RegistryImplDeserializer::KIND;
constexpr StringLiteral RegistryImplDeserializer::BASELINE;
constexpr StringLiteral RegistryImplDeserializer::PATH;
constexpr StringLiteral RegistryImplDeserializer::REPO;
constexpr StringLiteral RegistryImplDeserializer::REFERENCE;
constexpr StringLiteral RegistryImplDeserializer::NAME;
constexpr StringLiteral RegistryImplDeserializer::LOCATION;
constexpr StringLiteral RegistryImplDeserializer::KIND_BUILTIN;
constexpr StringLiteral RegistryImplDeserializer::KIND_FILESYSTEM;
constexpr StringLiteral RegistryImplDeserializer::KIND_GIT;
constexpr StringLiteral RegistryImplDeserializer::KIND_ARTIFACT;
struct RegistryDeserializer final : Json::IDeserializer<Registry>
{
constexpr static StringLiteral PACKAGES = "packages";
virtual StringView type_name() const override { return "a registry"; }
virtual View<StringView> valid_fields() const override;
virtual Optional<Registry> visit_object(Json::Reader&, const Json::Object&) override;
explicit RegistryDeserializer(const Path& configuration_directory) : impl_des(configuration_directory) { }
RegistryImplDeserializer impl_des;
};
constexpr StringLiteral RegistryDeserializer::PACKAGES;
View<StringView> RegistryImplDeserializer::valid_fields() const
{
static const StringView t[] = {KIND, BASELINE, PATH, REPO, REFERENCE, NAME, LOCATION};
return t;
}
View<StringView> valid_builtin_fields()
{
static const StringView t[] = {
RegistryImplDeserializer::KIND,
RegistryImplDeserializer::BASELINE,
RegistryDeserializer::PACKAGES,
};
return t;
}
View<StringView> valid_filesystem_fields()
{
static const StringView t[] = {
RegistryImplDeserializer::KIND,
RegistryImplDeserializer::BASELINE,
RegistryImplDeserializer::PATH,
RegistryDeserializer::PACKAGES,
};
return t;
}
View<StringView> valid_git_fields()
{
static const StringView t[] = {
RegistryImplDeserializer::KIND,
RegistryImplDeserializer::BASELINE,
RegistryImplDeserializer::REPO,
RegistryImplDeserializer::REFERENCE,
RegistryDeserializer::PACKAGES,
};
return t;
}
View<StringView> valid_artifact_fields()
{
static const StringView t[] = {
RegistryImplDeserializer::KIND,
RegistryImplDeserializer::NAME,
RegistryImplDeserializer::LOCATION,
};
return t;
}
Optional<std::unique_ptr<RegistryImplementation>> RegistryImplDeserializer::visit_null(Json::Reader&)
{
return nullptr;
}
Optional<std::unique_ptr<RegistryImplementation>> RegistryImplDeserializer::visit_object(Json::Reader& r,
const Json::Object& obj)
{
static Json::StringDeserializer kind_deserializer{"a registry implementation kind"};
static Json::StringDeserializer baseline_deserializer{"a baseline"};
std::string kind;
r.required_object_field(type_name(), obj, KIND, kind, kind_deserializer);
std::unique_ptr<RegistryImplementation> res;
if (kind == KIND_BUILTIN)
{
std::string baseline;
r.required_object_field("a builtin registry", obj, BASELINE, baseline, baseline_deserializer);
if (!is_git_commit_sha(baseline))
{
r.add_generic_error(
"a builtin registry",
"The baseline field of builtin registries must be a git commit SHA (40 lowercase hex characters)");
}
r.check_for_unexpected_fields(obj, valid_builtin_fields(), "a builtin registry");
res = std::make_unique<BuiltinGitRegistry>(std::move(baseline));
}
else if (kind == KIND_FILESYSTEM)
{
std::string baseline;
r.optional_object_field(obj, BASELINE, baseline, baseline_deserializer);
r.check_for_unexpected_fields(obj, valid_filesystem_fields(), "a filesystem registry");
Path p;
r.required_object_field("a filesystem registry", obj, PATH, p, Json::PathDeserializer::instance);
res = std::make_unique<FilesystemRegistry>(config_directory / p, std::move(baseline));
}
else if (kind == KIND_GIT)
{
r.check_for_unexpected_fields(obj, valid_git_fields(), "a git registry");
std::string repo;
Json::StringDeserializer repo_des{"a git repository URL"};
r.required_object_field("a git registry", obj, REPO, repo, repo_des);
std::string ref;
Json::StringDeserializer ref_des{"a git reference (for example, a branch)"};
if (!r.optional_object_field(obj, REFERENCE, ref, ref_des))
{
ref = "HEAD";
}
std::string baseline;
r.required_object_field("a git registry", obj, BASELINE, baseline, baseline_deserializer);
res = std::make_unique<GitRegistry>(std::move(repo), std::move(ref), std::move(baseline));
}
else if (kind == KIND_ARTIFACT)
{
r.check_for_unexpected_fields(obj, valid_artifact_fields(), "an artifacts registry");
std::string name;
r.required_object_field("an artifact registry", obj, NAME, name, Json::IdentifierDeserializer::instance);
std::string location;
Json::StringDeserializer location_des{"an artifacts git repository URL"};
r.required_object_field("an artifacts registry", obj, LOCATION, location, location_des);
res = std::make_unique<ArtifactRegistry>(std::move(name), std::move(location));
}
else
{
StringLiteral valid_kinds[] = {KIND_BUILTIN, KIND_FILESYSTEM, KIND_GIT, KIND_ARTIFACT};
r.add_generic_error(type_name(),
"Field \"kind\" did not have an expected value (expected one of: \"",
Strings::join("\", \"", valid_kinds),
"\"; found \"",
kind,
"\")");
return nullopt;
}
return std::move(res); // gcc-7 bug workaround redundant move
}
View<StringView> RegistryDeserializer::valid_fields() const
{
static const StringView t[] = {
RegistryImplDeserializer::KIND,
RegistryImplDeserializer::BASELINE,
RegistryImplDeserializer::PATH,
RegistryImplDeserializer::REPO,
RegistryImplDeserializer::REFERENCE,
RegistryImplDeserializer::NAME,
RegistryImplDeserializer::LOCATION,
PACKAGES,
};
return t;
}
Optional<Registry> RegistryDeserializer::visit_object(Json::Reader& r, const Json::Object& obj)
{
auto impl = impl_des.visit_object(r, obj);
if (!impl.has_value())
{
return nullopt;
}
static Json::ArrayDeserializer<Json::PackageNameDeserializer> package_names_deserializer{
"an array of package names"};
std::vector<std::string> packages;
if (impl.get()->get()->kind() != RegistryImplDeserializer::KIND_ARTIFACT)
{
r.required_object_field(type_name(), obj, PACKAGES, packages, package_names_deserializer);
}
return Registry{std::move(packages), std::move(impl).value_or_exit(VCPKG_LINE_INFO)};
}
Path relative_path_to_versions(StringView port_name)
{
char prefix[] = {port_name.byte_at_index(0), '-', '\0'};
@ -1285,57 +1053,6 @@ Optional<Path> RegistryImplementation::get_path_to_baseline_version(const VcpkgP
return nullopt;
}
// serializers
Json::Object RegistryImplementation::serialize() const
{
Json::Object obj;
obj.insert(RegistryImplDeserializer::KIND, Json::Value::string(kind()));
return obj;
}
Json::Object BuiltinGitRegistry::serialize() const
{
Json::Object obj;
obj.insert(RegistryImplDeserializer::KIND, Json::Value::string("builtin"));
obj.insert(RegistryImplDeserializer::BASELINE, Json::Value::string(m_baseline_identifier));
return obj;
}
Json::Object BuiltinFilesRegistry::serialize() const
{
Json::Object obj;
obj.insert(RegistryImplDeserializer::KIND, Json::Value::string("builtin"));
return obj;
}
Json::Object GitRegistry::serialize() const
{
Json::Object obj{RegistryImplementation::serialize()};
obj.insert(RegistryImplDeserializer::REPO, Json::Value::string(m_repo));
obj.insert(RegistryImplDeserializer::BASELINE, Json::Value::string(m_baseline_identifier));
return obj;
}
Json::Object FilesystemRegistry::serialize() const
{
Json::Object obj{RegistryImplementation::serialize()};
obj.insert(RegistryImplDeserializer::PATH, Json::Value::string(m_path.generic_u8string()));
if (!m_baseline_identifier.empty())
{
obj.insert(RegistryImplDeserializer::BASELINE, Json::Value::string(m_baseline_identifier));
}
return obj;
}
Json::Object ArtifactRegistry::serialize() const
{
Json::Object obj{RegistryImplementation::serialize()};
obj.insert(RegistryImplDeserializer::NAME, Json::Value::string(m_name));
obj.insert(RegistryImplDeserializer::LOCATION, Json::Value::string(m_location));
return obj;
}
namespace vcpkg
{
constexpr StringLiteral VersionDbEntryDeserializer::GIT_TREE;
@ -1486,26 +1203,12 @@ namespace vcpkg
}
}
std::unique_ptr<Json::IDeserializer<std::unique_ptr<RegistryImplementation>>>
get_registry_implementation_deserializer(const Path& configuration_directory)
{
return std::make_unique<RegistryImplDeserializer>(configuration_directory);
}
std::unique_ptr<Json::IDeserializer<std::vector<Registry>>> get_registry_array_deserializer(
const Path& configuration_directory)
{
return std::make_unique<Json::ArrayDeserializer<RegistryDeserializer>>(
"an array of registries", RegistryDeserializer(configuration_directory));
}
Registry::Registry(std::vector<std::string>&& packages, std::unique_ptr<RegistryImplementation>&& impl)
: packages_(std::move(packages)), implementation_(std::move(impl))
{
Checks::check_exit(VCPKG_LINE_INFO, implementation_ != nullptr);
}
RegistrySet::RegistrySet() : default_registry_(std::make_unique<BuiltinFilesRegistry>()) { }
const RegistryImplementation* RegistrySet::registry_for_port(StringView name) const
{
for (const auto& registry : registries())
@ -1526,50 +1229,10 @@ namespace vcpkg
return impl->get_baseline_version(paths, port_name);
}
void RegistrySet::add_registry(Registry&& r) { registries_.push_back(std::move(r)); }
void RegistrySet::set_default_registry(std::unique_ptr<RegistryImplementation>&& r)
{
default_registry_ = std::move(r);
}
void RegistrySet::set_default_registry(std::nullptr_t) { default_registry_.reset(); }
bool RegistrySet::is_default_builtin_registry() const
{
return default_registry_ && default_registry_->kind() == BuiltinFilesRegistry::s_kind;
}
void RegistrySet::set_default_builtin_registry_baseline(StringView baseline)
{
if (auto default_registry = default_registry_.get())
{
const auto k = default_registry->kind();
if (k == BuiltinFilesRegistry::s_kind)
{
default_registry_ = std::make_unique<BuiltinGitRegistry>(baseline.to_string());
}
else if (k == BuiltinGitRegistry::s_kind)
{
print2(Color::warning,
R"(warning: attempting to set builtin baseline in both vcpkg.json and vcpkg-configuration.json
(only one of these should be used; the baseline from vcpkg-configuration.json will be used))");
}
else
{
vcpkg::printf(
Color::warning,
"warning: the default registry has been replaced with a %s registry, but `builtin-baseline` "
"is specified in vcpkg.json. This field will have no effect.\n",
k);
}
}
else
{
print2(Color::warning,
"warning: the default registry has been disabled, but `builtin-baseline` is specified in "
"vcpkg.json. This field will have no effect.\n");
}
}
bool RegistrySet::has_modifications() const { return !registries_.empty() || !is_default_builtin_registry(); }
ExpectedS<std::vector<std::pair<SchemedVersion, std::string>>> get_builtin_versions(const VcpkgPaths& paths,
@ -1610,4 +1273,25 @@ namespace vcpkg
return sv.size() == 40 && std::all_of(sv.begin(), sv.end(), is_lcase_ascii_hex);
}
std::unique_ptr<RegistryImplementation> make_builtin_registry() { return std::make_unique<BuiltinFilesRegistry>(); }
std::unique_ptr<RegistryImplementation> make_builtin_registry(std::string baseline)
{
return std::make_unique<BuiltinGitRegistry>(std::move(baseline));
}
std::unique_ptr<RegistryImplementation> make_git_registry(std::string repo,
std::string reference,
std::string baseline)
{
return std::make_unique<GitRegistry>(std::move(repo), std::move(reference), std::move(baseline));
}
std::unique_ptr<RegistryImplementation> make_filesystem_registry(Path path, std::string baseline)
{
return std::make_unique<FilesystemRegistry>(std::move(path), std::move(baseline));
}
std::unique_ptr<RegistryImplementation> make_artifact_registry(std::string name, std::string location)
{
return std::make_unique<ArtifactRegistry>(std::move(name), std::move(location));
}
}

Просмотреть файл

@ -7,6 +7,7 @@
#include <vcpkg/base/util.h>
#include <vcpkg/configuration.h>
#include <vcpkg/documentation.h>
#include <vcpkg/metrics.h>
#include <vcpkg/packagespec.h>
#include <vcpkg/platform-expression.h>
@ -993,6 +994,61 @@ namespace vcpkg
constexpr StringLiteral ManifestDeserializer::BUILTIN_BASELINE;
constexpr StringLiteral ManifestDeserializer::VCPKG_CONFIGURATION;
// Extracts just the configuration information from a manifest object
struct ManifestConfigurationDeserializer final : Json::IDeserializer<ManifestConfiguration>
{
virtual StringView type_name() const override { return "a manifest"; }
virtual Optional<ManifestConfiguration> visit_object(Json::Reader& r, const Json::Object& obj) override
{
Optional<ManifestConfiguration> x;
ManifestConfiguration& ret = x.emplace();
if (!r.optional_object_field(obj,
ManifestDeserializer::VCPKG_CONFIGURATION,
ret.config.emplace(),
get_configuration_deserializer()))
{
ret.config = nullopt;
}
if (!r.optional_object_field(obj,
ManifestDeserializer::BUILTIN_BASELINE,
ret.builtin_baseline.emplace(),
BaselineCommitDeserializer::instance))
{
ret.builtin_baseline = nullopt;
}
return x;
}
static ManifestConfigurationDeserializer instance;
};
ManifestConfigurationDeserializer ManifestConfigurationDeserializer::instance;
ExpectedS<struct ManifestConfiguration> parse_manifest_configuration(StringView origin,
const Json::Object& manifest)
{
Json::Reader reader;
auto res = reader.visit(manifest, ManifestConfigurationDeserializer::instance);
if (!reader.errors().empty())
{
std::string ret = "Error: in the manifest ";
Strings::append(ret, origin, "\nwhile obtaining configuration information from the manifest:\n");
for (auto&& err : reader.errors())
{
Strings::append(ret, " ", err, "\n");
}
print2("See ", docs::registries_url, " for more information.\n");
print2("See ", docs::manifests_url, " for more information.\n");
return std::move(ret);
}
else
{
return std::move(res).value_or_exit(VCPKG_LINE_INFO);
}
}
SourceControlFile SourceControlFile::clone() const
{
SourceControlFile ret;
@ -1370,19 +1426,18 @@ namespace vcpkg
if (auto configuration = scf.core_paragraph->vcpkg_configuration.get())
{
Json::Reader reader;
auto maybe_configuration = reader.visit(*configuration, *vcpkg::make_configuration_deserializer(""));
auto maybe_configuration = reader.visit(*configuration, get_configuration_deserializer());
if (!reader.errors().empty())
{
print2(Color::error, "Errors occurred while parsing ", ManifestDeserializer::VCPKG_CONFIGURATION, "\n");
for (auto&& msg : reader.errors())
print2(" ", msg, '\n');
print2("See https://github.com/Microsoft/vcpkg/tree/master/docs/users/registries.md for "
"more information.\n");
print2("See ", docs::registries_url, " for more information.\n");
Checks::exit_fail(VCPKG_LINE_INFO);
}
obj.insert(ManifestDeserializer::VCPKG_CONFIGURATION,
serialize_configuration(maybe_configuration.value_or_exit(VCPKG_LINE_INFO)));
maybe_configuration.value_or_exit(VCPKG_LINE_INFO).serialize());
}
obj.insert(ManifestDeserializer::NAME, Json::Value::string(scf.core_paragraph->name));

Просмотреть файл

@ -15,6 +15,7 @@
#include <vcpkg/commands.h>
#include <vcpkg/commands.version.h>
#include <vcpkg/configuration.h>
#include <vcpkg/documentation.h>
#include <vcpkg/globalstate.h>
#include <vcpkg/metrics.h>
#include <vcpkg/packagespec.h>
@ -57,36 +58,6 @@ namespace
namespace vcpkg
{
static Configuration deserialize_configuration(const Json::Object& obj,
const VcpkgCmdArguments& args,
const Path& filepath)
{
Json::Reader reader;
auto deserializer = make_configuration_deserializer(filepath.parent_path());
auto parsed_config_opt = reader.visit(obj, *deserializer);
if (!reader.errors().empty())
{
print2(Color::error, "Errors occurred while parsing ", filepath, "\n");
for (auto&& msg : reader.errors())
print2(" ", msg, '\n');
print2("See https://github.com/Microsoft/vcpkg/tree/master/docs/users/registries.md for "
"more information.\n");
Checks::exit_fail(VCPKG_LINE_INFO);
}
parsed_config_opt.get()->validate_feature_flags(args.feature_flag_settings());
return std::move(parsed_config_opt).value_or_exit(VCPKG_LINE_INFO);
}
struct ManifestAndConfig
{
Path config_directory;
Configuration config;
};
static std::pair<Json::Object, Json::JsonStyle> load_manifest(const Filesystem& fs, const Path& manifest_dir)
{
std::error_code ec;
@ -116,69 +87,129 @@ namespace vcpkg
return {std::move(manifest_value.first.object()), std::move(manifest_value.second)};
}
struct ConfigAndPath
static Optional<ManifestConfiguration> config_from_manifest(
const Path& manifest_path, const Optional<std::pair<Json::Object, Json::JsonStyle>>& manifest_doc)
{
Path config_directory;
Configuration config;
};
if (auto manifest = manifest_doc.get())
{
return parse_manifest_configuration(manifest_path, manifest->first).value_or_exit(VCPKG_LINE_INFO);
}
return nullopt;
}
// doesn't yet implement searching upwards for configurations, nor inheritance of configurations
static ConfigAndPath load_configuration(const Filesystem& fs,
const VcpkgCmdArguments& args,
const Path& vcpkg_root,
const Path& manifest_dir,
const Optional<Json::Object>& configuration_from_manifest)
static Optional<Configuration> config_from_json(const Path& config_path, const Filesystem& fs)
{
Path config_dir;
if (manifest_dir.empty())
if (!fs.exists(config_path, VCPKG_LINE_INFO))
{
// classic mode
config_dir = vcpkg_root;
}
else
{
// manifest mode
config_dir = manifest_dir;
return nullopt;
}
auto path_to_config = config_dir / "vcpkg-configuration.json";
if (!fs.exists(path_to_config, IgnoreErrors{}))
{
if (!configuration_from_manifest.has_value())
{
return {};
}
return {std::move(config_dir),
deserialize_configuration(
configuration_from_manifest.value_or_exit(VCPKG_LINE_INFO), args, manifest_dir / "vcpkg.json")};
}
if (configuration_from_manifest.has_value())
{
print2(Color::error,
"Ambiguous vcpkg configuration provided by both manifest and configuration file.\n"
"-- Delete configuration file \"",
path_to_config,
"\"\n"
"-- Or remove \"vcpkg-configuration\" from the manifest file \"",
manifest_dir / "vcpkg.json",
"\".");
Checks::exit_fail(VCPKG_LINE_INFO);
}
auto parsed_config = Json::parse_file(VCPKG_LINE_INFO, fs, path_to_config);
auto parsed_config = Json::parse_file(VCPKG_LINE_INFO, fs, config_path);
if (!parsed_config.first.is_object())
{
print2(Color::error,
"Failed to parse ",
path_to_config,
": configuration files must have a top-level object\n");
print2(
Color::error, "Failed to parse ", config_path, ": configuration files must have a top-level object\n");
msg::println(Color::error, msg::msgSeeURL, msg::url = docs::registries_url);
Checks::exit_fail(VCPKG_LINE_INFO);
}
auto config_obj = std::move(parsed_config.first.object());
const auto& obj = parsed_config.first.object();
return {std::move(config_dir), deserialize_configuration(config_obj, args, path_to_config)};
Json::Reader reader;
auto parsed_config_opt = reader.visit(obj, get_configuration_deserializer());
if (!reader.errors().empty())
{
print2(Color::error, "Error: while parsing ", config_path, "\n");
for (auto&& msg : reader.errors())
print2(" ", msg, '\n');
print2("See ", docs::registries_url, " for more information.\n");
Checks::exit_fail(VCPKG_LINE_INFO);
}
return parsed_config_opt;
}
static Configuration merge_validate_configs(Optional<ManifestConfiguration>&& manifest_data,
const Path& manifest_dir,
Optional<Configuration>&& config_data,
const Path& config_dir,
const VcpkgPaths& paths)
{
Configuration ret;
if (auto manifest = manifest_data.get())
{
if (auto config = manifest->config.get())
{
print2(Color::warning,
"Embedding `vcpkg-configuration` in a manifest file is an EXPERIMENTAL feature.\n");
if (manifest->builtin_baseline && config->default_reg)
{
print2(Color::error,
"Error: Specifying vcpkg-configuration.default-registry in a manifest file conflicts with "
"builtin-baseline.\nPlease remove one of these conflicting settings.\n");
Checks::exit_fail(VCPKG_LINE_INFO);
}
config->validate_as_active();
if (config_data.has_value())
{
print2(Color::error,
"Ambiguous vcpkg configuration provided by both manifest and configuration file.\n"
"-- Delete configuration file \"",
config_dir / "vcpkg-configuration.json",
"\"\n"
"-- Or remove \"vcpkg-configuration\" from the manifest file \"",
manifest_dir / "vcpkg.json",
"\".");
Checks::exit_fail(VCPKG_LINE_INFO);
}
ret = std::move(*config);
}
}
if (auto config = config_data.get())
{
config->validate_as_active();
ret = std::move(*config);
}
if (auto manifest = manifest_data.get())
{
if (auto p_baseline = manifest->builtin_baseline.get())
{
LockGuardPtr<Metrics>(g_metrics)->track_property("manifest_baseline", "defined");
if (!is_git_commit_sha(*p_baseline))
{
LockGuardPtr<Metrics>(g_metrics)->track_property("versioning-error-baseline", "defined");
Checks::exit_maybe_upgrade(VCPKG_LINE_INFO,
"Error: the top-level builtin-baseline%s was not a valid commit sha: "
"expected 40 lowercase hexadecimal characters.\n%s\n",
Strings::concat(" (", *p_baseline, ')'),
paths.get_current_git_sha_baseline_message());
}
if (ret.default_reg)
{
print2(Color::warning,
"warning: attempting to set builtin-baseline in vcpkg.json while overriding the "
"default-registry in vcpkg-configuration.json.\n The default-registry from "
"vcpkg-configuration.json will be used.");
}
else
{
auto& default_reg = ret.default_reg.emplace();
default_reg.kind = "builtin";
default_reg.baseline = std::move(*p_baseline);
}
}
}
return ret;
}
namespace details
@ -265,7 +296,9 @@ namespace vcpkg
Optional<std::pair<Json::Object, Json::JsonStyle>> m_manifest_doc;
Path m_manifest_path;
Path m_config_dir;
Configuration m_config;
std::unique_ptr<RegistrySet> m_registry_set;
Downloads::DownloadManager m_download_manager;
@ -448,6 +481,7 @@ namespace vcpkg
if (manifest_root_dir.empty())
{
m_pimpl->m_config_dir = root;
if (!m_pimpl->m_readonly)
{
m_pimpl->installed =
@ -458,6 +492,7 @@ namespace vcpkg
{
Debug::print("Using manifest-root: ", manifest_root_dir, '\n');
m_pimpl->m_config_dir = manifest_root_dir;
m_pimpl->installed = process_output_directory(
filesystem, args.install_root_dir.get(), manifest_root_dir / "vcpkg_installed");
@ -486,59 +521,23 @@ namespace vcpkg
m_pimpl->m_manifest_path = manifest_root_dir / "vcpkg.json";
}
vcpkg::Optional<Json::Object> configuration_from_manifest;
if (auto manifest = m_pimpl->m_manifest_doc.get())
{
auto manifest_obj = manifest->first;
if (auto config_obj = manifest_obj.get("vcpkg-configuration"))
{
print2(Color::warning,
"Embedding `vcpkg-configuration` in a manifest file is an EXPERIMENTAL feature.\n"
"Loading configuration from: ",
m_pimpl->m_manifest_path,
"\n");
auto maybe_manifest_config = config_from_manifest(m_pimpl->m_manifest_path, m_pimpl->m_manifest_doc);
auto maybe_config_json = config_from_json(m_pimpl->m_config_dir / "vcpkg-configuration.json", filesystem);
if (!config_obj->is_object())
{
print2(Color::error,
"Failed to parse ",
m_pimpl->m_manifest_path,
": vcpkg-configuration must be an object\n");
Checks::exit_fail(VCPKG_LINE_INFO);
}
m_pimpl->m_config = merge_validate_configs(std::move(maybe_manifest_config),
manifest_root_dir,
std::move(maybe_config_json),
m_pimpl->m_config_dir,
*this);
configuration_from_manifest = make_optional(config_obj->object());
}
}
auto config_file = load_configuration(filesystem, args, root, manifest_root_dir, configuration_from_manifest);
if (auto manifest = m_pimpl->m_manifest_doc.get())
{
if (auto p_baseline = manifest->first.get("builtin-baseline"))
{
LockGuardPtr<Metrics>(g_metrics)->track_property("manifest_baseline", "defined");
if (!p_baseline->is_string() || !is_git_commit_sha(p_baseline->string()))
{
std::string baseline_in_error;
if (p_baseline->is_string())
{
baseline_in_error = Strings::concat(" (", p_baseline->string(), ')');
}
LockGuardPtr<Metrics>(g_metrics)->track_property("versioning-error-baseline", "defined");
Checks::exit_maybe_upgrade(VCPKG_LINE_INFO,
"Error: the top-level builtin-baseline%s was not a valid commit sha: "
"expected 40 lowercase hexadecimal characters.\n%s\n",
baseline_in_error,
get_current_git_sha_baseline_message());
}
config_file.config.registry_set.set_default_builtin_registry_baseline(p_baseline->string());
}
m_pimpl->m_registry_set = m_pimpl->m_config.instantiate_registry_set(m_pimpl->m_config_dir);
}
// metrics from configuration
{
auto default_registry = config_file.config.registry_set.default_registry();
auto other_registries = config_file.config.registry_set.registries();
auto default_registry = m_pimpl->m_registry_set->default_registry();
auto other_registries = m_pimpl->m_registry_set->registries();
LockGuardPtr<Metrics> metrics(g_metrics);
if (default_registry)
{
@ -561,9 +560,6 @@ namespace vcpkg
}
}
config_root_dir = std::move(config_file.config_directory);
m_pimpl->m_config = std::move(config_file.config);
m_pimpl->buildtrees = maybe_get_tmp_path(args.buildtrees_root_dir.get(), "buildtrees", "blds", VCPKG_LINE_INFO);
m_pimpl->packages = maybe_get_tmp_path(args.packages_root_dir.get(), "packages", "pkgs", VCPKG_LINE_INFO);
@ -1242,10 +1238,10 @@ namespace vcpkg
}
}
const Configuration& VcpkgPaths::get_configuration() const { return m_pimpl->m_config; }
void VcpkgPaths::set_builtin_baseline(const std::string& baseline) const
const RegistrySet& VcpkgPaths::get_registry_set() const
{
m_pimpl->m_config.registry_set.set_default_builtin_registry_baseline(baseline);
Checks::check_exit(VCPKG_LINE_INFO, m_pimpl->m_registry_set != nullptr);
return *m_pimpl->m_registry_set;
}
const Downloads::DownloadManager& VcpkgPaths::get_download_manager() const { return m_pimpl->m_download_manager; }