Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embed vcpkg configuration in manifest #239

Merged
merged 17 commits into from
Nov 4, 2021
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/vcpkg/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ namespace vcpkg
// `registries` and `default_registry`. The fall back logic is
// taken care of in RegistrySet.
RegistrySet registry_set;
Json::Object extra_info;

void validate_feature_flags(const FeatureFlagSettings& flags);
};

std::unique_ptr<Json::IDeserializer<Configuration>> make_configuration_deserializer(const Path& config_directory);
Json::Object serialize_configuration(const Configuration& config);
}
4 changes: 4 additions & 0 deletions include/vcpkg/registries.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ namespace vcpkg

virtual Optional<VersionT> get_baseline_version(const VcpkgPaths& paths, StringView port_name) const = 0;

virtual Json::Object serialize() const;

virtual ~RegistryImplementation() = default;
};

Expand Down Expand Up @@ -124,6 +126,8 @@ namespace vcpkg
std::vector<Registry> registries_;
};

Json::Object serialize_registry_set(const RegistrySet& config);

std::unique_ptr<Json::IDeserializer<std::unique_ptr<RegistryImplementation>>>
get_registry_implementation_deserializer(const Path& configuration_directory);

Expand Down
1 change: 1 addition & 0 deletions include/vcpkg/sourceparagraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ namespace vcpkg
std::vector<std::string> default_features;
std::string license; // SPDX license expression
Optional<std::string> builtin_baseline;
Optional<Json::Object> vcpkg_configuration;

Type type = {Type::PORT};
PlatformExpression::Expr supports_expression;
Expand Down
79 changes: 79 additions & 0 deletions src/vcpkg-test/manifests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,85 @@ TEST_CASE ("manifest overrides", "[manifests]")
REQUIRE(!pgh.check_against_feature_flags({}, feature_flags_with_versioning));
}

TEST_CASE ("manifest embed configuration", "[manifests]")
{
std::string raw_config = R"json({
"$extra-info": null,
"default-registry": {
"kind": "builtin",
"baseline": "089fa4de7dca22c67dcab631f618d5cd0697c8d4"
},
"registries": [
{
"kind": "filesystem",
"baseline": "default",
"path": "a/b/c",
"packages": [
"a",
"b",
"c"
]
}
]
})json";

std::string raw = Strings::concat(R"json({
"vcpkg-configuration": )json",
raw_config,
R"json(,
"name": "zlib",
"version": "1.0.0",
"builtin-baseline": "089fa4de7dca22c67dcab631f618d5cd0697c8d4",
"dependencies": [
"a",
{
"$extra": null,
"name": "b"
},
{
"name": "c",
"version>=": "2018-09-01"
}
]
})json");
auto m_pgh = test_parse_manifest(raw);

REQUIRE(m_pgh.has_value());
auto& pgh = **m_pgh.get();
REQUIRE(pgh.check_against_feature_flags({}, feature_flags_without_versioning));
REQUIRE(!pgh.check_against_feature_flags({}, feature_flags_with_versioning));

auto maybe_as_json = Json::parse(raw);
REQUIRE(maybe_as_json.has_value());
auto as_json = *maybe_as_json.get();
REQUIRE(as_json.first.is_object());
auto as_json_obj = as_json.first.object();
REQUIRE(Json::stringify(serialize_manifest(pgh), Json::JsonStyle::with_spaces(4)) ==
Json::stringify(as_json_obj, Json::JsonStyle::with_spaces(4)));

REQUIRE(pgh.core_paragraph->builtin_baseline == "089fa4de7dca22c67dcab631f618d5cd0697c8d4");
REQUIRE(pgh.core_paragraph->dependencies.size() == 3);
REQUIRE(pgh.core_paragraph->dependencies[0].name == "a");
REQUIRE(pgh.core_paragraph->dependencies[0].constraint ==
DependencyConstraint{Versions::Constraint::Type::None, "", 0});
REQUIRE(pgh.core_paragraph->dependencies[1].name == "b");
REQUIRE(pgh.core_paragraph->dependencies[1].constraint ==
DependencyConstraint{Versions::Constraint::Type::None, "", 0});
REQUIRE(pgh.core_paragraph->dependencies[2].name == "c");
REQUIRE(pgh.core_paragraph->dependencies[2].constraint ==
DependencyConstraint{Versions::Constraint::Type::Minimum, "2018-09-01", 0});

auto maybe_config = Json::parse(raw_config, "<test config>");
REQUIRE(maybe_config.has_value());
auto config = *maybe_config.get();
REQUIRE(config.first.is_object());
auto config_obj = config.first.object();
REQUIRE(pgh.core_paragraph->vcpkg_configuration.has_value());
auto parsed_config_obj = *pgh.core_paragraph->vcpkg_configuration.get();
REQUIRE(Json::stringify(parsed_config_obj, Json::JsonStyle::with_spaces(4)) ==
Json::stringify(config_obj, Json::JsonStyle::with_spaces(4)));
}

