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 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 # test the git registry
Write-Trace "test the git registry" Write-Trace "test the git registry"
$manifestDir = "$TestingRoot/git-registry-test-manifest-dir" $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; const Path& base_temporary_directory() noexcept;
} }

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

@ -281,7 +281,7 @@ namespace vcpkg::Json
virtual StringView type_name() const override { return type_name_; } virtual StringView type_name() const override { return type_name_; }
virtual Optional<std::string> visit_string(Reader&, StringView sv) override { return sv.to_string(); } 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: private:
StringLiteral type_name_; StringLiteral type_name_;
@ -327,7 +327,7 @@ namespace vcpkg::Json
virtual StringView type_name() const override { return m_type_name; } 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)) : 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(); } 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(); } constexpr bool has_value() const { return this->m_base.has_value(); }
template<class U> template<class U>

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

@ -10,21 +10,43 @@
namespace vcpkg 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 struct Configuration
{ {
// This member is set up via two different configuration options, Optional<RegistryConfig> default_reg;
// `registries` and `default_registry`. The fall back logic is std::vector<RegistryConfig> registries;
// taken care of in RegistrySet.
RegistrySet registry_set;
Json::Object ce_metadata; Json::Object ce_metadata;
Json::Object extra_info; 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(); static View<StringView> known_fields();
}; };
std::unique_ptr<Json::IDeserializer<Configuration>> make_configuration_deserializer(const Path& config_directory); struct ManifestConfiguration
Json::Object serialize_configuration(const Configuration& config); {
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); 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 namespace vcpkg
{ {
struct Configuration; 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 Optional<Path> get_path_to_baseline_version(const VcpkgPaths& paths, StringView port_name) const;
virtual Json::Object serialize() const;
virtual ~RegistryImplementation() = default; virtual ~RegistryImplementation() = default;
}; };
@ -104,7 +102,10 @@ namespace vcpkg
// configuration fields. // configuration fields.
struct RegistrySet 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 // finds the correct registry for the port name
// Returns the null pointer if there is no registry set up for that 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(); } 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; 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 // returns whether the registry set has any modifications to the default
// (i.e., whether `default_registry` was set, or `registries` had any entries) // (i.e., whether `default_registry` was set, or `registries` had any entries)
@ -132,13 +128,13 @@ namespace vcpkg
std::vector<Registry> registries_; std::vector<Registry> registries_;
}; };
Json::Object serialize_registry_set(const RegistrySet& config); std::unique_ptr<RegistryImplementation> make_builtin_registry();
std::unique_ptr<RegistryImplementation> make_builtin_registry(std::string baseline);
std::unique_ptr<Json::IDeserializer<std::unique_ptr<RegistryImplementation>>> std::unique_ptr<RegistryImplementation> make_git_registry(std::string repo,
get_registry_implementation_deserializer(const Path& configuration_directory); std::string reference,
std::string baseline);
std::unique_ptr<Json::IDeserializer<std::vector<Registry>>> get_registry_array_deserializer( std::unique_ptr<RegistryImplementation> make_filesystem_registry(Path path, std::string baseline);
const Path& configuration_directory); 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, ExpectedS<std::vector<std::pair<SchemedVersion, std::string>>> get_builtin_versions(const VcpkgPaths& paths,
StringView port_name); StringView port_name);

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

@ -128,6 +128,9 @@ namespace vcpkg
Json::Object serialize_manifest(const SourceControlFile& scf); Json::Object serialize_manifest(const SourceControlFile& scf);
Json::Object serialize_debug_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> /// <summary>
/// Named pair of a SourceControlFile and the location of this file /// Named pair of a SourceControlFile and the location of this file
/// </summary> /// </summary>

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

