From 829b20e144a9bd40e81c04275b3832641d78b3f4 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Wed, 23 Oct 2024 14:57:27 -0700 Subject: [PATCH] Add "maybe" operations to JSON. (#1520) Extracted from https://github.com/microsoft/vcpkg-tool/pull/1514 --- include/vcpkg/base/json.h | 8 ++++ src/vcpkg/base/json.cpp | 64 +++++++++++++++++++++++++++- src/vcpkg/binarycaching.cpp | 8 ++-- src/vcpkg/bundlesettings.cpp | 13 +++--- src/vcpkg/commands.set-installed.cpp | 42 +++++++++--------- src/vcpkg/configuration.cpp | 30 +++++++------ src/vcpkg/configure-environment.cpp | 26 +++++------ src/vcpkg/sourceparagraph.cpp | 4 +- src/vcpkg/spdx.cpp | 4 +- src/vcpkg/vcpkgpaths.cpp | 38 +++++++++-------- 10 files changed, 158 insertions(+), 79 deletions(-) diff --git a/include/vcpkg/base/json.h b/include/vcpkg/base/json.h index 24cbceb80e..9b33d870ff 100644 --- a/include/vcpkg/base/json.h +++ b/include/vcpkg/base/json.h @@ -108,15 +108,23 @@ namespace vcpkg::Json int64_t integer(LineInfo li) const noexcept; double number(LineInfo li) const noexcept; StringView string(LineInfo li) const noexcept; + std::string* maybe_string() noexcept; + const std::string* maybe_string() const noexcept; const Array& array(LineInfo li) const& noexcept; Array& array(LineInfo li) & noexcept; Array&& array(LineInfo li) && noexcept; + Array* maybe_array() noexcept; + const Array* maybe_array() const noexcept; + const Object& object(LineInfo li) const& noexcept; Object& object(LineInfo li) & noexcept; Object&& object(LineInfo li) && noexcept; + Object* maybe_object() noexcept; + const Object* maybe_object() const noexcept; + static Value null(std::nullptr_t) noexcept; static Value boolean(bool) noexcept; static Value integer(int64_t i) noexcept; diff --git a/src/vcpkg/base/json.cpp b/src/vcpkg/base/json.cpp index e65c51e65a..2c7116d117 100644 --- a/src/vcpkg/base/json.cpp +++ b/src/vcpkg/base/json.cpp @@ -157,6 +157,26 @@ namespace vcpkg::Json return underlying_->string; } + std::string* Value::maybe_string() noexcept + { + if (underlying_ && underlying_->tag == VK::String) + { + return &underlying_->string; + } + + return nullptr; + } + + const std::string* Value::maybe_string() const noexcept + { + if (underlying_ && underlying_->tag == VK::String) + { + return &underlying_->string; + } + + return nullptr; + } + const Array& Value::array(LineInfo li) const& noexcept { vcpkg::Checks::msg_check_exit(li, is_array(), msgJsonValueNotArray); @@ -169,6 +189,26 @@ namespace vcpkg::Json } Array&& Value::array(LineInfo li) && noexcept { return std::move(this->array(li)); } + Array* Value::maybe_array() noexcept + { + if (underlying_ && underlying_->tag == VK::Array) + { + return &underlying_->array; + } + + return nullptr; + } + + const Array* Value::maybe_array() const noexcept + { + if (underlying_ && underlying_->tag == VK::Array) + { + return &underlying_->array; + } + + return nullptr; + } + const Object& Value::object(LineInfo li) const& noexcept { vcpkg::Checks::msg_check_exit(li, is_object(), msgJsonValueNotObject); @@ -181,6 +221,26 @@ namespace vcpkg::Json } Object&& Value::object(LineInfo li) && noexcept { return std::move(this->object(li)); } + Object* Value::maybe_object() noexcept + { + if (underlying_ && underlying_->tag == VK::Object) + { + return &underlying_->object; + } + + return nullptr; + } + + const Object* Value::maybe_object() const noexcept + { + if (underlying_ && underlying_->tag == VK::Object) + { + return &underlying_->object; + } + + return nullptr; + } + Value::Value() noexcept = default; Value::Value(Value&&) noexcept = default; Value& Value::operator=(Value&&) noexcept = default; @@ -1120,9 +1180,9 @@ namespace vcpkg::Json { return parse(text, origin).then([&](ParsedJson&& mabeValueIsh) -> ExpectedL { auto& asValue = mabeValueIsh.value; - if (asValue.is_object()) + if (auto as_object = asValue.maybe_object()) { - return std::move(asValue).object(VCPKG_LINE_INFO); + return std::move(*as_object); } return msg::format(msgJsonErrorMustBeAnObject, msg::path = origin); diff --git a/src/vcpkg/binarycaching.cpp b/src/vcpkg/binarycaching.cpp index 00171cd62f..93207d06cd 100644 --- a/src/vcpkg/binarycaching.cpp +++ b/src/vcpkg/binarycaching.cpp @@ -812,10 +812,12 @@ namespace auto maybe_json = Json::parse_object(*p, m_url); if (auto json = maybe_json.get()) { - auto archive_location = json->get(JsonIdArchiveCapitalLocation); - if (archive_location && archive_location->is_string()) + if (auto archive_location = json->get(JsonIdArchiveCapitalLocation)) { - return archive_location->string(VCPKG_LINE_INFO).to_string(); + if (auto archive_location_string = archive_location->maybe_string()) + { + return *archive_location_string; + } } } } diff --git a/src/vcpkg/bundlesettings.cpp b/src/vcpkg/bundlesettings.cpp index 3d5fca9a1f..dfaebfb771 100644 --- a/src/vcpkg/bundlesettings.cpp +++ b/src/vcpkg/bundlesettings.cpp @@ -32,18 +32,17 @@ namespace bool parse_optional_json_string(const Json::Object& doc, StringLiteral field_name, Optional& output) { - auto value = doc.get(field_name); - if (!value) + if (auto value = doc.get(field_name)) { - return true; - } + if (auto value_string = value->maybe_string()) + { + output = *value_string; + return true; + } - if (!value->is_string()) - { return false; } - output = value->string(VCPKG_LINE_INFO).to_string(); return true; } } diff --git a/src/vcpkg/commands.set-installed.cpp b/src/vcpkg/commands.set-installed.cpp index 717858d3c4..7bc701e519 100644 --- a/src/vcpkg/commands.set-installed.cpp +++ b/src/vcpkg/commands.set-installed.cpp @@ -50,8 +50,12 @@ namespace vcpkg Optional create_dependency_graph_snapshot(const VcpkgCmdArguments& args, const ActionPlan& action_plan) { - if (args.github_ref.has_value() && args.github_sha.has_value() && args.github_job.has_value() && - args.github_workflow.has_value() && args.github_run_id.has_value()) + const auto github_ref = args.github_ref.get(); + const auto github_sha = args.github_sha.get(); + const auto github_job = args.github_job.get(); + const auto github_workflow = args.github_workflow.get(); + const auto github_run_id = args.github_run_id.get(); + if (github_ref && github_sha && github_job && github_workflow && github_run_id) { Json::Object detector; detector.insert(JsonIdName, Json::Value::string("vcpkg")); @@ -59,15 +63,14 @@ namespace vcpkg detector.insert(JsonIdVersion, Json::Value::string("1.0.0")); Json::Object job; - job.insert(JsonIdId, Json::Value::string(*args.github_run_id.get())); - job.insert(JsonIdCorrelator, - Json::Value::string(*args.github_workflow.get() + "-" + *args.github_job.get())); + job.insert(JsonIdId, Json::Value::string(*github_run_id)); + job.insert(JsonIdCorrelator, Json::Value::string(fmt::format("{}-{}", *github_workflow, *github_run_id))); Json::Object snapshot; snapshot.insert(JsonIdJob, job); snapshot.insert(JsonIdVersion, Json::Value::integer(0)); - snapshot.insert(JsonIdSha, Json::Value::string(*args.github_sha.get())); - snapshot.insert(JsonIdRef, Json::Value::string(*args.github_ref.get())); + snapshot.insert(JsonIdSha, Json::Value::string(*github_sha)); + snapshot.insert(JsonIdRef, Json::Value::string(*github_ref)); snapshot.insert(JsonIdScanned, Json::Value::string(CTime::now_string())); snapshot.insert(JsonIdDetector, detector); @@ -77,44 +80,45 @@ namespace vcpkg std::unordered_map map; for (auto&& action : action_plan.install_actions) { - if (!action.source_control_file_and_location.has_value()) + const auto scfl = action.source_control_file_and_location.get(); + if (!scfl) { return nullopt; } - const auto& scf = *action.source_control_file_and_location.get(); - auto version = scf.to_version().to_string(); - auto s = action.spec.to_string(); - auto pkg_url = Strings::concat("pkg:github/vcpkg/", s, "@", version); - map.insert({s, pkg_url}); + auto spec = action.spec.to_string(); + map.insert( + {spec, fmt::format("pkg:github/vcpkg/{}@{}", spec, scfl->source_control_file->to_version())}); } Json::Object resolved; for (auto&& action : action_plan.install_actions) { Json::Object resolved_item; - if (map.find(action.spec.to_string()) != map.end()) + auto spec = action.spec.to_string(); + const auto found = map.find(spec); + if (found != map.end()) { - auto pkg_url = map.at(action.spec.to_string()); + const auto& pkg_url = found->second; resolved_item.insert(JsonIdPackageUnderscoreUrl, pkg_url); resolved_item.insert(JsonIdRelationship, Json::Value::string(JsonIdDirect)); Json::Array deps_list; for (auto&& dep : action.package_dependencies) { - if (map.find(dep.to_string()) != map.end()) + const auto found_dep = map.find(dep.to_string()); + if (found_dep != map.end()) { - auto dep_pkg_url = map.at(dep.to_string()); - deps_list.push_back(dep_pkg_url); + deps_list.push_back(found_dep->second); } } resolved_item.insert(JsonIdDependencies, deps_list); resolved.insert(pkg_url, resolved_item); } } + manifest.insert(JsonIdResolved, resolved); Json::Object manifests; manifests.insert(JsonIdVcpkgDotJson, manifest); snapshot.insert(JsonIdManifests, manifests); - Debug::print(Json::stringify(snapshot)); return snapshot; } diff --git a/src/vcpkg/configuration.cpp b/src/vcpkg/configuration.cpp index 3c7f7155fa..9aa32cd370 100644 --- a/src/vcpkg/configuration.cpp +++ b/src/vcpkg/configuration.cpp @@ -441,20 +441,20 @@ namespace continue; } - if (!el.second.is_object()) + auto maybe_demand_obj = el.second.maybe_object(); + if (!maybe_demand_obj) { r.add_generic_error(type_name(), msg::format(msgJsonFieldNotObject, msg::json_field = key)); continue; } - const auto& demand_obj = el.second.object(VCPKG_LINE_INFO); - if (demand_obj.contains(JsonIdDemands)) + if (maybe_demand_obj->contains(JsonIdDemands)) { r.add_generic_error(type_name(), msg::format(msgConfigurationNestedDemands, msg::json_field = el.first)); } - auto maybe_demand = r.visit(demand_obj, CeMetadataDeserializer::instance); + auto maybe_demand = r.visit(*maybe_demand_obj, CeMetadataDeserializer::instance); if (maybe_demand.has_value()) { ret.insert_or_replace(key, maybe_demand.value_or_exit(VCPKG_LINE_INFO)); @@ -602,13 +602,14 @@ namespace auto serialize_demands = [](const Json::Object& obj, Json::Object& put_into) { if (auto demands = obj.get(JsonIdDemands)) { - if (!demands->is_object()) + auto demands_obj = demands->maybe_object(); + if (!demands_obj) { return; } Json::Object serialized_demands; - for (const auto& el : demands->object(VCPKG_LINE_INFO)) + for (const auto& el : *demands_obj) { auto key = el.first; if (Strings::starts_with(key, "$")) @@ -617,10 +618,10 @@ namespace continue; } - if (el.second.is_object()) + if (auto demand_obj = el.second.maybe_object()) { auto& inserted = serialized_demands.insert_or_replace(key, Json::Object{}); - serialize_ce_metadata(el.second.object(VCPKG_LINE_INFO), inserted); + serialize_ce_metadata(*demand_obj, inserted); } } put_into.insert_or_replace(JsonIdDemands, serialized_demands); @@ -667,12 +668,13 @@ namespace if (el.first == JsonIdDemands) { - if (!el.second.is_object()) + auto maybe_demands_object = el.second.maybe_object(); + if (!maybe_demands_object) { continue; } - for (const auto& demand : el.second.object(VCPKG_LINE_INFO)) + for (const auto& demand : *maybe_demands_object) { if (Strings::starts_with(demand.first, "$")) { @@ -840,13 +842,13 @@ namespace vcpkg } auto conf_value = std::move(conf).value(VCPKG_LINE_INFO).value; - if (!conf_value.is_object()) + if (auto conf_value_object = conf_value.maybe_object()) { - messageSink.println(msgFailedToParseNoTopLevelObj, msg::path = origin); - return nullopt; + return parse_configuration(std::move(*conf_value_object), origin, messageSink); } - return parse_configuration(std::move(conf_value).object(VCPKG_LINE_INFO), origin, messageSink); + messageSink.println(msgFailedToParseNoTopLevelObj, msg::path = origin); + return nullopt; } Optional parse_configuration(const Json::Object& obj, StringView origin, MessageSink& messageSink) diff --git a/src/vcpkg/configure-environment.cpp b/src/vcpkg/configure-environment.cpp index 75f65ec7b3..f36a3d2e6f 100644 --- a/src/vcpkg/configure-environment.cpp +++ b/src/vcpkg/configure-environment.cpp @@ -42,30 +42,32 @@ namespace return; } - auto acquired_artifacts = pparsed->get(JsonIdAcquiredArtifacts); - if (acquired_artifacts) + if (auto acquired_artifacts = pparsed->get(JsonIdAcquiredArtifacts)) { - if (acquired_artifacts->is_string()) + if (auto maybe_acquired_string = acquired_artifacts->maybe_string()) { - get_global_metrics_collector().track_string(StringMetric::AcquiredArtifacts, - acquired_artifacts->string(VCPKG_LINE_INFO)); + get_global_metrics_collector().track_string(StringMetric::AcquiredArtifacts, *maybe_acquired_string); + } + else + { + Debug::println("Acquired artifacts was not a string."); } - Debug::println("Acquired artifacts was not a string."); } else { Debug::println("No artifacts acquired."); } - auto activated_artifacts = pparsed->get(JsonIdActivatedArtifacts); - if (activated_artifacts) + if (auto activated_artifacts = pparsed->get(JsonIdActivatedArtifacts)) { - if (activated_artifacts->is_string()) + if (auto maybe_activated_string = activated_artifacts->maybe_string()) + { + get_global_metrics_collector().track_string(StringMetric::ActivatedArtifacts, *maybe_activated_string); + } + else { - get_global_metrics_collector().track_string(StringMetric::ActivatedArtifacts, - activated_artifacts->string(VCPKG_LINE_INFO)); + Debug::println("Activated artifacts was not a string."); } - Debug::println("Activated artifacts was not a string."); } else { diff --git a/src/vcpkg/sourceparagraph.cpp b/src/vcpkg/sourceparagraph.cpp index 52ecabaf94..1a581431ab 100644 --- a/src/vcpkg/sourceparagraph.cpp +++ b/src/vcpkg/sourceparagraph.cpp @@ -1194,9 +1194,9 @@ namespace vcpkg if (auto configuration = obj.get(JsonIdVcpkgConfiguration)) { - if (configuration->is_object()) + if (auto configuration_object = configuration->maybe_object()) { - spgh.vcpkg_configuration.emplace(configuration->object(VCPKG_LINE_INFO)); + spgh.vcpkg_configuration.emplace(*configuration_object); } else { diff --git a/src/vcpkg/spdx.cpp b/src/vcpkg/spdx.cpp index bcaba964b6..fd1ae3d842 100644 --- a/src/vcpkg/spdx.cpp +++ b/src/vcpkg/spdx.cpp @@ -24,9 +24,9 @@ static void append_move_if_exists_and_array(Json::Array& out, Json::Object& obj, { if (auto p = obj.get(property)) { - if (p->is_array()) + if (auto arr = p->maybe_array()) { - for (auto& e : p->array(VCPKG_LINE_INFO)) + for (auto& e : *arr) { out.push_back(std::move(e)); } diff --git a/src/vcpkg/vcpkgpaths.cpp b/src/vcpkg/vcpkgpaths.cpp index 8635927c72..9ca9881240 100644 --- a/src/vcpkg/vcpkgpaths.cpp +++ b/src/vcpkg/vcpkgpaths.cpp @@ -435,30 +435,32 @@ namespace { auto repo = repo_to_ref_info_value.first; const auto& ref_info_value = repo_to_ref_info_value.second; - - if (!ref_info_value.is_object()) + if (auto ref_info_value_object = ref_info_value.maybe_object()) { - Debug::print("Lockfile value for key '", repo, "' was not an object\n"); - return ret; - } + for (auto&& reference_to_commit : *ref_info_value_object) + { + auto reference = reference_to_commit.first; + const auto& commit = reference_to_commit.second; + if (auto commit_string = commit.maybe_string()) + { + if (!is_git_commit_sha(*commit_string)) + { + Debug::print("Lockfile value for key '", reference, "' was not a commit sha\n"); + return ret; + } - for (auto&& reference_to_commit : ref_info_value.object(VCPKG_LINE_INFO)) - { - auto reference = reference_to_commit.first; - const auto& commit = reference_to_commit.second; + ret.emplace(repo.to_string(), LockFile::EntryData{reference.to_string(), *commit_string, true}); + continue; + } - if (!commit.is_string()) - { - Debug::print("Lockfile value for key '", reference, "' was not a string\n"); - return ret; - } - auto sv = commit.string(VCPKG_LINE_INFO); - if (!is_git_commit_sha(sv)) - { Debug::print("Lockfile value for key '", reference, "' was not a string\n"); return ret; } - ret.emplace(repo.to_string(), LockFile::EntryData{reference.to_string(), sv.to_string(), true}); + } + else + { + Debug::print("Lockfile value for key '", repo, "' was not an object\n"); + return ret; } } return ret;