TEST_CASE ("manifest construct maximum", "[manifests]")
{
auto m_pgh = test_parse_manifest(R"json({
Expand Down
55 changes: 54 additions & 1 deletion src/vcpkg/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ namespace

Optional<Configuration> ConfigurationDeserializer::visit_object(Json::Reader& r, const Json::Object& obj)
{
Json::Object extra_info;
for (const auto& el : obj)
{
if (Strings::starts_with(el.first, "$"))
{
extra_info.insert_or_replace(el.first.to_string(), el.second);
}
}

RegistrySet registries;

auto impl_des = get_registry_implementation_deserializer(configuration_directory);
Expand All @@ -53,21 +62,65 @@ namespace
registries.add_registry(std::move(reg));
}

return Configuration{std::move(registries)};
return Configuration{std::move(registries), extra_info};
}

ConfigurationDeserializer::ConfigurationDeserializer(const Path& configuration_directory)
: configuration_directory(configuration_directory)
{
}

static Json::Object serialize_configuration_impl(const Configuration& config)
{
constexpr static StringLiteral REGISTRY_PACKAGES = "packages";

auto serialize_packages_list = [](vcpkg::View<std::string> packages) {
Json::Array ret;
for (auto pkg : packages)
ret.push_back(Json::Value::string(pkg));
return ret;
};

Json::Object obj;

for (const auto& el : config.extra_info)
{
obj.insert(el.first.to_string(), el.second);
}

if (config.registry_set.default_registry())
{
obj.insert(ConfigurationDeserializer::DEFAULT_REGISTRY,
config.registry_set.default_registry()->serialize());
}

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();
reg_obj.insert(REGISTRY_PACKAGES, serialize_packages_list(reg.packages()));
reg_arr.push_back(std::move(reg_obj));
}
}

return obj;
}

}

std::unique_ptr<Json::IDeserializer<Configuration>> vcpkg::make_configuration_deserializer(const Path& config_directory)
{
return std::make_unique<ConfigurationDeserializer>(config_directory);
}

Json::Object vcpkg::serialize_configuration(const Configuration& config)
{
return serialize_configuration_impl(config);
}

namespace vcpkg
{
void Configuration::validate_feature_flags(const FeatureFlagSettings& flags)
Expand Down
38 changes: 38 additions & 0 deletions src/vcpkg/registries.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ namespace

Optional<VersionT> get_baseline_version(const VcpkgPaths&, StringView) const override;

Json::Object serialize() const override;

private:
friend struct GitRegistryEntry;

Expand Down Expand Up @@ -218,6 +220,8 @@ namespace

Optional<VersionT> get_baseline_version(const VcpkgPaths& paths, StringView port_name) const override;

Json::Object serialize() const override;

~BuiltinRegistry() = default;

std::string m_baseline_identifier;
Expand All @@ -239,6 +243,8 @@ namespace

Optional<VersionT> get_baseline_version(const VcpkgPaths&, StringView) const override;

Json::Object serialize() const override;

private:
Path m_path;
std::string m_baseline_identifier;
Expand Down Expand Up @@ -1013,6 +1019,38 @@ namespace
}
}

// serializers

Json::Object RegistryImplementation::serialize() const
{
Json::Object obj;
obj.insert(RegistryImplDeserializer::KIND, Json::Value::string(kind()));
return obj;
}

Json::Object BuiltinRegistry::serialize() const
{
Json::Object obj{RegistryImplementation::serialize()};
obj.insert(RegistryImplDeserializer::BASELINE, Json::Value::string(m_baseline_identifier));
return obj;
}

Json::Object GitRegistry::serialize() const
{
Json::Object obj{RegistryImplementation::serialize()};
obj.insert(RegistryImplDeserializer::BASELINE, Json::Value::string(m_baseline_identifier));
obj.insert(RegistryImplDeserializer::REPO, Json::Value::string(m_repo));
return obj;
}

Json::Object FilesystemRegistry::serialize() const
{
Json::Object obj{RegistryImplementation::serialize()};
obj.insert(RegistryImplDeserializer::BASELINE, Json::Value::string(m_baseline_identifier));
obj.insert(RegistryImplDeserializer::PATH, Json::Value::string(m_path.generic_u8string()));
return obj;
}