@ -109,7 +109,6 @@ namespace vcpkg
Path original_cwd; Path original_cwd;
Path root; Path root;
Path manifest_root_dir; Path manifest_root_dir;
Path config_root_dir;
Path downloads; Path downloads;
Path triplets; Path triplets;
Path community_triplets; Path community_triplets;
@ -159,8 +158,7 @@ namespace vcpkg
Optional<const Json::Object&> get_manifest() const; Optional<const Json::Object&> get_manifest() const;
Optional<const Path&> get_manifest_path() const; Optional<const Path&> get_manifest_path() const;
const Configuration& get_configuration() const; const RegistrySet& get_registry_set() const;
void set_builtin_baseline(const std::string& baseline) const;
// Retrieve a toolset matching the requirements in prebuildinfo // Retrieve a toolset matching the requirements in prebuildinfo
const Toolset& get_toolset(const Build::PreBuildInfo& prebuildinfo) const; 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); auto object = parse_json_object(text);
Json::Reader reader; Json::Reader reader;
auto deserializer = make_configuration_deserializer(""); auto parsed_config_opt = reader.visit(object, get_configuration_deserializer());
auto parsed_config_opt = reader.visit(object, *deserializer);
REQUIRE(reader.errors().empty()); REQUIRE(reader.errors().empty());
return std::move(parsed_config_opt).value_or_exit(VCPKG_LINE_INFO); 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); 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) static void check_errors(const std::string& config_text, const std::string& expected_errors)
{ {
auto object = parse_json_object(config_text); auto object = parse_json_object(config_text);
Json::Reader reader; Json::Reader reader;
auto deserializer = make_configuration_deserializer(""); auto parsed_config_opt = reader.visit(object, get_configuration_deserializer());
auto parsed_config_opt = reader.visit(object, *deserializer);
REQUIRE(!reader.errors().empty()); REQUIRE(!reader.errors().empty());
CHECK_LINES(Strings::join("\n", reader.errors()), expected_errors); CHECK_LINES(Strings::join("\n", reader.errors()), expected_errors);
@ -114,6 +106,11 @@ TEST_CASE ("config registries only", "[ce-metadata]")
"kind": "artifact", "kind": "artifact",
"name": "vcpkg-artifacts", "name": "vcpkg-artifacts",
"location": "https://github.com/microsoft/vcpkg-artifacts" "location": "https://github.com/microsoft/vcpkg-artifacts"
},
{
"kind": "filesystem",
"path": "path/to/registry",
"packages": [ ]
} }
] ]
})json"; })json";
@ -121,39 +118,46 @@ TEST_CASE ("config registries only", "[ce-metadata]")
auto config = parse_test_configuration(raw_config); auto config = parse_test_configuration(raw_config);
REQUIRE(config.ce_metadata.is_empty()); REQUIRE(config.ce_metadata.is_empty());
REQUIRE(config.extra_info.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, KIND, "builtin");
check_string(default_registry, BASELINE, "843e0ba0d8f9c9c572e45564263eedfc7745e74f"); 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]; const auto& git_registry = config.registries[0];
auto serialized_git_registry = git_registry.implementation().serialize(); auto serialized_git_registry = git_registry.serialize().object();
check_string(serialized_git_registry, KIND, "git"); check_string(serialized_git_registry, KIND, "git");
check_string(serialized_git_registry, REPOSITORY, "https://github.com/northwindtraders/vcpkg-registry"); check_string(serialized_git_registry, REPOSITORY, "https://github.com/northwindtraders/vcpkg-registry");
check_string(serialized_git_registry, BASELINE, "dacf4de488094a384ca2c202b923ccc097956e0c"); check_string(serialized_git_registry, BASELINE, "dacf4de488094a384ca2c202b923ccc097956e0c");
REQUIRE(git_registry.packages().size() == 2); REQUIRE(git_registry.packages);
REQUIRE(git_registry.packages()[0] == "beicode"); auto&& p = *git_registry.packages.get();
REQUIRE(git_registry.packages()[1] == "beison"); REQUIRE(p.size() == 2);
REQUIRE(p[0] == "beicode");
REQUIRE(p[1] == "beison");
const auto& fs_registry = config.registry_set.registries()[1]; const auto& fs_registry = config.registries[1];
auto serialized_fs_registry = fs_registry.implementation().serialize(); auto serialized_fs_registry = fs_registry.serialize().object();
check_string(serialized_fs_registry, KIND, "filesystem"); check_string(serialized_fs_registry, KIND, "filesystem");
check_string(serialized_fs_registry, PATH, "path/to/registry"); check_string(serialized_fs_registry, PATH, "path/to/registry");
REQUIRE(fs_registry.packages().size() == 1); REQUIRE(fs_registry.packages);
REQUIRE(fs_registry.packages()[0] == "zlib"); REQUIRE(fs_registry.packages.get()->size() == 1);
REQUIRE((*fs_registry.packages.get())[0] == "zlib");
const auto& artifact_registry = config.registry_set.registries()[2]; const auto& artifact_registry = config.registries[2];
auto serialized_art_registry = artifact_registry.implementation().serialize(); auto serialized_art_registry = artifact_registry.serialize().object();
check_string(serialized_art_registry, KIND, "artifact"); check_string(serialized_art_registry, KIND, "artifact");
check_string(serialized_art_registry, NAME, "vcpkg-artifacts"); check_string(serialized_art_registry, NAME, "vcpkg-artifacts");
check_string(serialized_art_registry, LOCATION, "https://github.com/microsoft/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 raw_obj = parse_json_object(raw_config);
auto serialized_obj = serialize_configuration(config); auto serialized_obj = config.serialize();
compare_json_objects(raw_obj, serialized_obj); Test::check_json_eq(raw_obj, serialized_obj);
} }
SECTION ("default invalid json") SECTION ("default invalid json")
@ -165,7 +169,6 @@ TEST_CASE ("config registries only", "[ce-metadata]")
})json"; })json";
check_errors(raw_no_baseline, R"( check_errors(raw_no_baseline, R"(
$.default-registry (a builtin registry): missing required field 'baseline' (a baseline) $.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({ std::string raw_with_packages = R"json({
@ -187,7 +190,7 @@ $.default-registry (a registry): unexpected field 'packages', did you mean 'path
} }
})json"; })json";
check_errors(raw_default_artifact, R"( 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({ std::string raw_bad_kind = R"json({
"registries": [{ "registries": [{
@ -223,9 +226,9 @@ $.registries[0] (a registry): missing required field 'packages' (an array of pac
})json"; })json";
check_errors(raw_bad_git_registry, R"( check_errors(raw_bad_git_registry, R"(
$.registries[0] (a registry): unexpected field 'no-repository', did you mean 'repository'? $.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] (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].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 $.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"; })json";
check_errors(raw_bad_artifact_registry, R"( check_errors(raw_bad_artifact_registry, R"(
$.registries[0] (a registry): unexpected field 'no-location', did you mean 'location'? $.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 '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 'baseline', did you mean 'kind'?
$.registries[0] (an artifacts registry): unexpected field 'packages', did you mean 'name'? $.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"; })json";
auto config = parse_test_configuration(raw_config); auto config = parse_test_configuration(raw_config);
REQUIRE(!config.registry_set.registries().size()); REQUIRE(!config.registries.size());
REQUIRE(config.registry_set.is_default_builtin_registry()); REQUIRE(config.instantiate_registry_set({})->is_default_builtin_registry());
REQUIRE(!config.extra_info.is_empty()); REQUIRE(!config.extra_info.is_empty());
REQUIRE(config.extra_info.size() == 1); REQUIRE(config.extra_info.size() == 1);
@ -299,8 +302,8 @@ TEST_CASE ("config ce metadata only", "[ce-metadata]")
REQUIRE(nested.contains("unexpected")); REQUIRE(nested.contains("unexpected"));
auto raw_obj = parse_json_object(raw_config); auto raw_obj = parse_json_object(raw_config);
auto serialized_obj = serialize_configuration(config); auto serialized_obj = config.serialize();
compare_json_objects(raw_obj, serialized_obj); Test::check_json_eq(raw_obj, serialized_obj);
} }
TEST_CASE ("metadata strings", "[ce-metadata]") 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"); check_string(valid_config.ce_metadata, CE_ERROR, "this is a valid error");
auto raw_obj = parse_json_object(valid_raw); 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") SECTION ("invalid json")
@ -383,7 +386,7 @@ TEST_CASE ("metadata dictionaries", "[ce-metadata]")
check_string(settings, "SETTING_2", "value2"); check_string(settings, "SETTING_2", "value2");
auto raw_obj = parse_json_object(valid_raw); 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") SECTION ("invalid json")
@ -466,7 +469,7 @@ TEST_CASE ("metadata demands", "[ce-metadata]")
check_string(level1, CE_MESSAGE, "this is level 1"); check_string(level1, CE_MESSAGE, "this is level 1");
auto raw_obj = parse_json_object(simple_raw); 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") SECTION ("invalid json")
@ -517,7 +520,7 @@ TEST_CASE ("serialize configuration", "[ce-metadata]")
})json"; })json";
// parsing of configuration is tested elsewhere // parsing of configuration is tested elsewhere
auto config = parse_test_configuration(raw); 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") SECTION ("overriden default registry and registries")
@ -538,7 +541,7 @@ TEST_CASE ("serialize configuration", "[ce-metadata]")
})json"; })json";
// parsing of configuration is tested elsewhere // parsing of configuration is tested elsewhere
auto config = parse_test_configuration(raw); 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") SECTION ("only registries")
@ -555,7 +558,7 @@ TEST_CASE ("serialize configuration", "[ce-metadata]")
})json"; })json";
// parsing of configuration is tested elsewhere // parsing of configuration is tested elsewhere
auto config = parse_test_configuration(raw); 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") SECTION ("preserve comments and unexpected fields")
@ -580,7 +583,7 @@ TEST_CASE ("serialize configuration", "[ce-metadata]")
})json"; })json";
auto config = parse_test_configuration(raw); 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); auto extra_fields = find_unknown_fields(config);
CHECK(extra_fields.size() == 4); CHECK(extra_fields.size() == 4);
@ -681,7 +684,7 @@ TEST_CASE ("serialize configuration", "[ce-metadata]")
// demands // demands
// Object values in `demands` are also sorted recursively. // Object values in `demands` are also sorted recursively.
auto config = parse_test_configuration(raw); 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); 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, KIND, "builtin");
check_string(default_registry, BASELINE, "843e0ba0d8f9c9c572e45564263eedfc7745e74f"); check_string(default_registry, BASELINE, "843e0ba0d8f9c9c572e45564263eedfc7745e74f");
REQUIRE(config.registry_set.registries().size() == 1); REQUIRE(config.registries.size() == 1);
const auto& registry = *config.registry_set.registries().begin(); const auto& registry = *config.registries.begin();
auto serialized_registry = registry.implementation().serialize(); auto serialized_registry = registry.serialize().object();
check_string(serialized_registry, KIND, "git"); check_string(serialized_registry, KIND, "git");
check_string(serialized_registry, REPOSITORY, "https://github.com/northwindtraders/vcpkg-registry"); check_string(serialized_registry, REPOSITORY, "https://github.com/northwindtraders/vcpkg-registry");
check_string(serialized_registry, BASELINE, "dacf4de488094a384ca2c202b923ccc097956e0c"); check_string(serialized_registry, BASELINE, "dacf4de488094a384ca2c202b923ccc097956e0c");
REQUIRE(registry.packages().size() == 2); REQUIRE(registry.packages);
REQUIRE(registry.packages()[0] == "beicode"); REQUIRE(registry.packages.get()->size() == 2);
REQUIRE(registry.packages()[1] == "beison"); REQUIRE(registry.packages.get()->at(0) == "beicode");
REQUIRE(registry.packages.get()->at(1) == "beison");
REQUIRE(!config.extra_info.is_empty()); REQUIRE(!config.extra_info.is_empty());
REQUIRE(config.extra_info.size() == 2); 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 // finally test serialization is OK
auto raw_obj = parse_json_object(raw_config); auto raw_obj = parse_json_object(raw_config);
auto serialized_obj = serialize_configuration(config); auto serialized_obj = config.serialize();
compare_json_objects(raw_obj, serialized_obj); 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); auto maybe_as_json = Json::parse(raw);
REQUIRE(maybe_as_json.has_value()); REQUIRE(maybe_as_json.has_value());
auto as_json = *maybe_as_json.get(); auto as_json = *maybe_as_json.get();
REQUIRE(as_json.first.is_object()); check_json_eq(Json::Value::object(serialize_manifest(pgh)), as_json.first);
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)));
REQUIRE(pgh.core_paragraph->builtin_baseline == "089fa4de7dca22c67dcab631f618d5cd0697c8d4"); REQUIRE(pgh.core_paragraph->builtin_baseline == "089fa4de7dca22c67dcab631f618d5cd0697c8d4");
REQUIRE(pgh.core_paragraph->dependencies.size() == 3); REQUIRE(pgh.core_paragraph->dependencies.size() == 3);

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

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

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

