/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include #include #include #include #include #include #include #include #include #include #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 ConfigurePresets; std::vector BuildPresets; std::vector TestPresets; }; std::unique_ptr InvertCondition( std::unique_ptr condition) { auto retval = cm::make_unique(); retval->SubCondition = std::move(condition); return retval; } auto const ConditionStringHelper = cmJSONStringHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION); auto const ConditionBoolHelper = cmJSONBoolHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION); auto const ConditionStringListHelper = cmJSONVectorHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, ConditionStringHelper); auto const ConstConditionHelper = cmJSONObjectHelper(ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false) .Bind("type"_s, nullptr, ConditionStringHelper, true) .Bind("value"_s, &cmCMakePresetsFileInternal::ConstCondition::Value, ConditionBoolHelper, true); auto const EqualsConditionHelper = cmJSONObjectHelper(ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false) .Bind("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(ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false) .Bind("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(ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false) .Bind("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& out, const Json::Value* value); auto const ListConditionVectorHelper = cmJSONVectorHelper, ReadFileResult>(ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, SubConditionHelper); auto const AnyAllOfConditionHelper = cmJSONObjectHelper(ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false) .Bind("type"_s, nullptr, ConditionStringHelper, true) .Bind("conditions"_s, &cmCMakePresetsFileInternal::AnyAllOfCondition::Conditions, ListConditionVectorHelper); auto const NotConditionHelper = cmJSONObjectHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false) .Bind("type"_s, nullptr, ConditionStringHelper, true) .Bind("condition"_s, &cmCMakePresetsFileInternal::NotCondition::SubCondition, SubConditionHelper); ReadFileResult ConditionHelper( std::unique_ptr& out, const Json::Value* value) { if (!value) { out.reset(); return ReadFileResult::READ_OK; } if (value->isBool()) { auto c = cm::make_unique(); c->Value = value->asBool(); out = std::move(c); return ReadFileResult::READ_OK; } if (value->isNull()) { out = cm::make_unique(); 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(); CHECK_OK(ConstConditionHelper(*c, value)); out = std::move(c); return ReadFileResult::READ_OK; } if (type == "equals" || type == "notEquals") { auto c = cm::make_unique(); 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(); 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(); 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(); 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(); CHECK_OK(NotConditionHelper(*c, value)); out = std::move(c); return ReadFileResult::READ_OK; } } return ReadFileResult::INVALID_CONDITION; } ReadFileResult PresetConditionHelper( std::shared_ptr& out, const Json::Value* value) { std::unique_ptr ptr; auto result = ConditionHelper(ptr, value); out = std::move(ptr); return result; } ReadFileResult SubConditionHelper( std::unique_ptr& out, const Json::Value* value) { std::unique_ptr ptr; auto result = ConditionHelper(ptr, value); if (ptr && ptr->IsNull()) { return ReadFileResult::INVALID_CONDITION; } out = std::move(ptr); return result; } cmJSONHelper 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::READ_OK, ReadFileResult::INVALID_VERSION); auto const VersionHelper = cmJSONRequiredHelper( ReadFileResult::NO_VERSION, VersionIntHelper); auto const RootVersionHelper = cmJSONObjectHelper(ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT) .Bind("version"_s, VersionHelper, false); auto const VariableStringHelper = cmJSONStringHelper( 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( ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false) .Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false) .Bind("value"_s, &CacheVariable::Value, VariableValueHelper); ReadFileResult VariableHelper(cm::optional& 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, ReadFileResult>( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper); auto const PresetStringHelper = cmJSONStringHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); ReadFileResult EnvironmentHelper(cm::optional& 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, ReadFileResult>( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, EnvironmentHelper); auto const PresetVectorStringHelper = cmJSONVectorHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetStringHelper); ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector& 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::READ_OK, ReadFileResult::INVALID_PRESET); auto const PresetOptionalBoolHelper = cmJSONOptionalHelper(ReadFileResult::READ_OK, PresetBoolHelper); auto const PresetIntHelper = cmJSONIntHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); auto const PresetOptionalIntHelper = cmJSONOptionalHelper( ReadFileResult::READ_OK, PresetIntHelper); auto const PresetVectorIntHelper = cmJSONVectorHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper); auto const PresetWarningsHelper = cmJSONObjectHelper( 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( 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( 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& 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 ArchToolsetHelper( std::string ConfigurePreset::*valueField, cm::optional ConfigurePreset::*strategyField) { auto const objectHelper = cmJSONObjectHelper( 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( 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("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("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( 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("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(ReadFileResult::READ_OK, TestPresetOutputVerbosityHelper); auto const TestPresetOptionalOutputHelper = cmJSONOptionalHelper( ReadFileResult::READ_OK, cmJSONObjectHelper( 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( ReadFileResult::READ_OK, cmJSONObjectHelper(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& 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( ReadFileResult::READ_OK, cmJSONObjectHelper( 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( ReadFileResult::READ_OK, cmJSONObjectHelper(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( ReadFileResult::READ_OK, cmJSONObjectHelper( 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(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( ReadFileResult::READ_OK, cmJSONObjectHelper(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(ReadFileResult::READ_OK, TestPresetExecutionNoTestsActionHelper); auto const TestPresetExecutionHelper = cmJSONOptionalHelper( ReadFileResult::READ_OK, cmJSONObjectHelper( 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( ReadFileResult::READ_OK, cmJSONObjectHelper( 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( 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("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( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, ConfigurePresetHelper); auto const BuildPresetsHelper = cmJSONVectorHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, BuildPresetHelper); auto const TestPresetsHelper = cmJSONVectorHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, TestPresetHelper); auto const CMakeVersionUIntHelper = cmJSONUIntHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION); auto const CMakeVersionHelper = cmJSONObjectHelper( 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( ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false) .Bind("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("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 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 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 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; }