namespace vcpkg
{
constexpr StringLiteral VersionDbEntryDeserializer::GIT_TREE;
Expand Down
55 changes: 47 additions & 8 deletions src/vcpkg/sourceparagraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <vcpkg/base/system.print.h>
#include <vcpkg/base/util.h>

#include <vcpkg/configuration.h>
#include <vcpkg/metrics.h>
#include <vcpkg/packagespec.h>
#include <vcpkg/platform-expression.h>
Expand Down Expand Up @@ -857,6 +858,7 @@ namespace vcpkg
constexpr static StringLiteral SUPPORTS = "supports";
constexpr static StringLiteral OVERRIDES = "overrides";
constexpr static StringLiteral BUILTIN_BASELINE = "builtin-baseline";
constexpr static StringLiteral VCPKG_CONFIGURATION = "vcpkg-configuration";

virtual Span<const StringView> valid_fields() const override
{
Expand All @@ -874,6 +876,7 @@ namespace vcpkg
SUPPORTS,
OVERRIDES,
BUILTIN_BASELINE,
VCPKG_CONFIGURATION,
};
static const auto t = Util::Vectors::concat<StringView>(schemed_deserializer_fields(), u);

Expand Down Expand Up @@ -932,6 +935,18 @@ namespace vcpkg
r.optional_object_field(
obj, FEATURES, control_file->feature_paragraphs, FeaturesFieldDeserializer::instance);

if (auto configuration = obj.get(VCPKG_CONFIGURATION))
{
if (!configuration->is_object())
{
r.add_generic_error(type_name(), VCPKG_CONFIGURATION, " must be an object");
}
else
{
spgh->vcpkg_configuration = make_optional(configuration->object());
}
}

if (auto maybe_error = canonicalize(*control_file))
{
Checks::exit_with_message(VCPKG_LINE_INFO, maybe_error->error);
Expand All @@ -957,6 +972,7 @@ namespace vcpkg
constexpr StringLiteral ManifestDeserializer::SUPPORTS;
constexpr StringLiteral ManifestDeserializer::OVERRIDES;
constexpr StringLiteral ManifestDeserializer::BUILTIN_BASELINE;
constexpr StringLiteral ManifestDeserializer::VCPKG_CONFIGURATION;

SourceControlFile SourceControlFile::clone() const
{
Expand Down Expand Up @@ -998,6 +1014,14 @@ namespace vcpkg
bool is_default_builtin_registry) const
{
static constexpr StringLiteral s_extended_help = "See `vcpkg help versioning` for more information.";
auto format_error_message = [&](StringView manifest_field, StringView feature_flag) {
return Strings::format(" was rejected because it uses \"%s\" and the `%s` feature flag is disabled.\n"
"This can be fixed by removing \"%s\".\n",
manifest_field,
feature_flag,
manifest_field);
};

if (!flags.versions)
{
auto check_deps = [&](View<Dependency> deps) -> Optional<std::string> {
Expand Down Expand Up @@ -1027,21 +1051,18 @@ namespace vcpkg
if (core_paragraph->overrides.size() != 0)
{
LockGuardPtr<Metrics>(g_metrics)->track_property("error-versioning-disabled", "defined");
return Strings::concat(origin,
" was rejected because it uses overrides and the `",
VcpkgCmdArguments::VERSIONS_FEATURE,
"` feature flag is disabled.\nThis can be fixed by removing \"overrides\".\n",
s_extended_help);
return Strings::concat(
origin,
format_error_message(ManifestDeserializer::OVERRIDES, VcpkgCmdArguments::VERSIONS_FEATURE),
s_extended_help);
}

if (core_paragraph->builtin_baseline.has_value())
{
LockGuardPtr<Metrics>(g_metrics)->track_property("error-versioning-disabled", "defined");
return Strings::concat(
origin,
" was rejected because it uses builtin-baseline and the `",
VcpkgCmdArguments::VERSIONS_FEATURE,
"` feature flag is disabled.\nThis can be fixed by removing \"builtin-baseline\".\n",
format_error_message(ManifestDeserializer::BUILTIN_BASELINE, VcpkgCmdArguments::VERSIONS_FEATURE),
s_extended_help);
}
}
Expand Down Expand Up @@ -1327,6 +1348,24 @@ namespace vcpkg
obj.insert(el.first.to_string(), el.second);
}

if (auto configuration = scf.core_paragraph->vcpkg_configuration.get())
{
Json::Reader reader;
auto maybe_configuration = reader.visit(*configuration, *vcpkg::make_configuration_deserializer(""));
if (!reader.errors().empty())
{
print2(Color::error, "Errors occurred while parsing ", ManifestDeserializer::VCPKG_CONFIGURATION, "\n");
for (auto&& msg : reader.errors())
print2(" ", msg, '\n');

print2("See https://github.com/Microsoft/vcpkg/tree/master/docs/users/registries.md for "
"more information.\n");
Checks::exit_fail(VCPKG_LINE_INFO);
}
obj.insert(ManifestDeserializer::VCPKG_CONFIGURATION,
serialize_configuration(maybe_configuration.value_or_exit(VCPKG_LINE_INFO)));
}

obj.insert(ManifestDeserializer::NAME, Json::Value::string(scf.core_paragraph->name));

serialize_schemed_version(obj,
Expand Down
Loading