@ -10,6 +10,7 @@
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <set>
#include <vector> #include <vector>
#include <vcpkg-test/util.h> #include <vcpkg-test/util.h>
@ -105,4 +106,84 @@ namespace vcpkg::Test
const static Path BASE_TEMPORARY_DIRECTORY = internal_base_temporary_directory(); const static Path BASE_TEMPORARY_DIRECTORY = internal_base_temporary_directory();
return 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/system.print.h>
#include <vcpkg/base/unicode.h> #include <vcpkg/base/unicode.h>
#include <vcpkg/documentation.h>
#include <inttypes.h> #include <inttypes.h>
namespace vcpkg::Json namespace vcpkg::Json
@ -1425,9 +1427,9 @@ namespace vcpkg::Json
if (!is_ident(sv)) if (!is_ident(sv))
{ {
r.add_generic_error(type_name(), r.add_generic_error(type_name(),
"must be lowercase alphanumeric+hyphens and not reserved (see " Strings::concat("must be lowercase alphanumeric+hyphens and not reserved (see ",
"https://github.com/Microsoft/vcpkg/tree/master/docs/specifications/manifests.md for " vcpkg::docs::manifests_url,
"more information)"); " for more information)"));
} }
return sv.to_string(); return sv.to_string();
} }

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

@ -12,6 +12,7 @@
#include <vcpkg/binarycaching.private.h> #include <vcpkg/binarycaching.private.h>
#include <vcpkg/build.h> #include <vcpkg/build.h>
#include <vcpkg/dependencies.h> #include <vcpkg/dependencies.h>
#include <vcpkg/documentation.h>
#include <vcpkg/metrics.h> #include <vcpkg/metrics.h>
#include <vcpkg/tools.h> #include <vcpkg/tools.h>
@ -21,11 +22,6 @@ using namespace vcpkg;
namespace 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 struct ConfigSegmentsParser : Parse::ParserBase
{ {
using Parse::ParserBase::ParserBase; using Parse::ParserBase::ParserBase;
@ -633,9 +629,9 @@ namespace
res.exit_code != 0) res.exit_code != 0)
{ {
print2(Color::warning, print2(Color::warning,
"One or more NuGet credential providers failed to authenticate. See " "One or more NuGet credential providers failed to authenticate. See ",
"https://github.com/Microsoft/vcpkg/tree/master/docs/users/binarycaching.md for " docs::binarycaching_url,
"more details on how to provide credentials.\n"); " for more details on how to provide credentials.\n");
} }
else if (res.output.find("for example \"-ApiKey AzureDevOps\"") != std::string::npos) 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(); parser.parse();
if (auto err = parser.get_error()) 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) if (s.azblob_templates_to_put.size() > 1)
{ {
return Strings::concat("Error: a maximum of one asset write url can be specified\n" return Strings::concat("Error: a maximum of one asset write url can be specified\n"
"For more information, see ", "For more information, see ",
s_assetcaching_doc_url, docs::assetcaching_url,
"\n"); "\n");
} }
if (s.url_templates_to_get.size() > 1) if (s.url_templates_to_get.size() > 1)
{ {
return Strings::concat("Error: a maximum of one asset read url can be specified\n" return Strings::concat("Error: a maximum of one asset read url can be specified\n"
"For more information, see ", "For more information, see ",
s_assetcaching_doc_url, docs::assetcaching_url,
"\n"); "\n");
} }
@ -2108,7 +2104,7 @@ void vcpkg::help_topic_asset_caching(const VcpkgPaths&)
tbl.blank(); tbl.blank();
print2(tbl.m_str); 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&) 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"); "\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) std::string vcpkg::generate_nuget_packages_config(const Dependencies::ActionPlan& action)

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

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

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

