| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include <functional> |
| #include <map> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <cm/memory> |
| #include <cm/optional> |
| #include <cmext/string_view> |
| |
| #include <cm3p/json/reader.h> |
| #include <cm3p/json/value.h> |
| |
| #include "cmsys/FStream.hxx" |
| |
| #include "cmCMakePresetsFile.h" |
| #include "cmCMakePresetsFileInternal.h" |
| #include "cmJSONHelpers.h" |
| #include "cmVersion.h" |
| |
| namespace { |
| using ReadFileResult = cmCMakePresetsFile::ReadFileResult; |
| using CacheVariable = cmCMakePresetsFile::CacheVariable; |
| using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset; |
| using BuildPreset = cmCMakePresetsFile::BuildPreset; |
| using TestPreset = cmCMakePresetsFile::TestPreset; |
| using ArchToolsetStrategy = cmCMakePresetsFile::ArchToolsetStrategy; |
| |
| constexpr int MIN_VERSION = 1; |
| constexpr int MAX_VERSION = 3; |
| |
| struct CMakeVersion |
| { |
| unsigned int Major = 0; |
| unsigned int Minor = 0; |
| unsigned int Patch = 0; |
| }; |
| |
| struct RootPresets |
| { |
| CMakeVersion CMakeMinimumRequired; |
| std::vector<cmCMakePresetsFile::ConfigurePreset> ConfigurePresets; |
| std::vector<cmCMakePresetsFile::BuildPreset> BuildPresets; |
| std::vector<cmCMakePresetsFile::TestPreset> TestPresets; |
| }; |
| |
| std::unique_ptr<cmCMakePresetsFileInternal::NotCondition> InvertCondition( |
| std::unique_ptr<cmCMakePresetsFile::Condition> condition) |
| { |
| auto retval = cm::make_unique<cmCMakePresetsFileInternal::NotCondition>(); |
| retval->SubCondition = std::move(condition); |
| return retval; |
| } |
| |
| auto const ConditionStringHelper = cmJSONStringHelper<ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION); |
| |
| auto const ConditionBoolHelper = cmJSONBoolHelper<ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION); |
| |
| auto const ConditionStringListHelper = |
| cmJSONVectorHelper<std::string, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, |
| ConditionStringHelper); |
| |
| auto const ConstConditionHelper = |
| cmJSONObjectHelper<cmCMakePresetsFileInternal::ConstCondition, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| ReadFileResult::INVALID_CONDITION, false) |
| .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) |
| .Bind("value"_s, &cmCMakePresetsFileInternal::ConstCondition::Value, |
| ConditionBoolHelper, true); |
| |
| auto const EqualsConditionHelper = |
| cmJSONObjectHelper<cmCMakePresetsFileInternal::EqualsCondition, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| ReadFileResult::INVALID_CONDITION, false) |
| .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) |
| .Bind("lhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Lhs, |
| ConditionStringHelper, true) |
| .Bind("rhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Rhs, |
| ConditionStringHelper, true); |
| |
| auto const InListConditionHelper = |
| cmJSONObjectHelper<cmCMakePresetsFileInternal::InListCondition, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| ReadFileResult::INVALID_CONDITION, false) |
| .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) |
| .Bind("string"_s, &cmCMakePresetsFileInternal::InListCondition::String, |
| ConditionStringHelper, true) |
| .Bind("list"_s, &cmCMakePresetsFileInternal::InListCondition::List, |
| ConditionStringListHelper, true); |
| |
| auto const MatchesConditionHelper = |
| cmJSONObjectHelper<cmCMakePresetsFileInternal::MatchesCondition, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| ReadFileResult::INVALID_CONDITION, false) |
| .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) |
| .Bind("string"_s, &cmCMakePresetsFileInternal::MatchesCondition::String, |
| ConditionStringHelper, true) |
| .Bind("regex"_s, &cmCMakePresetsFileInternal::MatchesCondition::Regex, |
| ConditionStringHelper, true); |
| |
| ReadFileResult SubConditionHelper( |
| std::unique_ptr<cmCMakePresetsFile::Condition>& out, |
| const Json::Value* value); |
| |
| auto const ListConditionVectorHelper = |
| cmJSONVectorHelper<std::unique_ptr<cmCMakePresetsFile::Condition>, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| ReadFileResult::INVALID_CONDITION, |
| SubConditionHelper); |
| auto const AnyAllOfConditionHelper = |
| cmJSONObjectHelper<cmCMakePresetsFileInternal::AnyAllOfCondition, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| ReadFileResult::INVALID_CONDITION, false) |
| .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) |
| .Bind("conditions"_s, |
| &cmCMakePresetsFileInternal::AnyAllOfCondition::Conditions, |
| ListConditionVectorHelper); |
| |
| auto const NotConditionHelper = |
| cmJSONObjectHelper<cmCMakePresetsFileInternal::NotCondition, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false) |
| .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) |
| .Bind("condition"_s, |
| &cmCMakePresetsFileInternal::NotCondition::SubCondition, |
| SubConditionHelper); |
| |
| ReadFileResult ConditionHelper( |
| std::unique_ptr<cmCMakePresetsFile::Condition>& out, |
| const Json::Value* value) |
| { |
| if (!value) { |
| out.reset(); |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->isBool()) { |
| auto c = cm::make_unique<cmCMakePresetsFileInternal::ConstCondition>(); |
| c->Value = value->asBool(); |
| out = std::move(c); |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->isNull()) { |
| out = cm::make_unique<cmCMakePresetsFileInternal::NullCondition>(); |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->isObject()) { |
| if (!value->isMember("type")) { |
| return ReadFileResult::INVALID_CONDITION; |
| } |
| |
| if (!(*value)["type"].isString()) { |
| return ReadFileResult::INVALID_CONDITION; |
| } |
| auto type = (*value)["type"].asString(); |
| |
| if (type == "const") { |
| auto c = cm::make_unique<cmCMakePresetsFileInternal::ConstCondition>(); |
| CHECK_OK(ConstConditionHelper(*c, value)); |
| out = std::move(c); |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (type == "equals" || type == "notEquals") { |
| auto c = cm::make_unique<cmCMakePresetsFileInternal::EqualsCondition>(); |
| CHECK_OK(EqualsConditionHelper(*c, value)); |
| out = std::move(c); |
| if (type == "notEquals") { |
| out = InvertCondition(std::move(out)); |
| } |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (type == "inList" || type == "notInList") { |
| auto c = cm::make_unique<cmCMakePresetsFileInternal::InListCondition>(); |
| CHECK_OK(InListConditionHelper(*c, value)); |
| out = std::move(c); |
| if (type == "notInList") { |
| out = InvertCondition(std::move(out)); |
| } |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (type == "matches" || type == "notMatches") { |
| auto c = cm::make_unique<cmCMakePresetsFileInternal::MatchesCondition>(); |
| CHECK_OK(MatchesConditionHelper(*c, value)); |
| out = std::move(c); |
| if (type == "notMatches") { |
| out = InvertCondition(std::move(out)); |
| } |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (type == "anyOf" || type == "allOf") { |
| auto c = |
| cm::make_unique<cmCMakePresetsFileInternal::AnyAllOfCondition>(); |
| c->StopValue = (type == "anyOf"); |
| CHECK_OK(AnyAllOfConditionHelper(*c, value)); |
| out = std::move(c); |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (type == "not") { |
| auto c = cm::make_unique<cmCMakePresetsFileInternal::NotCondition>(); |
| CHECK_OK(NotConditionHelper(*c, value)); |
| out = std::move(c); |
| return ReadFileResult::READ_OK; |
| } |
| } |
| |
| return ReadFileResult::INVALID_CONDITION; |
| } |
| |
| ReadFileResult PresetConditionHelper( |
| std::shared_ptr<cmCMakePresetsFile::Condition>& out, |
| const Json::Value* value) |
| { |
| std::unique_ptr<cmCMakePresetsFile::Condition> ptr; |
| auto result = ConditionHelper(ptr, value); |
| out = std::move(ptr); |
| return result; |
| } |
| |
| ReadFileResult SubConditionHelper( |
| std::unique_ptr<cmCMakePresetsFile::Condition>& out, |
| const Json::Value* value) |
| { |
| std::unique_ptr<cmCMakePresetsFile::Condition> ptr; |
| auto result = ConditionHelper(ptr, value); |
| if (ptr && ptr->IsNull()) { |
| return ReadFileResult::INVALID_CONDITION; |
| } |
| out = std::move(ptr); |
| return result; |
| } |
| |
| cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error) |
| { |
| return [error](std::nullptr_t& /*out*/, |
| const Json::Value* value) -> ReadFileResult { |
| if (!value) { |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (!value->isObject()) { |
| return error; |
| } |
| |
| return ReadFileResult::READ_OK; |
| }; |
| } |
| |
| auto const VersionIntHelper = cmJSONIntHelper<ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION); |
| |
| auto const VersionHelper = cmJSONRequiredHelper<int, ReadFileResult>( |
| ReadFileResult::NO_VERSION, VersionIntHelper); |
| |
| auto const RootVersionHelper = |
| cmJSONObjectHelper<int, ReadFileResult>(ReadFileResult::READ_OK, |
| ReadFileResult::INVALID_ROOT) |
| .Bind("version"_s, VersionHelper, false); |
| |
| auto const VariableStringHelper = cmJSONStringHelper<ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE); |
| |
| ReadFileResult VariableValueHelper(std::string& out, const Json::Value* value) |
| { |
| if (!value) { |
| out.clear(); |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->isBool()) { |
| out = value->asBool() ? "TRUE" : "FALSE"; |
| return ReadFileResult::READ_OK; |
| } |
| |
| return VariableStringHelper(out, value); |
| } |
| |
| auto const VariableObjectHelper = |
| cmJSONObjectHelper<CacheVariable, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false) |
| .Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false) |
| .Bind("value"_s, &CacheVariable::Value, VariableValueHelper); |
| |
| ReadFileResult VariableHelper(cm::optional<CacheVariable>& out, |
| const Json::Value* value) |
| { |
| if (value->isBool()) { |
| out = CacheVariable{ |
| /*Type=*/"BOOL", |
| /*Value=*/value->asBool() ? "TRUE" : "FALSE", |
| }; |
| return ReadFileResult::READ_OK; |
| } |
| if (value->isString()) { |
| out = CacheVariable{ |
| /*Type=*/"", |
| /*Value=*/value->asString(), |
| }; |
| return ReadFileResult::READ_OK; |
| } |
| if (value->isObject()) { |
| out.emplace(); |
| return VariableObjectHelper(*out, value); |
| } |
| if (value->isNull()) { |
| out = cm::nullopt; |
| return ReadFileResult::READ_OK; |
| } |
| return ReadFileResult::INVALID_VARIABLE; |
| } |
| |
| auto const VariablesHelper = |
| cmJSONMapHelper<cm::optional<CacheVariable>, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper); |
| |
| auto const PresetStringHelper = cmJSONStringHelper<ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); |
| |
| ReadFileResult EnvironmentHelper(cm::optional<std::string>& out, |
| const Json::Value* value) |
| { |
| if (!value || value->isNull()) { |
| out = cm::nullopt; |
| return ReadFileResult::READ_OK; |
| } |
| if (value->isString()) { |
| out = value->asString(); |
| return ReadFileResult::READ_OK; |
| } |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| auto const EnvironmentMapHelper = |
| cmJSONMapHelper<cm::optional<std::string>, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, |
| EnvironmentHelper); |
| |
| auto const PresetVectorStringHelper = |
| cmJSONVectorHelper<std::string, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, |
| PresetStringHelper); |
| |
| ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out, |
| const Json::Value* value) |
| { |
| out.clear(); |
| if (!value) { |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->isString()) { |
| out.push_back(value->asString()); |
| return ReadFileResult::READ_OK; |
| } |
| |
| return PresetVectorStringHelper(out, value); |
| } |
| |
| auto const PresetBoolHelper = cmJSONBoolHelper<ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); |
| |
| auto const PresetOptionalBoolHelper = |
| cmJSONOptionalHelper<bool, ReadFileResult>(ReadFileResult::READ_OK, |
| PresetBoolHelper); |
| |
| auto const PresetIntHelper = cmJSONIntHelper<ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); |
| |
| auto const PresetOptionalIntHelper = cmJSONOptionalHelper<int, ReadFileResult>( |
| ReadFileResult::READ_OK, PresetIntHelper); |
| |
| auto const PresetVectorIntHelper = cmJSONVectorHelper<int, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper); |
| |
| auto const PresetWarningsHelper = |
| cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) |
| .Bind("dev"_s, &ConfigurePreset::WarnDev, PresetOptionalBoolHelper, false) |
| .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated, |
| PresetOptionalBoolHelper, false) |
| .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized, |
| PresetOptionalBoolHelper, false) |
| .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli, |
| PresetOptionalBoolHelper, false) |
| .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars, |
| PresetOptionalBoolHelper, false); |
| |
| auto const PresetErrorsHelper = |
| cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) |
| .Bind("dev"_s, &ConfigurePreset::ErrorDev, PresetOptionalBoolHelper, false) |
| .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated, |
| PresetOptionalBoolHelper, false); |
| |
| auto const PresetDebugHelper = |
| cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) |
| .Bind("output"_s, &ConfigurePreset::DebugOutput, PresetOptionalBoolHelper, |
| false) |
| .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile, |
| PresetOptionalBoolHelper, false) |
| .Bind("find"_s, &ConfigurePreset::DebugFind, PresetOptionalBoolHelper, |
| false); |
| |
| ReadFileResult ArchToolsetStrategyHelper( |
| cm::optional<ArchToolsetStrategy>& out, const Json::Value* value) |
| { |
| if (!value) { |
| out = cm::nullopt; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (!value->isString()) { |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| if (value->asString() == "set") { |
| out = ArchToolsetStrategy::Set; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->asString() == "external") { |
| out = ArchToolsetStrategy::External; |
| return ReadFileResult::READ_OK; |
| } |
| |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)> |
| ArchToolsetHelper( |
| std::string ConfigurePreset::*valueField, |
| cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField) |
| { |
| auto const objectHelper = |
| cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) |
| .Bind("value", valueField, PresetStringHelper, false) |
| .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false); |
| return [valueField, strategyField, objectHelper]( |
| ConfigurePreset& out, const Json::Value* value) -> ReadFileResult { |
| if (!value) { |
| (out.*valueField).clear(); |
| out.*strategyField = cm::nullopt; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->isString()) { |
| out.*valueField = value->asString(); |
| out.*strategyField = cm::nullopt; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->isObject()) { |
| return objectHelper(out, value); |
| } |
| |
| return ReadFileResult::INVALID_PRESET; |
| }; |
| } |
| |
| auto const ArchitectureHelper = ArchToolsetHelper( |
| &ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy); |
| auto const ToolsetHelper = ArchToolsetHelper( |
| &ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy); |
| |
| auto const ConfigurePresetHelper = |
| cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) |
| .Bind("name"_s, &ConfigurePreset::Name, PresetStringHelper) |
| .Bind("inherits"_s, &ConfigurePreset::Inherits, |
| PresetVectorOneOrMoreStringHelper, false) |
| .Bind("hidden"_s, &ConfigurePreset::Hidden, PresetBoolHelper, false) |
| .Bind<std::nullptr_t>("vendor"_s, nullptr, |
| VendorHelper(ReadFileResult::INVALID_PRESET), false) |
| .Bind("displayName"_s, &ConfigurePreset::DisplayName, PresetStringHelper, |
| false) |
| .Bind("description"_s, &ConfigurePreset::Description, PresetStringHelper, |
| false) |
| .Bind("generator"_s, &ConfigurePreset::Generator, PresetStringHelper, |
| false) |
| .Bind("architecture"_s, ArchitectureHelper, false) |
| .Bind("toolset"_s, ToolsetHelper, false) |
| .Bind("toolchainFile"_s, &ConfigurePreset::ToolchainFile, |
| PresetStringHelper, false) |
| .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir, PresetStringHelper, |
| false) |
| .Bind("installDir"_s, &ConfigurePreset::InstallDir, PresetStringHelper, |
| false) |
| .Bind<std::string>("cmakeExecutable"_s, nullptr, PresetStringHelper, false) |
| .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables, |
| VariablesHelper, false) |
| .Bind("environment"_s, &ConfigurePreset::Environment, EnvironmentMapHelper, |
| false) |
| .Bind("warnings"_s, PresetWarningsHelper, false) |
| .Bind("errors"_s, PresetErrorsHelper, false) |
| .Bind("debug"_s, PresetDebugHelper, false) |
| .Bind("condition"_s, &ConfigurePreset::ConditionEvaluator, |
| PresetConditionHelper, false); |
| |
| auto const BuildPresetHelper = |
| cmJSONObjectHelper<BuildPreset, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) |
| .Bind("name"_s, &BuildPreset::Name, PresetStringHelper) |
| .Bind("inherits"_s, &BuildPreset::Inherits, |
| PresetVectorOneOrMoreStringHelper, false) |
| .Bind("hidden"_s, &BuildPreset::Hidden, PresetBoolHelper, false) |
| .Bind<std::nullptr_t>("vendor"_s, nullptr, |
| VendorHelper(ReadFileResult::INVALID_PRESET), false) |
| .Bind("displayName"_s, &BuildPreset::DisplayName, PresetStringHelper, |
| false) |
| .Bind("description"_s, &BuildPreset::Description, PresetStringHelper, |
| false) |
| .Bind("environment"_s, &BuildPreset::Environment, EnvironmentMapHelper, |
| false) |
| .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset, |
| PresetStringHelper, false) |
| .Bind("inheritConfigureEnvironment"_s, |
| &BuildPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper, |
| false) |
| .Bind("jobs"_s, &BuildPreset::Jobs, PresetOptionalIntHelper, false) |
| .Bind("targets"_s, &BuildPreset::Targets, |
| PresetVectorOneOrMoreStringHelper, false) |
| .Bind("configuration"_s, &BuildPreset::Configuration, PresetStringHelper, |
| false) |
| .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, PresetOptionalBoolHelper, |
| false) |
| .Bind("verbose"_s, &BuildPreset::Verbose, PresetOptionalBoolHelper, false) |
| .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions, |
| PresetVectorStringHelper, false) |
| .Bind("condition"_s, &BuildPreset::ConditionEvaluator, |
| PresetConditionHelper, false); |
| |
| ReadFileResult TestPresetOutputVerbosityHelper( |
| TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value) |
| { |
| if (!value) { |
| out = TestPreset::OutputOptions::VerbosityEnum::Default; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (!value->isString()) { |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| if (value->asString() == "default") { |
| out = TestPreset::OutputOptions::VerbosityEnum::Default; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->asString() == "verbose") { |
| out = TestPreset::OutputOptions::VerbosityEnum::Verbose; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->asString() == "extra") { |
| out = TestPreset::OutputOptions::VerbosityEnum::Extra; |
| return ReadFileResult::READ_OK; |
| } |
| |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| auto const TestPresetOptionalOutputVerbosityHelper = |
| cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| TestPresetOutputVerbosityHelper); |
| |
| auto const TestPresetOptionalOutputHelper = |
| cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>( |
| ReadFileResult::READ_OK, |
| cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) |
| .Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress, |
| PresetOptionalBoolHelper, false) |
| .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity, |
| TestPresetOptionalOutputVerbosityHelper, false) |
| .Bind("debug"_s, &TestPreset::OutputOptions::Debug, |
| PresetOptionalBoolHelper, false) |
| .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure, |
| PresetOptionalBoolHelper, false) |
| .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet, |
| PresetOptionalBoolHelper, false) |
| .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile, |
| PresetStringHelper, false) |
| .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary, |
| PresetOptionalBoolHelper, false) |
| .Bind("subprojectSummary"_s, |
| &TestPreset::OutputOptions::SubprojectSummary, |
| PresetOptionalBoolHelper, false) |
| .Bind("maxPassedTestOutputSize"_s, |
| &TestPreset::OutputOptions::MaxPassedTestOutputSize, |
| PresetOptionalIntHelper, false) |
| .Bind("maxFailedTestOutputSize"_s, |
| &TestPreset::OutputOptions::MaxFailedTestOutputSize, |
| PresetOptionalIntHelper, false) |
| .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth, |
| PresetOptionalIntHelper, false)); |
| |
| auto const TestPresetOptionalFilterIncludeIndexObjectHelper = |
| cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions, |
| ReadFileResult>( |
| ReadFileResult::READ_OK, |
| cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| ReadFileResult::INVALID_PRESET) |
| .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start, |
| PresetOptionalIntHelper, false) |
| .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End, |
| PresetOptionalIntHelper, false) |
| .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride, |
| PresetOptionalIntHelper, false) |
| .Bind("specificTests"_s, |
| &TestPreset::IncludeOptions::IndexOptions::SpecificTests, |
| PresetVectorIntHelper, false)); |
| |
| ReadFileResult TestPresetOptionalFilterIncludeIndexHelper( |
| cm::optional<TestPreset::IncludeOptions::IndexOptions>& out, |
| const Json::Value* value) |
| { |
| if (!value) { |
| out = cm::nullopt; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->isString()) { |
| out.emplace(); |
| out->IndexFile = value->asString(); |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->isObject()) { |
| return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value); |
| } |
| |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| auto const TestPresetOptionalFilterIncludeHelper = |
| cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>( |
| ReadFileResult::READ_OK, |
| cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) |
| .Bind("name"_s, &TestPreset::IncludeOptions::Name, PresetStringHelper, |
| false) |
| .Bind("label"_s, &TestPreset::IncludeOptions::Label, PresetStringHelper, |
| false) |
| .Bind("index"_s, &TestPreset::IncludeOptions::Index, |
| TestPresetOptionalFilterIncludeIndexHelper, false) |
| .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion, |
| PresetOptionalBoolHelper, false)); |
| |
| auto const TestPresetOptionalFilterExcludeFixturesHelper = |
| cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions, |
| ReadFileResult>( |
| ReadFileResult::READ_OK, |
| cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| ReadFileResult::INVALID_PRESET) |
| .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any, |
| PresetStringHelper, false) |
| .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup, |
| PresetStringHelper, false) |
| .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup, |
| PresetStringHelper, false)); |
| |
| auto const TestPresetOptionalFilterExcludeHelper = |
| cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>( |
| ReadFileResult::READ_OK, |
| cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) |
| .Bind("name"_s, &TestPreset::ExcludeOptions::Name, PresetStringHelper, |
| false) |
| .Bind("label"_s, &TestPreset::ExcludeOptions::Label, PresetStringHelper, |
| false) |
| .Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures, |
| TestPresetOptionalFilterExcludeFixturesHelper, false)); |
| |
| ReadFileResult TestPresetExecutionShowOnlyHelper( |
| TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value) |
| { |
| if (!value || !value->isString()) { |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| if (value->asString() == "human") { |
| out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->asString() == "json-v1") { |
| out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1; |
| return ReadFileResult::READ_OK; |
| } |
| |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| auto const TestPresetOptionalExecutionShowOnlyHelper = |
| cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| TestPresetExecutionShowOnlyHelper); |
| |
| ReadFileResult TestPresetExecutionModeHelper( |
| TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out, |
| const Json::Value* value) |
| { |
| if (!value) { |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (!value->isString()) { |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| if (value->asString() == "until-fail") { |
| out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->asString() == "until-pass") { |
| out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->asString() == "after-timeout") { |
| out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout; |
| return ReadFileResult::READ_OK; |
| } |
| |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| auto const TestPresetOptionalExecutionRepeatHelper = |
| cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions, |
| ReadFileResult>( |
| ReadFileResult::READ_OK, |
| cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| ReadFileResult::INVALID_PRESET) |
| .Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode, |
| TestPresetExecutionModeHelper, true) |
| .Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count, |
| PresetIntHelper, true)); |
| |
| ReadFileResult TestPresetExecutionNoTestsActionHelper( |
| TestPreset::ExecutionOptions::NoTestsActionEnum& out, |
| const Json::Value* value) |
| { |
| if (!value) { |
| out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (!value->isString()) { |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| if (value->asString() == "default") { |
| out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->asString() == "error") { |
| out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error; |
| return ReadFileResult::READ_OK; |
| } |
| |
| if (value->asString() == "ignore") { |
| out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore; |
| return ReadFileResult::READ_OK; |
| } |
| |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| auto const TestPresetOptionalExecutionNoTestsActionHelper = |
| cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum, |
| ReadFileResult>(ReadFileResult::READ_OK, |
| TestPresetExecutionNoTestsActionHelper); |
| |
| auto const TestPresetExecutionHelper = |
| cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>( |
| ReadFileResult::READ_OK, |
| cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) |
| .Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure, |
| PresetOptionalBoolHelper, false) |
| .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover, |
| PresetOptionalBoolHelper, false) |
| .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs, |
| PresetOptionalIntHelper, false) |
| .Bind("resourceSpecFile"_s, |
| &TestPreset::ExecutionOptions::ResourceSpecFile, |
| PresetStringHelper, false) |
| .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad, |
| PresetOptionalIntHelper, false) |
| .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly, |
| TestPresetOptionalExecutionShowOnlyHelper, false) |
| .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat, |
| TestPresetOptionalExecutionRepeatHelper, false) |
| .Bind("interactiveDebugging"_s, |
| &TestPreset::ExecutionOptions::InteractiveDebugging, |
| PresetOptionalBoolHelper, false) |
| .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom, |
| PresetOptionalBoolHelper, false) |
| .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout, |
| PresetOptionalIntHelper, false) |
| .Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction, |
| TestPresetOptionalExecutionNoTestsActionHelper, false)); |
| |
| auto const TestPresetFilterHelper = |
| cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>( |
| ReadFileResult::READ_OK, |
| cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) |
| .Bind("include"_s, &TestPreset::FilterOptions::Include, |
| TestPresetOptionalFilterIncludeHelper, false) |
| .Bind("exclude"_s, &TestPreset::FilterOptions::Exclude, |
| TestPresetOptionalFilterExcludeHelper, false)); |
| |
| auto const TestPresetHelper = |
| cmJSONObjectHelper<TestPreset, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) |
| .Bind("name"_s, &TestPreset::Name, PresetStringHelper) |
| .Bind("inherits"_s, &TestPreset::Inherits, |
| PresetVectorOneOrMoreStringHelper, false) |
| .Bind("hidden"_s, &TestPreset::Hidden, PresetBoolHelper, false) |
| .Bind<std::nullptr_t>("vendor"_s, nullptr, |
| VendorHelper(ReadFileResult::INVALID_PRESET), false) |
| .Bind("displayName"_s, &TestPreset::DisplayName, PresetStringHelper, false) |
| .Bind("description"_s, &TestPreset::Description, PresetStringHelper, false) |
| .Bind("environment"_s, &TestPreset::Environment, EnvironmentMapHelper, |
| false) |
| .Bind("configurePreset"_s, &TestPreset::ConfigurePreset, |
| PresetStringHelper, false) |
| .Bind("inheritConfigureEnvironment"_s, |
| &TestPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper, |
| false) |
| .Bind("configuration"_s, &TestPreset::Configuration, PresetStringHelper, |
| false) |
| .Bind("overwriteConfigurationFile"_s, |
| &TestPreset::OverwriteConfigurationFile, PresetVectorStringHelper, |
| false) |
| .Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper, |
| false) |
| .Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false) |
| .Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper, |
| false) |
| .Bind("condition"_s, &TestPreset::ConditionEvaluator, |
| PresetConditionHelper, false); |
| |
| auto const ConfigurePresetsHelper = |
| cmJSONVectorHelper<ConfigurePreset, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, |
| ConfigurePresetHelper); |
| |
| auto const BuildPresetsHelper = |
| cmJSONVectorHelper<BuildPreset, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, |
| BuildPresetHelper); |
| |
| auto const TestPresetsHelper = cmJSONVectorHelper<TestPreset, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, TestPresetHelper); |
| |
| auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION); |
| |
| auto const CMakeVersionHelper = |
| cmJSONObjectHelper<CMakeVersion, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false) |
| .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false) |
| .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false) |
| .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false); |
| |
| auto const RootPresetsHelper = |
| cmJSONObjectHelper<RootPresets, ReadFileResult>( |
| ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false) |
| .Bind<int>("version"_s, nullptr, VersionHelper) |
| .Bind("configurePresets"_s, &RootPresets::ConfigurePresets, |
| ConfigurePresetsHelper, false) |
| .Bind("buildPresets"_s, &RootPresets::BuildPresets, BuildPresetsHelper, |
| false) |
| .Bind("testPresets"_s, &RootPresets::TestPresets, TestPresetsHelper, false) |
| .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired, |
| CMakeVersionHelper, false) |
| .Bind<std::nullptr_t>("vendor"_s, nullptr, |
| VendorHelper(ReadFileResult::INVALID_ROOT), false); |
| } |
| |
| cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile( |
| const std::string& filename, bool user) |
| { |
| cmsys::ifstream fin(filename.c_str()); |
| if (!fin) { |
| return ReadFileResult::FILE_NOT_FOUND; |
| } |
| // If there's a BOM, toss it. |
| cmsys::FStream::ReadBOM(fin); |
| |
| Json::Value root; |
| Json::CharReaderBuilder builder; |
| Json::CharReaderBuilder::strictMode(&builder.settings_); |
| if (!Json::parseFromStream(builder, fin, &root, nullptr)) { |
| return ReadFileResult::JSON_PARSE_ERROR; |
| } |
| |
| int v = 0; |
| auto result = RootVersionHelper(v, &root); |
| if (result != ReadFileResult::READ_OK) { |
| return result; |
| } |
| if (v < MIN_VERSION || v > MAX_VERSION) { |
| return ReadFileResult::UNRECOGNIZED_VERSION; |
| } |
| if (user) { |
| this->UserVersion = v; |
| } else { |
| this->Version = v; |
| } |
| |
| // Support for build and test presets added in version 2. |
| if (v < 2 && |
| (root.isMember("buildPresets") || root.isMember("testPresets"))) { |
| return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED; |
| } |
| |
| RootPresets presets; |
| if ((result = RootPresetsHelper(presets, &root)) != |
| ReadFileResult::READ_OK) { |
| return result; |
| } |
| |
| unsigned int currentMajor = cmVersion::GetMajorVersion(); |
| unsigned int currentMinor = cmVersion::GetMinorVersion(); |
| unsigned int currentPatch = cmVersion::GetPatchVersion(); |
| auto const& required = presets.CMakeMinimumRequired; |
| if (required.Major > currentMajor || |
| (required.Major == currentMajor && |
| (required.Minor > currentMinor || |
| (required.Minor == currentMinor && |
| (required.Patch > currentPatch))))) { |
| return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION; |
| } |
| |
| for (auto& preset : presets.ConfigurePresets) { |
| preset.User = user; |
| if (preset.Name.empty()) { |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| PresetPair<ConfigurePreset> presetPair; |
| presetPair.Unexpanded = preset; |
| presetPair.Expanded = cm::nullopt; |
| if (!this->ConfigurePresets |
| .emplace(std::make_pair(preset.Name, presetPair)) |
| .second) { |
| return ReadFileResult::DUPLICATE_PRESETS; |
| } |
| |
| // Support for installDir presets added in version 3. |
| if (v < 3 && !preset.InstallDir.empty()) { |
| return ReadFileResult::INSTALL_PREFIX_UNSUPPORTED; |
| } |
| |
| // Support for conditions added in version 3. |
| if (v < 3 && preset.ConditionEvaluator) { |
| return ReadFileResult::CONDITION_UNSUPPORTED; |
| } |
| |
| // Support for toolchainFile presets added in version 3. |
| if (v < 3 && !preset.ToolchainFile.empty()) { |
| return ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED; |
| } |
| |
| this->ConfigurePresetOrder.push_back(preset.Name); |
| } |
| |
| for (auto& preset : presets.BuildPresets) { |
| preset.User = user; |
| if (preset.Name.empty()) { |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| PresetPair<BuildPreset> presetPair; |
| presetPair.Unexpanded = preset; |
| presetPair.Expanded = cm::nullopt; |
| if (!this->BuildPresets.emplace(preset.Name, presetPair).second) { |
| return ReadFileResult::DUPLICATE_PRESETS; |
| } |
| |
| // Support for conditions added in version 3. |
| if (v < 3 && preset.ConditionEvaluator) { |
| return ReadFileResult::CONDITION_UNSUPPORTED; |
| } |
| |
| this->BuildPresetOrder.push_back(preset.Name); |
| } |
| |
| for (auto& preset : presets.TestPresets) { |
| preset.User = user; |
| if (preset.Name.empty()) { |
| return ReadFileResult::INVALID_PRESET; |
| } |
| |
| PresetPair<TestPreset> presetPair; |
| presetPair.Unexpanded = preset; |
| presetPair.Expanded = cm::nullopt; |
| if (!this->TestPresets.emplace(preset.Name, presetPair).second) { |
| return ReadFileResult::DUPLICATE_PRESETS; |
| } |
| |
| // Support for conditions added in version 3. |
| if (v < 3 && preset.ConditionEvaluator) { |
| return ReadFileResult::CONDITION_UNSUPPORTED; |
| } |
| |
| this->TestPresetOrder.push_back(preset.Name); |
| } |
| |
| return ReadFileResult::READ_OK; |
| } |