@ -9,6 +9,204 @@ namespace
{ {
using namespace vcpkg; 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> struct DictionaryDeserializer final : Json::IDeserializer<Json::Object>
{ {
virtual StringView type_name() const override { return "a `string: string` dictionary"; } 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; virtual Optional<Configuration> visit_object(Json::Reader& r, const Json::Object& obj) override;
ConfigurationDeserializer(const Path& configuration_directory); static ConfigurationDeserializer instance;
private:
Path configuration_directory;
}; };
ConfigurationDeserializer ConfigurationDeserializer::instance;
constexpr StringLiteral ConfigurationDeserializer::DEFAULT_REGISTRY; constexpr StringLiteral ConfigurationDeserializer::DEFAULT_REGISTRY;
constexpr StringLiteral ConfigurationDeserializer::REGISTRIES; constexpr StringLiteral ConfigurationDeserializer::REGISTRIES;
@ -186,9 +382,8 @@ namespace
Optional<Configuration> ConfigurationDeserializer::visit_object(Json::Reader& r, const Json::Object& obj) Optional<Configuration> ConfigurationDeserializer::visit_object(Json::Reader& r, const Json::Object& obj)
{ {
static const StringView ARTIFACT = "artifact"; Configuration ret;
Json::Object& extra_info = ret.extra_info;
Json::Object extra_info;
std::vector<std::string> comment_keys; std::vector<std::string> comment_keys;
for (const auto& el : obj) for (const auto& el : obj)
@ -201,30 +396,24 @@ namespace
} }
} }
RegistrySet registries; RegistryConfig default_registry;
if (r.optional_object_field(obj, DEFAULT_REGISTRY, default_registry, RegistryConfigDeserializer::instance))
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))
{ {
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); static Json::ArrayDeserializer<RegistryDeserializer> regs_des("an array of registries");
std::vector<Registry> regs; r.optional_object_field(obj, REGISTRIES, ret.registries, regs_des);
r.optional_object_field(obj, REGISTRIES, regs, *reg_des);
for (Registry& reg : regs) Json::Object& ce_metadata_obj = ret.ce_metadata;
{
registries.add_registry(std::move(reg));
}
Json::Object ce_metadata_obj;
auto maybe_ce_metadata = r.visit(obj, CeMetadataDeserializer::instance); auto maybe_ce_metadata = r.visit(obj, CeMetadataDeserializer::instance);
if (maybe_ce_metadata.has_value()) if (maybe_ce_metadata.has_value())
{ {
@ -243,12 +432,7 @@ namespace
ce_metadata_obj.remove(comment_key); ce_metadata_obj.remove(comment_key);
} }
return Configuration{std::move(registries), ce_metadata_obj, extra_info}; return std::move(ret);
}
ConfigurationDeserializer::ConfigurationDeserializer(const Path& configuration_directory)
: configuration_directory(configuration_directory)
{
} }
static void serialize_ce_metadata(const Json::Object& ce_metadata, Json::Object& put_into) 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); 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) static void find_unknown_fields_impl(const Json::Object& obj, std::vector<std::string>& out, StringView path)
{ {
std::vector<StringView> ret; std::vector<StringView> ret;
@ -420,19 +554,8 @@ namespace vcpkg
return known_fields; 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()) if (!ce_metadata.is_empty())
{ {
auto unknown_fields = find_unknown_fields(*this); 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) std::vector<std::string> find_unknown_fields(const Configuration& config)
{ {

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

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

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

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

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

@ -412,7 +412,7 @@ namespace vcpkg::Paragraphs
std::vector<std::string> ports; 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()) for (const auto& registry : registries.registries())
{ {

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

@ -107,7 +107,7 @@ namespace vcpkg::PortFileProvider
} }
else 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); m_baseline_cache.emplace(port_name.to_string(), version);
return version; return version;
} }
@ -129,7 +129,7 @@ namespace vcpkg::PortFileProvider
auto entry_it = m_entry_cache.find(name); auto entry_it = m_entry_cache.find(name);
if (entry_it == m_entry_cache.end()) 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)) if (auto entry = reg->get_port_entry(paths, name))
{ {

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

@ -64,8 +64,6 @@ namespace
Optional<VersionT> get_baseline_version(const VcpkgPaths&, StringView) const override; Optional<VersionT> get_baseline_version(const VcpkgPaths&, StringView) const override;
Json::Object serialize() const override;
private: private:
friend struct GitRegistryEntry; friend struct GitRegistryEntry;
@ -231,8 +229,6 @@ namespace
return paths.builtin_ports_directory() / port_name; return paths.builtin_ports_directory() / port_name;
} }
Json::Object serialize() const override;
~BuiltinFilesRegistry() = default; ~BuiltinFilesRegistry() = default;
DelayedInit<Baseline> m_baseline; DelayedInit<Baseline> m_baseline;
@ -266,8 +262,6 @@ namespace
Optional<VersionT> get_baseline_version(const VcpkgPaths& paths, StringView port_name) const override; Optional<VersionT> get_baseline_version(const VcpkgPaths& paths, StringView port_name) const override;
Json::Object serialize() const override;
~BuiltinGitRegistry() = default; ~BuiltinGitRegistry() = default;
std::string m_baseline_identifier; std::string m_baseline_identifier;
@ -292,7 +286,7 @@ namespace
struct FilesystemRegistry final : RegistryImplementation struct FilesystemRegistry final : RegistryImplementation
{ {
FilesystemRegistry(Path&& path, std::string&& baseline) 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; Optional<VersionT> get_baseline_version(const VcpkgPaths&, StringView) const override;
Json::Object serialize() const override;
private: private:
Path m_path; Path m_path;
std::string m_baseline_identifier; std::string m_baseline_identifier;
@ -336,8 +328,6 @@ namespace
Checks::exit_fail(VCPKG_LINE_INFO); Checks::exit_fail(VCPKG_LINE_INFO);
} }
Json::Object serialize() const override;
~ArtifactRegistry() = default; ~ArtifactRegistry() = default;
private: private:
@ -922,228 +912,6 @@ namespace
}; };
BaselineDeserializer BaselineDeserializer::instance; 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) Path relative_path_to_versions(StringView port_name)
{ {
char prefix[] = {port_name.byte_at_index(0), '-', '\0'}; 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; 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 namespace vcpkg
{ {
constexpr StringLiteral VersionDbEntryDeserializer::GIT_TREE; 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) Registry::Registry(std::vector<std::string>&& packages, std::unique_ptr<RegistryImplementation>&& impl)
: packages_(std::move(packages)), implementation_(std::move(impl)) : packages_(std::move(packages)), implementation_(std::move(impl))
{ {
Checks::check_exit(VCPKG_LINE_INFO, implementation_ != nullptr); 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 const RegistryImplementation* RegistrySet::registry_for_port(StringView name) const
{ {
for (const auto& registry : registries()) for (const auto& registry : registries())
@ -1526,50 +1229,10 @@ namespace vcpkg
return impl->get_baseline_version(paths, port_name); 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 bool RegistrySet::is_default_builtin_registry() const
{ {
return default_registry_ && default_registry_->kind() == BuiltinFilesRegistry::s_kind; 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(); } 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, 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); 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/base/util.h>
#include <vcpkg/configuration.h> #include <vcpkg/configuration.h>
#include <vcpkg/documentation.h>
#include <vcpkg/metrics.h> #include <vcpkg/metrics.h>
#include <vcpkg/packagespec.h> #include <vcpkg/packagespec.h>
#include <vcpkg/platform-expression.h> #include <vcpkg/platform-expression.h>
@ -993,6 +994,61 @@ namespace vcpkg
constexpr StringLiteral ManifestDeserializer::BUILTIN_BASELINE; constexpr StringLiteral ManifestDeserializer::BUILTIN_BASELINE;
constexpr StringLiteral ManifestDeserializer::VCPKG_CONFIGURATION; 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 SourceControlFile::clone() const
{ {
SourceControlFile ret; SourceControlFile ret;
@ -1370,19 +1426,18 @@ namespace vcpkg
if (auto configuration = scf.core_paragraph->vcpkg_configuration.get()) if (auto configuration = scf.core_paragraph->vcpkg_configuration.get())
{ {
Json::Reader reader; 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()) if (!reader.errors().empty())
{ {
print2(Color::error, "Errors occurred while parsing ", ManifestDeserializer::VCPKG_CONFIGURATION, "\n"); print2(Color::error, "Errors occurred while parsing ", ManifestDeserializer::VCPKG_CONFIGURATION, "\n");
for (auto&& msg : reader.errors()) for (auto&& msg : reader.errors())
print2(" ", msg, '\n'); print2(" ", msg, '\n');
print2("See https://github.com/Microsoft/vcpkg/tree/master/docs/users/registries.md for " print2("See ", docs::registries_url, " for more information.\n");
"more information.\n");
Checks::exit_fail(VCPKG_LINE_INFO); Checks::exit_fail(VCPKG_LINE_INFO);
} }
obj.insert(ManifestDeserializer::VCPKG_CONFIGURATION, 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)); obj.insert(ManifestDeserializer::NAME, Json::Value::string(scf.core_paragraph->name));

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

@ -15,6 +15,7 @@
#include <vcpkg/commands.h> #include <vcpkg/commands.h>
#include <vcpkg/commands.version.h> #include <vcpkg/commands.version.h>
#include <vcpkg/configuration.h> #include <vcpkg/configuration.h>
#include <vcpkg/documentation.h>
#include <vcpkg/globalstate.h> #include <vcpkg/globalstate.h>
#include <vcpkg/metrics.h> #include <vcpkg/metrics.h>
#include <vcpkg/packagespec.h> #include <vcpkg/packagespec.h>
@ -57,36 +58,6 @@ namespace
namespace vcpkg 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) static std::pair<Json::Object, Json::JsonStyle> load_manifest(const Filesystem& fs, const Path& manifest_dir)
{ {
std::error_code ec; std::error_code ec;
@ -116,69 +87,129 @@ namespace vcpkg
return {std::move(manifest_value.first.object()), std::move(manifest_value.second)}; 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; if (auto manifest = manifest_doc.get())
Configuration config; {
}; 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 Optional<Configuration> config_from_json(const Path& config_path, const Filesystem& fs)
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)
{ {
Path config_dir; if (!fs.exists(config_path, VCPKG_LINE_INFO))
if (manifest_dir.empty())
{ {
// classic mode return nullopt;
config_dir = vcpkg_root;
}
else
{
// manifest mode
config_dir = manifest_dir;
} }
auto path_to_config = config_dir / "vcpkg-configuration.json"; auto parsed_config = Json::parse_file(VCPKG_LINE_INFO, fs, config_path);
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);
if (!parsed_config.first.is_object()) if (!parsed_config.first.is_object())
{ {
print2(Color::error, print2(
"Failed to parse ", Color::error, "Failed to parse ", config_path, ": configuration files must have a top-level object\n");
path_to_config, msg::println(Color::error, msg::msgSeeURL, msg::url = docs::registries_url);
": configuration files must have a top-level object\n");
Checks::exit_fail(VCPKG_LINE_INFO); 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 namespace details
@ -265,7 +296,9 @@ namespace vcpkg
Optional<std::pair<Json::Object, Json::JsonStyle>> m_manifest_doc; Optional<std::pair<Json::Object, Json::JsonStyle>> m_manifest_doc;
Path m_manifest_path; Path m_manifest_path;
Path m_config_dir;
Configuration m_config; Configuration m_config;
std::unique_ptr<RegistrySet> m_registry_set;
Downloads::DownloadManager m_download_manager; Downloads::DownloadManager m_download_manager;
@ -448,6 +481,7 @@ namespace vcpkg
if (manifest_root_dir.empty()) if (manifest_root_dir.empty())
{ {
m_pimpl->m_config_dir = root;
if (!m_pimpl->m_readonly) if (!m_pimpl->m_readonly)
{ {
m_pimpl->installed = m_pimpl->installed =
@ -458,6 +492,7 @@ namespace vcpkg
{ {
Debug::print("Using manifest-root: ", manifest_root_dir, '\n'); Debug::print("Using manifest-root: ", manifest_root_dir, '\n');
m_pimpl->m_config_dir = manifest_root_dir;
m_pimpl->installed = process_output_directory( m_pimpl->installed = process_output_directory(
filesystem, args.install_root_dir.get(), manifest_root_dir / "vcpkg_installed"); 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"; 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; auto maybe_manifest_config = config_from_manifest(m_pimpl->m_manifest_path, m_pimpl->m_manifest_doc);
if (auto config_obj = manifest_obj.get("vcpkg-configuration")) auto maybe_config_json = config_from_json(m_pimpl->m_config_dir / "vcpkg-configuration.json", filesystem);
{
print2(Color::warning,
"Embedding `vcpkg-configuration` in a manifest file is an EXPERIMENTAL feature.\n"
"Loading configuration from: ",
m_pimpl->m_manifest_path,
"\n");
if (!config_obj->is_object()) m_pimpl->m_config = merge_validate_configs(std::move(maybe_manifest_config),
{ manifest_root_dir,
print2(Color::error, std::move(maybe_config_json),
"Failed to parse ", m_pimpl->m_config_dir,
m_pimpl->m_manifest_path, *this);
": vcpkg-configuration must be an object\n");
Checks::exit_fail(VCPKG_LINE_INFO);
}
configuration_from_manifest = make_optional(config_obj->object()); m_pimpl->m_registry_set = m_pimpl->m_config.instantiate_registry_set(m_pimpl->m_config_dir);
}
}
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());
}
} }
// metrics from configuration // metrics from configuration
{ {
auto default_registry = config_file.config.registry_set.default_registry(); auto default_registry = m_pimpl->m_registry_set->default_registry();
auto other_registries = config_file.config.registry_set.registries(); auto other_registries = m_pimpl->m_registry_set->registries();
LockGuardPtr<Metrics> metrics(g_metrics); LockGuardPtr<Metrics> metrics(g_metrics);
if (default_registry) 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->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); 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; } const RegistrySet& VcpkgPaths::get_registry_set() const
void VcpkgPaths::set_builtin_baseline(const std::string& baseline) 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; } const Downloads::DownloadManager& VcpkgPaths::get_download_manager() const { return m_pimpl->m_download_manager; }