From fd6ea2f67fc5fd1aee27ae92d6a16bc0fba1209e Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Tue, 21 Dec 2021 14:39:04 -0500 Subject: Refactor: Rename cmCMakePresetsFile to cmCMakePresetsGraph And change all references to "file" to say "graph" instead. --- Source/CMakeLists.txt | 8 +- Source/QtDialog/CMakeSetupDialog.cxx | 4 +- Source/QtDialog/CMakeSetupDialog.h | 2 +- Source/QtDialog/QCMake.cxx | 22 +- Source/QtDialog/QCMake.h | 12 +- Source/QtDialog/QCMakePreset.h | 2 +- Source/cmCMakePresetsFile.cxx | 1115 ------------------------------- Source/cmCMakePresetsFile.h | 378 ----------- Source/cmCMakePresetsFileInternal.h | 112 ---- Source/cmCMakePresetsFileReadJSON.cxx | 1032 ----------------------------- Source/cmCMakePresetsGraph.cxx | 1116 ++++++++++++++++++++++++++++++++ Source/cmCMakePresetsGraph.h | 378 +++++++++++ Source/cmCMakePresetsGraphInternal.h | 112 ++++ Source/cmCMakePresetsGraphReadJSON.cxx | 1034 +++++++++++++++++++++++++++++ Source/cmCTest.cxx | 34 +- Source/cmake.cxx | 42 +- Source/cmake.h | 6 +- 17 files changed, 2706 insertions(+), 2703 deletions(-) delete mode 100644 Source/cmCMakePresetsFile.cxx delete mode 100644 Source/cmCMakePresetsFile.h delete mode 100644 Source/cmCMakePresetsFileInternal.h delete mode 100644 Source/cmCMakePresetsFileReadJSON.cxx create mode 100644 Source/cmCMakePresetsGraph.cxx create mode 100644 Source/cmCMakePresetsGraph.h create mode 100644 Source/cmCMakePresetsGraphInternal.h create mode 100644 Source/cmCMakePresetsGraphReadJSON.cxx diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 677fd2f..e0c5ed9 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -161,10 +161,10 @@ set(SRCS cmCLocaleEnvironmentScope.cxx cmCMakePath.h cmCMakePath.cxx - cmCMakePresetsFile.cxx - cmCMakePresetsFile.h - cmCMakePresetsFileInternal.h - cmCMakePresetsFileReadJSON.cxx + cmCMakePresetsGraph.cxx + cmCMakePresetsGraph.h + cmCMakePresetsGraphInternal.h + cmCMakePresetsGraphReadJSON.cxx cmCommandArgumentParserHelper.cxx cmCommonTargetGenerator.cxx cmCommonTargetGenerator.h diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index 1785571..f90b781 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -730,12 +730,12 @@ void CMakeSetupDialog::updatePreset(const QString& name) } void CMakeSetupDialog::showPresetLoadError( - const QString& dir, cmCMakePresetsFile::ReadFileResult result) + const QString& dir, cmCMakePresetsGraph::ReadFileResult result) { QMessageBox::warning( this, "Error Reading CMake Presets", QString::fromLocal8Bit("Could not read presets from %1: %2") - .arg(dir, cmCMakePresetsFile::ResultToString(result))); + .arg(dir, cmCMakePresetsGraph::ResultToString(result))); } void CMakeSetupDialog::doBinaryBrowse() diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h index f0cc929..8aee70d 100644 --- a/Source/QtDialog/CMakeSetupDialog.h +++ b/Source/QtDialog/CMakeSetupDialog.h @@ -60,7 +60,7 @@ protected slots: void updatePresets(const QVector& presets); void updatePreset(const QString& name); void showPresetLoadError(const QString& dir, - cmCMakePresetsFile::ReadFileResult result); + cmCMakePresetsGraph::ReadFileResult result); void showProgress(const QString& msg, float percent); void setEnabledState(bool); bool setupFirstConfigure(); diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx index 8ab8656..ffb6157 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -32,7 +32,7 @@ QCMake::QCMake(QObject* p) qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType>(); - qRegisterMetaType(); + qRegisterMetaType(); cmSystemTools::DisableRunCommandOutput(); cmSystemTools::SetRunCommandHideConsole(true); @@ -69,9 +69,9 @@ QCMake::QCMake(QObject* p) connect(&this->LoadPresetsTimer, &QTimer::timeout, this, [this]() { this->loadPresets(); if (!this->PresetName.isEmpty() && - this->CMakePresetsFile.ConfigurePresets.find( + this->CMakePresetsGraph.ConfigurePresets.find( std::string(this->PresetName.toLocal8Bit())) == - this->CMakePresetsFile.ConfigurePresets.end()) { + this->CMakePresetsGraph.ConfigurePresets.end()) { this->setPreset(QString{}); } }); @@ -159,7 +159,7 @@ void QCMake::setPreset(const QString& name, bool setBinary) if (!name.isNull()) { std::string presetName(name.toLocal8Bit()); auto const& expandedPreset = - this->CMakePresetsFile.ConfigurePresets[presetName].Expanded; + this->CMakePresetsGraph.ConfigurePresets[presetName].Expanded; if (expandedPreset) { if (setBinary && !expandedPreset->BinaryDir.empty()) { QString binaryDir = @@ -427,7 +427,7 @@ QCMakePropertyList QCMake::properties() const if (!this->PresetName.isNull()) { std::string presetName(this->PresetName.toLocal8Bit()); auto const& p = - this->CMakePresetsFile.ConfigurePresets.at(presetName).Expanded; + this->CMakePresetsGraph.ConfigurePresets.at(presetName).Expanded; if (p) { for (auto const& v : p->CacheVariables) { if (!v.second) { @@ -533,17 +533,17 @@ void QCMake::setUpEnvironment() const void QCMake::loadPresets() { - auto result = this->CMakePresetsFile.ReadProjectPresets( + auto result = this->CMakePresetsGraph.ReadProjectPresets( this->SourceDirectory.toLocal8Bit().data(), true); if (result != this->LastLoadPresetsResult && - result != cmCMakePresetsFile::ReadFileResult::READ_OK) { + result != cmCMakePresetsGraph::ReadFileResult::READ_OK) { emit this->presetLoadError(this->SourceDirectory, result); } this->LastLoadPresetsResult = result; QVector presets; - for (auto const& name : this->CMakePresetsFile.ConfigurePresetOrder) { - auto const& it = this->CMakePresetsFile.ConfigurePresets[name]; + for (auto const& name : this->CMakePresetsGraph.ConfigurePresetOrder) { + auto const& it = this->CMakePresetsGraph.ConfigurePresets[name]; auto const& p = it.Unexpanded; if (p.Hidden) { continue; @@ -556,10 +556,10 @@ void QCMake::loadPresets() preset.generator = QString::fromLocal8Bit(p.Generator.data()); preset.architecture = QString::fromLocal8Bit(p.Architecture.data()); preset.setArchitecture = !p.ArchitectureStrategy || - p.ArchitectureStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set; + p.ArchitectureStrategy == cmCMakePresetsGraph::ArchToolsetStrategy::Set; preset.toolset = QString::fromLocal8Bit(p.Toolset.data()); preset.setToolset = !p.ToolsetStrategy || - p.ToolsetStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set; + p.ToolsetStrategy == cmCMakePresetsGraph::ArchToolsetStrategy::Set; preset.enabled = it.Expanded && it.Expanded->ConditionResult && std::find_if(this->AvailableGenerators.begin(), this->AvailableGenerators.end(), diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h index a6751b0..8a7e4cb 100644 --- a/Source/QtDialog/QCMake.h +++ b/Source/QtDialog/QCMake.h @@ -4,7 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include "cmCMakePresetsFile.h" +#include "cmCMakePresetsGraph.h" #include "cmake.h" #ifdef _MSC_VER @@ -60,7 +60,7 @@ using QCMakePropertyList = QList; Q_DECLARE_METATYPE(QCMakeProperty) Q_DECLARE_METATYPE(QCMakePropertyList) Q_DECLARE_METATYPE(QProcessEnvironment) -Q_DECLARE_METATYPE(cmCMakePresetsFile::ReadFileResult) +Q_DECLARE_METATYPE(cmCMakePresetsGraph::ReadFileResult) /// Qt API for CMake library. /// Wrapper like class allows for easier integration with @@ -159,7 +159,7 @@ signals: void presetChanged(const QString& name); /// signal when there's an error reading the presets files void presetLoadError(const QString& dir, - cmCMakePresetsFile::ReadFileResult error); + cmCMakePresetsGraph::ReadFileResult error); /// signal when uninitialized warning changes void warnUninitializedModeChanged(bool value); /// signal for progress events @@ -202,9 +202,9 @@ protected: QString Platform; QString Toolset; std::vector AvailableGenerators; - cmCMakePresetsFile CMakePresetsFile; - cmCMakePresetsFile::ReadFileResult LastLoadPresetsResult = - cmCMakePresetsFile::ReadFileResult::READ_OK; + cmCMakePresetsGraph CMakePresetsGraph; + cmCMakePresetsGraph::ReadFileResult LastLoadPresetsResult = + cmCMakePresetsGraph::ReadFileResult::READ_OK; QString PresetName; QString CMakeExecutable; QAtomicInt InterruptFlag; diff --git a/Source/QtDialog/QCMakePreset.h b/Source/QtDialog/QCMakePreset.h index 1609fcb..7387655 100644 --- a/Source/QtDialog/QCMakePreset.h +++ b/Source/QtDialog/QCMakePreset.h @@ -5,7 +5,7 @@ #include #include -#include "cmCMakePresetsFile.h" +#include "cmCMakePresetsGraph.h" class QCMakePreset { diff --git a/Source/cmCMakePresetsFile.cxx b/Source/cmCMakePresetsFile.cxx deleted file mode 100644 index 4a0742a..0000000 --- a/Source/cmCMakePresetsFile.cxx +++ /dev/null @@ -1,1115 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmCMakePresetsFile.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include "cmsys/RegularExpression.hxx" - -#include "cmCMakePresetsFileInternal.h" -#include "cmStringAlgorithms.h" -#include "cmSystemTools.h" - -#define CHECK_EXPAND(out, field, expanders, version) \ - do { \ - switch (ExpandMacros(field, expanders, version)) { \ - case ExpandMacroResult::Error: \ - return false; \ - case ExpandMacroResult::Ignore: \ - out.reset(); \ - return true; \ - case ExpandMacroResult::Ok: \ - break; \ - } \ - } while (false) - -namespace { -enum class CycleStatus -{ - Unvisited, - InProgress, - Verified, -}; - -using ReadFileResult = cmCMakePresetsFile::ReadFileResult; -using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset; -using BuildPreset = cmCMakePresetsFile::BuildPreset; -using TestPreset = cmCMakePresetsFile::TestPreset; -using ExpandMacroResult = cmCMakePresetsFileInternal::ExpandMacroResult; -using MacroExpander = cmCMakePresetsFileInternal::MacroExpander; - -void InheritString(std::string& child, const std::string& parent) -{ - if (child.empty()) { - child = parent; - } -} - -template -void InheritOptionalValue(cm::optional& child, - const cm::optional& parent) -{ - if (!child) { - child = parent; - } -} - -template -void InheritVector(std::vector& child, const std::vector& parent) -{ - if (child.empty()) { - child = parent; - } -} - -/** - * Check preset inheritance for cycles (using a DAG check algorithm) while - * also bubbling up fields through the inheritance hierarchy, then verify - * that each preset has the required fields, either directly or through - * inheritance. - */ -template -ReadFileResult VisitPreset( - T& preset, std::map>& presets, - std::map cycleStatus, - const cmCMakePresetsFile& file) -{ - switch (cycleStatus[preset.Name]) { - case CycleStatus::InProgress: - return ReadFileResult::CYCLIC_PRESET_INHERITANCE; - case CycleStatus::Verified: - return ReadFileResult::READ_OK; - default: - break; - } - - cycleStatus[preset.Name] = CycleStatus::InProgress; - - if (preset.Environment.count("") != 0) { - return ReadFileResult::INVALID_PRESET; - } - - CHECK_OK(preset.VisitPresetBeforeInherit()); - - for (auto const& i : preset.Inherits) { - auto parent = presets.find(i); - if (parent == presets.end()) { - return ReadFileResult::INVALID_PRESET; - } - - auto& parentPreset = parent->second.Unexpanded; - if (!preset.User && parentPreset.User) { - return ReadFileResult::USER_PRESET_INHERITANCE; - } - - auto result = VisitPreset(parentPreset, presets, cycleStatus, file); - if (result != ReadFileResult::READ_OK) { - return result; - } - - CHECK_OK(preset.VisitPresetInherit(parentPreset)); - - for (auto const& v : parentPreset.Environment) { - preset.Environment.insert(v); - } - - if (!preset.ConditionEvaluator) { - preset.ConditionEvaluator = parentPreset.ConditionEvaluator; - } - } - - if (preset.ConditionEvaluator && preset.ConditionEvaluator->IsNull()) { - preset.ConditionEvaluator.reset(); - } - - CHECK_OK(preset.VisitPresetAfterInherit(file.GetVersion(preset))); - - cycleStatus[preset.Name] = CycleStatus::Verified; - return ReadFileResult::READ_OK; -} - -template -ReadFileResult ComputePresetInheritance( - std::map>& presets, - const cmCMakePresetsFile& file) -{ - std::map cycleStatus; - for (auto const& it : presets) { - cycleStatus[it.first] = CycleStatus::Unvisited; - } - - for (auto& it : presets) { - auto& preset = it.second.Unexpanded; - auto result = VisitPreset(preset, presets, cycleStatus, file); - if (result != ReadFileResult::READ_OK) { - return result; - } - } - - return ReadFileResult::READ_OK; -} - -constexpr const char* ValidPrefixes[] = { - "", - "env", - "penv", - "vendor", -}; - -bool PrefixesValidMacroNamespace(const std::string& str) -{ - return std::any_of( - std::begin(ValidPrefixes), std::end(ValidPrefixes), - [&str](const char* prefix) -> bool { return cmHasPrefix(prefix, str); }); -} - -bool IsValidMacroNamespace(const std::string& str) -{ - return std::any_of( - std::begin(ValidPrefixes), std::end(ValidPrefixes), - [&str](const char* prefix) -> bool { return str == prefix; }); -} - -ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status, - const std::vector& macroExpanders, - int version); -ExpandMacroResult ExpandMacros( - std::string& out, const std::vector& macroExpanders, - int version); -ExpandMacroResult ExpandMacro(std::string& out, - const std::string& macroNamespace, - const std::string& macroName, - const std::vector& macroExpanders, - int version); - -bool ExpandMacros(const cmCMakePresetsFile& file, - const ConfigurePreset& preset, - cm::optional& out, - const std::vector& macroExpanders) -{ - std::string binaryDir = preset.BinaryDir; - CHECK_EXPAND(out, binaryDir, macroExpanders, file.GetVersion(preset)); - - if (!binaryDir.empty()) { - if (!cmSystemTools::FileIsFullPath(binaryDir)) { - binaryDir = cmStrCat(file.SourceDir, '/', binaryDir); - } - out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir); - cmSystemTools::ConvertToUnixSlashes(out->BinaryDir); - } - - if (!preset.InstallDir.empty()) { - std::string installDir = preset.InstallDir; - CHECK_EXPAND(out, installDir, macroExpanders, file.GetVersion(preset)); - - if (!cmSystemTools::FileIsFullPath(installDir)) { - installDir = cmStrCat(file.SourceDir, '/', installDir); - } - out->InstallDir = cmSystemTools::CollapseFullPath(installDir); - cmSystemTools::ConvertToUnixSlashes(out->InstallDir); - } - - if (!preset.ToolchainFile.empty()) { - std::string toolchain = preset.ToolchainFile; - CHECK_EXPAND(out, toolchain, macroExpanders, file.GetVersion(preset)); - out->ToolchainFile = toolchain; - } - - for (auto& variable : out->CacheVariables) { - if (variable.second) { - CHECK_EXPAND(out, variable.second->Value, macroExpanders, - file.GetVersion(preset)); - } - } - - return true; -} - -bool ExpandMacros(const cmCMakePresetsFile& file, const BuildPreset& preset, - cm::optional& out, - const std::vector& macroExpanders) -{ - for (auto& target : out->Targets) { - CHECK_EXPAND(out, target, macroExpanders, file.GetVersion(preset)); - } - - for (auto& nativeToolOption : out->NativeToolOptions) { - CHECK_EXPAND(out, nativeToolOption, macroExpanders, - file.GetVersion(preset)); - } - - return true; -} - -bool ExpandMacros(const cmCMakePresetsFile& file, const TestPreset& preset, - cm::optional& out, - const std::vector& macroExpanders) -{ - for (auto& overwrite : out->OverwriteConfigurationFile) { - CHECK_EXPAND(out, overwrite, macroExpanders, file.GetVersion(preset)); - } - - if (out->Output) { - CHECK_EXPAND(out, out->Output->OutputLogFile, macroExpanders, - file.GetVersion(preset)); - } - - if (out->Filter) { - if (out->Filter->Include) { - CHECK_EXPAND(out, out->Filter->Include->Name, macroExpanders, - file.GetVersion(preset)); - CHECK_EXPAND(out, out->Filter->Include->Label, macroExpanders, - file.GetVersion(preset)); - - if (out->Filter->Include->Index) { - CHECK_EXPAND(out, out->Filter->Include->Index->IndexFile, - macroExpanders, file.GetVersion(preset)); - } - } - - if (out->Filter->Exclude) { - CHECK_EXPAND(out, out->Filter->Exclude->Name, macroExpanders, - file.GetVersion(preset)); - CHECK_EXPAND(out, out->Filter->Exclude->Label, macroExpanders, - file.GetVersion(preset)); - - if (out->Filter->Exclude->Fixtures) { - CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Any, macroExpanders, - file.GetVersion(preset)); - CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Setup, - macroExpanders, file.GetVersion(preset)); - CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Cleanup, - macroExpanders, file.GetVersion(preset)); - } - } - } - - if (out->Execution) { - CHECK_EXPAND(out, out->Execution->ResourceSpecFile, macroExpanders, - file.GetVersion(preset)); - } - - return true; -} - -template -bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset, - cm::optional& out) -{ - out.emplace(preset); - - std::map envCycles; - for (auto const& v : out->Environment) { - envCycles[v.first] = CycleStatus::Unvisited; - } - - std::vector macroExpanders; - - MacroExpander defaultMacroExpander = - [&file, &preset](const std::string& macroNamespace, - const std::string& macroName, std::string& macroOut, - int version) -> ExpandMacroResult { - if (macroNamespace.empty()) { - if (macroName == "sourceDir") { - macroOut += file.SourceDir; - return ExpandMacroResult::Ok; - } - if (macroName == "sourceParentDir") { - macroOut += cmSystemTools::GetParentDirectory(file.SourceDir); - return ExpandMacroResult::Ok; - } - if (macroName == "sourceDirName") { - macroOut += cmSystemTools::GetFilenameName(file.SourceDir); - return ExpandMacroResult::Ok; - } - if (macroName == "presetName") { - macroOut += preset.Name; - return ExpandMacroResult::Ok; - } - if (macroName == "generator") { - // Generator only makes sense if preset is not hidden. - if (!preset.Hidden) { - macroOut += file.GetGeneratorForPreset(preset.Name); - } - return ExpandMacroResult::Ok; - } - if (macroName == "dollar") { - macroOut += '$'; - return ExpandMacroResult::Ok; - } - if (macroName == "hostSystemName") { - if (version < 3) { - return ExpandMacroResult::Error; - } - macroOut += cmSystemTools::GetSystemName(); - return ExpandMacroResult::Ok; - } - } - - return ExpandMacroResult::Ignore; - }; - - MacroExpander environmentMacroExpander = - [¯oExpanders, &out, &envCycles]( - const std::string& macroNamespace, const std::string& macroName, - std::string& result, int version) -> ExpandMacroResult { - if (macroNamespace == "env" && !macroName.empty() && out) { - auto v = out->Environment.find(macroName); - if (v != out->Environment.end() && v->second) { - auto e = - VisitEnv(*v->second, envCycles[macroName], macroExpanders, version); - if (e != ExpandMacroResult::Ok) { - return e; - } - result += *v->second; - return ExpandMacroResult::Ok; - } - } - - if (macroNamespace == "env" || macroNamespace == "penv") { - if (macroName.empty()) { - return ExpandMacroResult::Error; - } - const char* value = std::getenv(macroName.c_str()); - if (value) { - result += value; - } - return ExpandMacroResult::Ok; - } - - return ExpandMacroResult::Ignore; - }; - - macroExpanders.push_back(defaultMacroExpander); - macroExpanders.push_back(environmentMacroExpander); - - for (auto& v : out->Environment) { - if (v.second) { - switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders, - file.GetVersion(preset))) { - case ExpandMacroResult::Error: - return false; - case ExpandMacroResult::Ignore: - out.reset(); - return true; - case ExpandMacroResult::Ok: - break; - } - } - } - - if (preset.ConditionEvaluator) { - cm::optional result; - if (!preset.ConditionEvaluator->Evaluate( - macroExpanders, file.GetVersion(preset), result)) { - return false; - } - if (!result) { - out.reset(); - return true; - } - out->ConditionResult = *result; - } - - return ExpandMacros(file, preset, out, macroExpanders); -} - -ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status, - const std::vector& macroExpanders, - int version) -{ - if (status == CycleStatus::Verified) { - return ExpandMacroResult::Ok; - } - if (status == CycleStatus::InProgress) { - return ExpandMacroResult::Error; - } - - status = CycleStatus::InProgress; - auto e = ExpandMacros(value, macroExpanders, version); - if (e != ExpandMacroResult::Ok) { - return e; - } - status = CycleStatus::Verified; - return ExpandMacroResult::Ok; -} - -ExpandMacroResult ExpandMacros( - std::string& out, const std::vector& macroExpanders, - int version) -{ - std::string result; - std::string macroNamespace; - std::string macroName; - - enum class State - { - Default, - MacroNamespace, - MacroName, - } state = State::Default; - - for (auto c : out) { - switch (state) { - case State::Default: - if (c == '$') { - state = State::MacroNamespace; - } else { - result += c; - } - break; - - case State::MacroNamespace: - if (c == '{') { - if (IsValidMacroNamespace(macroNamespace)) { - state = State::MacroName; - } else { - result += '$'; - result += macroNamespace; - result += '{'; - macroNamespace.clear(); - state = State::Default; - } - } else { - macroNamespace += c; - if (!PrefixesValidMacroNamespace(macroNamespace)) { - result += '$'; - result += macroNamespace; - macroNamespace.clear(); - state = State::Default; - } - } - break; - - case State::MacroName: - if (c == '}') { - auto e = ExpandMacro(result, macroNamespace, macroName, - macroExpanders, version); - if (e != ExpandMacroResult::Ok) { - return e; - } - macroNamespace.clear(); - macroName.clear(); - state = State::Default; - } else { - macroName += c; - } - break; - } - } - - switch (state) { - case State::Default: - break; - case State::MacroNamespace: - result += '$'; - result += macroNamespace; - break; - case State::MacroName: - return ExpandMacroResult::Error; - } - - out = std::move(result); - return ExpandMacroResult::Ok; -} - -ExpandMacroResult ExpandMacro(std::string& out, - const std::string& macroNamespace, - const std::string& macroName, - const std::vector& macroExpanders, - int version) -{ - for (auto const& macroExpander : macroExpanders) { - auto result = macroExpander(macroNamespace, macroName, out, version); - if (result != ExpandMacroResult::Ignore) { - return result; - } - } - - if (macroNamespace == "vendor") { - return ExpandMacroResult::Ignore; - } - - return ExpandMacroResult::Error; -} -} - -bool cmCMakePresetsFileInternal::EqualsCondition::Evaluate( - const std::vector& expanders, int version, - cm::optional& out) const -{ - std::string lhs = this->Lhs; - CHECK_EXPAND(out, lhs, expanders, version); - - std::string rhs = this->Rhs; - CHECK_EXPAND(out, rhs, expanders, version); - - out = (lhs == rhs); - return true; -} - -bool cmCMakePresetsFileInternal::InListCondition::Evaluate( - const std::vector& expanders, int version, - cm::optional& out) const -{ - std::string str = this->String; - CHECK_EXPAND(out, str, expanders, version); - - for (auto item : this->List) { - CHECK_EXPAND(out, item, expanders, version); - if (str == item) { - out = true; - return true; - } - } - - out = false; - return true; -} - -bool cmCMakePresetsFileInternal::MatchesCondition::Evaluate( - const std::vector& expanders, int version, - cm::optional& out) const -{ - std::string str = this->String; - CHECK_EXPAND(out, str, expanders, version); - std::string regexStr = this->Regex; - CHECK_EXPAND(out, regexStr, expanders, version); - - cmsys::RegularExpression regex; - if (!regex.compile(regexStr)) { - return false; - } - - out = regex.find(str); - return true; -} - -bool cmCMakePresetsFileInternal::AnyAllOfCondition::Evaluate( - const std::vector& expanders, int version, - cm::optional& out) const -{ - for (auto const& condition : this->Conditions) { - cm::optional result; - if (!condition->Evaluate(expanders, version, result)) { - out.reset(); - return false; - } - - if (!result) { - out.reset(); - return true; - } - - if (result == this->StopValue) { - out = result; - return true; - } - } - - out = !this->StopValue; - return true; -} - -bool cmCMakePresetsFileInternal::NotCondition::Evaluate( - const std::vector& expanders, int version, - cm::optional& out) const -{ - out.reset(); - if (!this->SubCondition->Evaluate(expanders, version, out)) { - out.reset(); - return false; - } - if (out) { - *out = !*out; - } - return true; -} - -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::ConfigurePreset::VisitPresetInherit( - const cmCMakePresetsFile::Preset& parentPreset) -{ - auto& preset = *this; - const ConfigurePreset& parent = - static_cast(parentPreset); - InheritString(preset.Generator, parent.Generator); - InheritString(preset.Architecture, parent.Architecture); - InheritString(preset.Toolset, parent.Toolset); - if (!preset.ArchitectureStrategy) { - preset.ArchitectureStrategy = parent.ArchitectureStrategy; - } - if (!preset.ToolsetStrategy) { - preset.ToolsetStrategy = parent.ToolsetStrategy; - } - InheritString(preset.BinaryDir, parent.BinaryDir); - InheritString(preset.InstallDir, parent.InstallDir); - InheritString(preset.ToolchainFile, parent.ToolchainFile); - InheritOptionalValue(preset.WarnDev, parent.WarnDev); - InheritOptionalValue(preset.ErrorDev, parent.ErrorDev); - InheritOptionalValue(preset.WarnDeprecated, parent.WarnDeprecated); - InheritOptionalValue(preset.ErrorDeprecated, parent.ErrorDeprecated); - InheritOptionalValue(preset.WarnUninitialized, parent.WarnUninitialized); - InheritOptionalValue(preset.WarnUnusedCli, parent.WarnUnusedCli); - InheritOptionalValue(preset.WarnSystemVars, parent.WarnSystemVars); - - for (auto const& v : parent.CacheVariables) { - preset.CacheVariables.insert(v); - } - - return ReadFileResult::READ_OK; -} - -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::ConfigurePreset::VisitPresetBeforeInherit() -{ - auto& preset = *this; - if (preset.Environment.count("") != 0) { - return ReadFileResult::INVALID_PRESET; - } - - return ReadFileResult::READ_OK; -} - -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::ConfigurePreset::VisitPresetAfterInherit(int version) -{ - auto& preset = *this; - if (!preset.Hidden) { - if (version < 3) { - if (preset.Generator.empty()) { - return ReadFileResult::INVALID_PRESET; - } - if (preset.BinaryDir.empty()) { - return ReadFileResult::INVALID_PRESET; - } - } - - if (preset.WarnDev == false && preset.ErrorDev == true) { - return ReadFileResult::INVALID_PRESET; - } - if (preset.WarnDeprecated == false && preset.ErrorDeprecated == true) { - return ReadFileResult::INVALID_PRESET; - } - if (preset.CacheVariables.count("") != 0) { - return ReadFileResult::INVALID_PRESET; - } - } - - return ReadFileResult::READ_OK; -} - -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::BuildPreset::VisitPresetInherit( - const cmCMakePresetsFile::Preset& parentPreset) -{ - auto& preset = *this; - const BuildPreset& parent = static_cast(parentPreset); - - InheritString(preset.ConfigurePreset, parent.ConfigurePreset); - InheritOptionalValue(preset.InheritConfigureEnvironment, - parent.InheritConfigureEnvironment); - InheritOptionalValue(preset.Jobs, parent.Jobs); - InheritVector(preset.Targets, parent.Targets); - InheritString(preset.Configuration, parent.Configuration); - InheritOptionalValue(preset.CleanFirst, parent.CleanFirst); - InheritOptionalValue(preset.Verbose, parent.Verbose); - InheritVector(preset.NativeToolOptions, parent.NativeToolOptions); - - return ReadFileResult::READ_OK; -} - -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::BuildPreset::VisitPresetAfterInherit(int /* version */) -{ - auto& preset = *this; - if (!preset.Hidden && preset.ConfigurePreset.empty()) { - return ReadFileResult::INVALID_PRESET; - } - return ReadFileResult::READ_OK; -} - -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::TestPreset::VisitPresetInherit( - const cmCMakePresetsFile::Preset& parentPreset) -{ - auto& preset = *this; - const TestPreset& parent = static_cast(parentPreset); - - InheritString(preset.ConfigurePreset, parent.ConfigurePreset); - InheritOptionalValue(preset.InheritConfigureEnvironment, - parent.InheritConfigureEnvironment); - InheritString(preset.Configuration, parent.Configuration); - InheritVector(preset.OverwriteConfigurationFile, - parent.OverwriteConfigurationFile); - - if (parent.Output) { - if (preset.Output) { - auto& output = preset.Output.value(); - const auto& parentOutput = parent.Output.value(); - InheritOptionalValue(output.ShortProgress, parentOutput.ShortProgress); - InheritOptionalValue(output.Verbosity, parentOutput.Verbosity); - InheritOptionalValue(output.Debug, parentOutput.Debug); - InheritOptionalValue(output.OutputOnFailure, - parentOutput.OutputOnFailure); - InheritOptionalValue(output.Quiet, parentOutput.Quiet); - InheritString(output.OutputLogFile, parentOutput.OutputLogFile); - InheritOptionalValue(output.LabelSummary, parentOutput.LabelSummary); - InheritOptionalValue(output.SubprojectSummary, - parentOutput.SubprojectSummary); - InheritOptionalValue(output.MaxPassedTestOutputSize, - parentOutput.MaxPassedTestOutputSize); - InheritOptionalValue(output.MaxFailedTestOutputSize, - parentOutput.MaxFailedTestOutputSize); - InheritOptionalValue(output.MaxTestNameWidth, - parentOutput.MaxTestNameWidth); - } else { - preset.Output = parent.Output; - } - } - - if (parent.Filter) { - if (parent.Filter->Include) { - if (preset.Filter && preset.Filter->Include) { - auto& include = *preset.Filter->Include; - const auto& parentInclude = *parent.Filter->Include; - InheritString(include.Name, parentInclude.Name); - InheritString(include.Label, parentInclude.Label); - InheritOptionalValue(include.Index, parentInclude.Index); - } else { - if (!preset.Filter) { - preset.Filter.emplace(); - } - preset.Filter->Include = parent.Filter->Include; - } - } - - if (parent.Filter->Exclude) { - if (preset.Filter && preset.Filter->Exclude) { - auto& exclude = *preset.Filter->Exclude; - const auto& parentExclude = *parent.Filter->Exclude; - InheritString(exclude.Name, parentExclude.Name); - InheritString(exclude.Label, parentExclude.Label); - InheritOptionalValue(exclude.Fixtures, parentExclude.Fixtures); - } else { - if (!preset.Filter) { - preset.Filter.emplace(); - } - preset.Filter->Exclude = parent.Filter->Exclude; - } - } - } - - if (parent.Execution) { - if (preset.Execution) { - auto& execution = *preset.Execution; - const auto& parentExecution = *parent.Execution; - InheritOptionalValue(execution.StopOnFailure, - parentExecution.StopOnFailure); - InheritOptionalValue(execution.EnableFailover, - parentExecution.EnableFailover); - InheritOptionalValue(execution.Jobs, parentExecution.Jobs); - InheritString(execution.ResourceSpecFile, - parentExecution.ResourceSpecFile); - InheritOptionalValue(execution.TestLoad, parentExecution.TestLoad); - InheritOptionalValue(execution.ShowOnly, parentExecution.ShowOnly); - InheritOptionalValue(execution.Repeat, parentExecution.Repeat); - InheritOptionalValue(execution.InteractiveDebugging, - parentExecution.InteractiveDebugging); - InheritOptionalValue(execution.ScheduleRandom, - parentExecution.ScheduleRandom); - InheritOptionalValue(execution.Timeout, parentExecution.Timeout); - InheritOptionalValue(execution.NoTestsAction, - parentExecution.NoTestsAction); - } else { - preset.Execution = parent.Execution; - } - } - - return ReadFileResult::READ_OK; -} - -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::TestPreset::VisitPresetAfterInherit(int /* version */) -{ - auto& preset = *this; - if (!preset.Hidden && preset.ConfigurePreset.empty()) { - return ReadFileResult::INVALID_PRESET; - } - return ReadFileResult::READ_OK; -} - -std::string cmCMakePresetsFile::GetFilename(const std::string& sourceDir) -{ - return cmStrCat(sourceDir, "/CMakePresets.json"); -} - -std::string cmCMakePresetsFile::GetUserFilename(const std::string& sourceDir) -{ - return cmStrCat(sourceDir, "/CMakeUserPresets.json"); -} - -cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadProjectPresets( - const std::string& sourceDir, bool allowNoFiles) -{ - this->SourceDir = sourceDir; - this->ClearPresets(); - - auto result = this->ReadProjectPresetsInternal(allowNoFiles); - if (result != ReadFileResult::READ_OK) { - this->ClearPresets(); - } - - return result; -} - -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::ReadProjectPresetsInternal(bool allowNoFiles) -{ - bool haveOneFile = false; - - std::string filename = GetUserFilename(this->SourceDir); - if (cmSystemTools::FileExists(filename)) { - auto result = this->ReadJSONFile(filename, true); - if (result != ReadFileResult::READ_OK) { - return result; - } - haveOneFile = true; - } - - filename = GetFilename(this->SourceDir); - if (cmSystemTools::FileExists(filename)) { - auto result = this->ReadJSONFile(filename, false); - if (result != ReadFileResult::READ_OK) { - return result; - } - haveOneFile = true; - } - - if (!haveOneFile) { - return allowNoFiles ? ReadFileResult::READ_OK - : ReadFileResult::FILE_NOT_FOUND; - } - - CHECK_OK(ComputePresetInheritance(this->ConfigurePresets, *this)); - CHECK_OK(ComputePresetInheritance(this->BuildPresets, *this)); - CHECK_OK(ComputePresetInheritance(this->TestPresets, *this)); - - for (auto& it : this->ConfigurePresets) { - if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) { - return ReadFileResult::INVALID_MACRO_EXPANSION; - } - } - - for (auto& it : this->BuildPresets) { - if (!it.second.Unexpanded.Hidden) { - const auto configurePreset = - this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset); - if (configurePreset == this->ConfigurePresets.end()) { - return ReadFileResult::INVALID_CONFIGURE_PRESET; - } - - if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) { - it.second.Unexpanded.Environment.insert( - configurePreset->second.Unexpanded.Environment.begin(), - configurePreset->second.Unexpanded.Environment.end()); - } - } - - if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) { - return ReadFileResult::INVALID_MACRO_EXPANSION; - } - } - - for (auto& it : this->TestPresets) { - if (!it.second.Unexpanded.Hidden) { - const auto configurePreset = - this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset); - if (configurePreset == this->ConfigurePresets.end()) { - return ReadFileResult::INVALID_CONFIGURE_PRESET; - } - - if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) { - it.second.Unexpanded.Environment.insert( - configurePreset->second.Unexpanded.Environment.begin(), - configurePreset->second.Unexpanded.Environment.end()); - } - } - - if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) { - return ReadFileResult::INVALID_MACRO_EXPANSION; - } - } - - return ReadFileResult::READ_OK; -} - -const char* cmCMakePresetsFile::ResultToString(ReadFileResult result) -{ - switch (result) { - case ReadFileResult::READ_OK: - return "OK"; - case ReadFileResult::FILE_NOT_FOUND: - return "File not found"; - case ReadFileResult::JSON_PARSE_ERROR: - return "JSON parse error"; - case ReadFileResult::INVALID_ROOT: - return "Invalid root object"; - case ReadFileResult::NO_VERSION: - return "No \"version\" field"; - case ReadFileResult::INVALID_VERSION: - return "Invalid \"version\" field"; - case ReadFileResult::UNRECOGNIZED_VERSION: - return "Unrecognized \"version\" field"; - case ReadFileResult::INVALID_CMAKE_VERSION: - return "Invalid \"cmakeMinimumRequired\" field"; - case ReadFileResult::UNRECOGNIZED_CMAKE_VERSION: - return "\"cmakeMinimumRequired\" version too new"; - case ReadFileResult::INVALID_PRESETS: - return "Invalid \"configurePresets\" field"; - case ReadFileResult::INVALID_PRESET: - return "Invalid preset"; - case ReadFileResult::INVALID_VARIABLE: - return "Invalid CMake variable definition"; - case ReadFileResult::DUPLICATE_PRESETS: - return "Duplicate presets"; - case ReadFileResult::CYCLIC_PRESET_INHERITANCE: - return "Cyclic preset inheritance"; - case ReadFileResult::USER_PRESET_INHERITANCE: - return "Project preset inherits from user preset"; - case ReadFileResult::INVALID_MACRO_EXPANSION: - return "Invalid macro expansion"; - case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED: - return "File version must be 2 or higher for build and test preset " - "support."; - case ReadFileResult::INVALID_CONFIGURE_PRESET: - return "Invalid \"configurePreset\" field"; - case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED: - return "File version must be 3 or higher for installDir preset " - "support."; - case ReadFileResult::INVALID_CONDITION: - return "Invalid preset condition"; - case ReadFileResult::CONDITION_UNSUPPORTED: - return "File version must be 3 or higher for condition support"; - case ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED: - return "File version must be 3 or higher for toolchainFile preset " - "support."; - } - - return "Unknown error"; -} - -void cmCMakePresetsFile::ClearPresets() -{ - this->ConfigurePresets.clear(); - this->BuildPresets.clear(); - this->TestPresets.clear(); - - this->ConfigurePresetOrder.clear(); - this->BuildPresetOrder.clear(); - this->TestPresetOrder.clear(); -} - -void cmCMakePresetsFile::PrintPresets( - const std::vector& presets) -{ - if (presets.empty()) { - return; - } - - auto longestPresetName = - std::max_element(presets.begin(), presets.end(), - [](const cmCMakePresetsFile::Preset* a, - const cmCMakePresetsFile::Preset* b) { - return a->Name.length() < b->Name.length(); - }); - auto longestLength = (*longestPresetName)->Name.length(); - - for (const auto* preset : presets) { - std::cout << " \"" << preset->Name << '"'; - const auto& description = preset->DisplayName; - if (!description.empty()) { - for (std::size_t i = 0; i < longestLength - preset->Name.length(); ++i) { - std::cout << ' '; - } - std::cout << " - " << description; - } - std::cout << '\n'; - } -} - -void cmCMakePresetsFile::PrintConfigurePresetList() const -{ - PrintConfigurePresetList([](const ConfigurePreset&) { return true; }); -} - -void cmCMakePresetsFile::PrintConfigurePresetList( - const std::function& filter) const -{ - std::vector presets; - for (auto const& p : this->ConfigurePresetOrder) { - auto const& preset = this->ConfigurePresets.at(p); - if (!preset.Unexpanded.Hidden && preset.Expanded && - preset.Expanded->ConditionResult && filter(preset.Unexpanded)) { - presets.push_back( - static_cast(&preset.Unexpanded)); - } - } - - if (!presets.empty()) { - std::cout << "Available configure presets:\n\n"; - cmCMakePresetsFile::PrintPresets(presets); - } -} - -void cmCMakePresetsFile::PrintBuildPresetList() const -{ - std::vector presets; - for (auto const& p : this->BuildPresetOrder) { - auto const& preset = this->BuildPresets.at(p); - if (!preset.Unexpanded.Hidden && preset.Expanded && - preset.Expanded->ConditionResult) { - presets.push_back( - static_cast(&preset.Unexpanded)); - } - } - - if (!presets.empty()) { - std::cout << "Available build presets:\n\n"; - cmCMakePresetsFile::PrintPresets(presets); - } -} - -void cmCMakePresetsFile::PrintTestPresetList() const -{ - std::vector presets; - for (auto const& p : this->TestPresetOrder) { - auto const& preset = this->TestPresets.at(p); - if (!preset.Unexpanded.Hidden && preset.Expanded && - preset.Expanded->ConditionResult) { - presets.push_back( - static_cast(&preset.Unexpanded)); - } - } - - if (!presets.empty()) { - std::cout << "Available test presets:\n\n"; - cmCMakePresetsFile::PrintPresets(presets); - } -} - -void cmCMakePresetsFile::PrintAllPresets() const -{ - this->PrintConfigurePresetList(); - std::cout << std::endl; - this->PrintBuildPresetList(); - std::cout << std::endl; - this->PrintTestPresetList(); -} diff --git a/Source/cmCMakePresetsFile.h b/Source/cmCMakePresetsFile.h deleted file mode 100644 index 769fb4e..0000000 --- a/Source/cmCMakePresetsFile.h +++ /dev/null @@ -1,378 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#pragma once - -#include "cmConfigure.h" // IWYU pragma: keep - -#include -#include -#include -#include -#include -#include - -#include - -class cmCMakePresetsFile -{ -public: - enum class ReadFileResult - { - READ_OK, - FILE_NOT_FOUND, - JSON_PARSE_ERROR, - INVALID_ROOT, - NO_VERSION, - INVALID_VERSION, - UNRECOGNIZED_VERSION, - INVALID_CMAKE_VERSION, - UNRECOGNIZED_CMAKE_VERSION, - INVALID_PRESETS, - INVALID_PRESET, - INVALID_VARIABLE, - DUPLICATE_PRESETS, - CYCLIC_PRESET_INHERITANCE, - USER_PRESET_INHERITANCE, - INVALID_MACRO_EXPANSION, - BUILD_TEST_PRESETS_UNSUPPORTED, - INVALID_CONFIGURE_PRESET, - INSTALL_PREFIX_UNSUPPORTED, - INVALID_CONDITION, - CONDITION_UNSUPPORTED, - TOOLCHAIN_FILE_UNSUPPORTED, - }; - - enum class ArchToolsetStrategy - { - Set, - External, - }; - - class CacheVariable - { - public: - std::string Type; - std::string Value; - }; - - class Condition; - - class Preset - { - public: - Preset() = default; - Preset(Preset&& /*other*/) = default; - Preset(const Preset& /*other*/) = default; - Preset& operator=(const Preset& /*other*/) = default; - virtual ~Preset() = default; -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) - Preset& operator=(Preset&& /*other*/) = default; -#else - // The move assignment operators for several STL classes did not become - // noexcept until C++17, which causes some tools to warn about this move - // assignment operator throwing an exception when it shouldn't. - Preset& operator=(Preset&& /*other*/) = delete; -#endif - - std::string Name; - std::vector Inherits; - bool Hidden; - bool User; - std::string DisplayName; - std::string Description; - - std::shared_ptr ConditionEvaluator; - bool ConditionResult = true; - - std::map> Environment; - - virtual ReadFileResult VisitPresetInherit(const Preset& parent) = 0; - virtual ReadFileResult VisitPresetBeforeInherit() - { - return ReadFileResult::READ_OK; - } - - virtual ReadFileResult VisitPresetAfterInherit(int /* version */) - { - return ReadFileResult::READ_OK; - } - }; - - class ConfigurePreset : public Preset - { - public: - ConfigurePreset() = default; - ConfigurePreset(ConfigurePreset&& /*other*/) = default; - ConfigurePreset(const ConfigurePreset& /*other*/) = default; - ConfigurePreset& operator=(const ConfigurePreset& /*other*/) = default; - ~ConfigurePreset() override = default; -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) - ConfigurePreset& operator=(ConfigurePreset&& /*other*/) = default; -#else - // The move assignment operators for several STL classes did not become - // noexcept until C++17, which causes some tools to warn about this move - // assignment operator throwing an exception when it shouldn't. - ConfigurePreset& operator=(ConfigurePreset&& /*other*/) = delete; -#endif - - std::string Generator; - std::string Architecture; - cm::optional ArchitectureStrategy; - std::string Toolset; - cm::optional ToolsetStrategy; - std::string ToolchainFile; - std::string BinaryDir; - std::string InstallDir; - - std::map> CacheVariables; - - cm::optional WarnDev; - cm::optional ErrorDev; - cm::optional WarnDeprecated; - cm::optional ErrorDeprecated; - cm::optional WarnUninitialized; - cm::optional WarnUnusedCli; - cm::optional WarnSystemVars; - - cm::optional DebugOutput; - cm::optional DebugTryCompile; - cm::optional DebugFind; - - ReadFileResult VisitPresetInherit(const Preset& parent) override; - ReadFileResult VisitPresetBeforeInherit() override; - ReadFileResult VisitPresetAfterInherit(int version) override; - }; - - class BuildPreset : public Preset - { - public: - BuildPreset() = default; - BuildPreset(BuildPreset&& /*other*/) = default; - BuildPreset(const BuildPreset& /*other*/) = default; - BuildPreset& operator=(const BuildPreset& /*other*/) = default; - ~BuildPreset() override = default; -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) - BuildPreset& operator=(BuildPreset&& /*other*/) = default; -#else - // The move assignment operators for several STL classes did not become - // noexcept until C++17, which causes some tools to warn about this move - // assignment operator throwing an exception when it shouldn't. - BuildPreset& operator=(BuildPreset&& /*other*/) = delete; -#endif - - std::string ConfigurePreset; - cm::optional InheritConfigureEnvironment; - cm::optional Jobs; - std::vector Targets; - std::string Configuration; - cm::optional CleanFirst; - cm::optional Verbose; - std::vector NativeToolOptions; - - ReadFileResult VisitPresetInherit(const Preset& parent) override; - ReadFileResult VisitPresetAfterInherit(int /* version */) override; - }; - - class TestPreset : public Preset - { - public: - TestPreset() = default; - TestPreset(TestPreset&& /*other*/) = default; - TestPreset(const TestPreset& /*other*/) = default; - TestPreset& operator=(const TestPreset& /*other*/) = default; - ~TestPreset() override = default; -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) - TestPreset& operator=(TestPreset&& /*other*/) = default; -#else - // The move assignment operators for several STL classes did not become - // noexcept until C++17, which causes some tools to warn about this move - // assignment operator throwing an exception when it shouldn't. - TestPreset& operator=(TestPreset&& /*other*/) = delete; -#endif - - struct OutputOptions - { - enum class VerbosityEnum - { - Default, - Verbose, - Extra - }; - - cm::optional ShortProgress; - cm::optional Verbosity; - cm::optional Debug; - cm::optional OutputOnFailure; - cm::optional Quiet; - std::string OutputLogFile; - cm::optional LabelSummary; - cm::optional SubprojectSummary; - cm::optional MaxPassedTestOutputSize; - cm::optional MaxFailedTestOutputSize; - cm::optional MaxTestNameWidth; - }; - - struct IncludeOptions - { - struct IndexOptions - { - cm::optional Start; - cm::optional End; - cm::optional Stride; - std::vector SpecificTests; - - std::string IndexFile; - }; - - std::string Name; - std::string Label; - cm::optional Index; - cm::optional UseUnion; - }; - - struct ExcludeOptions - { - struct FixturesOptions - { - std::string Any; - std::string Setup; - std::string Cleanup; - }; - - std::string Name; - std::string Label; - cm::optional Fixtures; - }; - - struct FilterOptions - { - cm::optional Include; - cm::optional Exclude; - }; - - struct ExecutionOptions - { - enum class ShowOnlyEnum - { - Human, - JsonV1 - }; - - struct RepeatOptions - { - enum class ModeEnum - { - UntilFail, - UntilPass, - AfterTimeout - }; - - ModeEnum Mode; - int Count; - }; - - enum class NoTestsActionEnum - { - Default, - Error, - Ignore - }; - - cm::optional StopOnFailure; - cm::optional EnableFailover; - cm::optional Jobs; - std::string ResourceSpecFile; - cm::optional TestLoad; - cm::optional ShowOnly; - - cm::optional Repeat; - cm::optional InteractiveDebugging; - cm::optional ScheduleRandom; - cm::optional Timeout; - cm::optional NoTestsAction; - }; - - std::string ConfigurePreset; - cm::optional InheritConfigureEnvironment; - std::string Configuration; - std::vector OverwriteConfigurationFile; - cm::optional Output; - cm::optional Filter; - cm::optional Execution; - - ReadFileResult VisitPresetInherit(const Preset& parent) override; - ReadFileResult VisitPresetAfterInherit(int /* version */) override; - }; - - template - class PresetPair - { - public: - T Unexpanded; - cm::optional Expanded; - }; - - std::map> ConfigurePresets; - std::map> BuildPresets; - std::map> TestPresets; - - std::vector ConfigurePresetOrder; - std::vector BuildPresetOrder; - std::vector TestPresetOrder; - - std::string SourceDir; - int Version; - int UserVersion; - - int GetVersion(const Preset& preset) const - { - return preset.User ? this->UserVersion : this->Version; - } - - static std::string GetFilename(const std::string& sourceDir); - static std::string GetUserFilename(const std::string& sourceDir); - ReadFileResult ReadProjectPresets(const std::string& sourceDir, - bool allowNoFiles = false); - static const char* ResultToString(ReadFileResult result); - - std::string GetGeneratorForPreset(const std::string& presetName) const - { - auto configurePresetName = presetName; - - auto buildPresetIterator = this->BuildPresets.find(presetName); - if (buildPresetIterator != this->BuildPresets.end()) { - configurePresetName = - buildPresetIterator->second.Unexpanded.ConfigurePreset; - } else { - auto testPresetIterator = this->TestPresets.find(presetName); - if (testPresetIterator != this->TestPresets.end()) { - configurePresetName = - testPresetIterator->second.Unexpanded.ConfigurePreset; - } - } - - auto configurePresetIterator = - this->ConfigurePresets.find(configurePresetName); - if (configurePresetIterator != this->ConfigurePresets.end()) { - return configurePresetIterator->second.Unexpanded.Generator; - } - - // This should only happen if the preset is hidden - // or (for build or test presets) if ConfigurePreset is invalid. - return ""; - } - - static void PrintPresets( - const std::vector& presets); - void PrintConfigurePresetList() const; - void PrintConfigurePresetList( - const std::function& filter) const; - void PrintBuildPresetList() const; - void PrintTestPresetList() const; - void PrintAllPresets() const; - -private: - ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles); - ReadFileResult ReadJSONFile(const std::string& filename, bool user); - void ClearPresets(); -}; diff --git a/Source/cmCMakePresetsFileInternal.h b/Source/cmCMakePresetsFileInternal.h deleted file mode 100644 index afb00ce..0000000 --- a/Source/cmCMakePresetsFileInternal.h +++ /dev/null @@ -1,112 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include - -#include "cmCMakePresetsFile.h" - -#define CHECK_OK(expr) \ - do { \ - auto _result = expr; \ - if (_result != ReadFileResult::READ_OK) \ - return _result; \ - } while (false) - -namespace cmCMakePresetsFileInternal { -enum class ExpandMacroResult -{ - Ok, - Ignore, - Error, -}; - -using MacroExpander = std::function; -} - -class cmCMakePresetsFile::Condition -{ -public: - virtual ~Condition() = default; - - virtual bool Evaluate( - const std::vector& expanders, - int version, cm::optional& out) const = 0; - virtual bool IsNull() const { return false; } -}; - -namespace cmCMakePresetsFileInternal { - -class NullCondition : public cmCMakePresetsFile::Condition -{ - bool Evaluate(const std::vector& /*expanders*/, - int /*version*/, cm::optional& out) const override - { - out = true; - return true; - } - - bool IsNull() const override { return true; } -}; - -class ConstCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector& /*expanders*/, - int /*version*/, cm::optional& out) const override - { - out = this->Value; - return true; - } - - bool Value; -}; - -class EqualsCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector& expanders, int version, - cm::optional& out) const override; - - std::string Lhs; - std::string Rhs; -}; - -class InListCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector& expanders, int version, - cm::optional& out) const override; - - std::string String; - std::vector List; -}; - -class MatchesCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector& expanders, int version, - cm::optional& out) const override; - - std::string String; - std::string Regex; -}; - -class AnyAllOfCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector& expanders, int version, - cm::optional& out) const override; - - std::vector> Conditions; - bool StopValue; -}; - -class NotCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector& expanders, int version, - cm::optional& out) const override; - - std::unique_ptr SubCondition; -}; -} diff --git a/Source/cmCMakePresetsFileReadJSON.cxx b/Source/cmCMakePresetsFileReadJSON.cxx deleted file mode 100644 index 489551d..0000000 --- a/Source/cmCMakePresetsFileReadJSON.cxx +++ /dev/null @@ -1,1032 +0,0 @@ -/* 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; -} diff --git a/Source/cmCMakePresetsGraph.cxx b/Source/cmCMakePresetsGraph.cxx new file mode 100644 index 0000000..ebc243b --- /dev/null +++ b/Source/cmCMakePresetsGraph.cxx @@ -0,0 +1,1116 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCMakePresetsGraph.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "cmsys/RegularExpression.hxx" + +#include "cmCMakePresetsGraphInternal.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +#define CHECK_EXPAND(out, field, expanders, version) \ + do { \ + switch (ExpandMacros(field, expanders, version)) { \ + case ExpandMacroResult::Error: \ + return false; \ + case ExpandMacroResult::Ignore: \ + out.reset(); \ + return true; \ + case ExpandMacroResult::Ok: \ + break; \ + } \ + } while (false) + +namespace { +enum class CycleStatus +{ + Unvisited, + InProgress, + Verified, +}; + +using ReadFileResult = cmCMakePresetsGraph::ReadFileResult; +using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset; +using BuildPreset = cmCMakePresetsGraph::BuildPreset; +using TestPreset = cmCMakePresetsGraph::TestPreset; +using ExpandMacroResult = cmCMakePresetsGraphInternal::ExpandMacroResult; +using MacroExpander = cmCMakePresetsGraphInternal::MacroExpander; + +void InheritString(std::string& child, const std::string& parent) +{ + if (child.empty()) { + child = parent; + } +} + +template +void InheritOptionalValue(cm::optional& child, + const cm::optional& parent) +{ + if (!child) { + child = parent; + } +} + +template +void InheritVector(std::vector& child, const std::vector& parent) +{ + if (child.empty()) { + child = parent; + } +} + +/** + * Check preset inheritance for cycles (using a DAG check algorithm) while + * also bubbling up fields through the inheritance hierarchy, then verify + * that each preset has the required fields, either directly or through + * inheritance. + */ +template +ReadFileResult VisitPreset( + T& preset, + std::map>& presets, + std::map cycleStatus, + const cmCMakePresetsGraph& graph) +{ + switch (cycleStatus[preset.Name]) { + case CycleStatus::InProgress: + return ReadFileResult::CYCLIC_PRESET_INHERITANCE; + case CycleStatus::Verified: + return ReadFileResult::READ_OK; + default: + break; + } + + cycleStatus[preset.Name] = CycleStatus::InProgress; + + if (preset.Environment.count("") != 0) { + return ReadFileResult::INVALID_PRESET; + } + + CHECK_OK(preset.VisitPresetBeforeInherit()); + + for (auto const& i : preset.Inherits) { + auto parent = presets.find(i); + if (parent == presets.end()) { + return ReadFileResult::INVALID_PRESET; + } + + auto& parentPreset = parent->second.Unexpanded; + if (!preset.User && parentPreset.User) { + return ReadFileResult::USER_PRESET_INHERITANCE; + } + + auto result = VisitPreset(parentPreset, presets, cycleStatus, graph); + if (result != ReadFileResult::READ_OK) { + return result; + } + + CHECK_OK(preset.VisitPresetInherit(parentPreset)); + + for (auto const& v : parentPreset.Environment) { + preset.Environment.insert(v); + } + + if (!preset.ConditionEvaluator) { + preset.ConditionEvaluator = parentPreset.ConditionEvaluator; + } + } + + if (preset.ConditionEvaluator && preset.ConditionEvaluator->IsNull()) { + preset.ConditionEvaluator.reset(); + } + + CHECK_OK(preset.VisitPresetAfterInherit(graph.GetVersion(preset))); + + cycleStatus[preset.Name] = CycleStatus::Verified; + return ReadFileResult::READ_OK; +} + +template +ReadFileResult ComputePresetInheritance( + std::map>& presets, + const cmCMakePresetsGraph& graph) +{ + std::map cycleStatus; + for (auto const& it : presets) { + cycleStatus[it.first] = CycleStatus::Unvisited; + } + + for (auto& it : presets) { + auto& preset = it.second.Unexpanded; + auto result = VisitPreset(preset, presets, cycleStatus, graph); + if (result != ReadFileResult::READ_OK) { + return result; + } + } + + return ReadFileResult::READ_OK; +} + +constexpr const char* ValidPrefixes[] = { + "", + "env", + "penv", + "vendor", +}; + +bool PrefixesValidMacroNamespace(const std::string& str) +{ + return std::any_of( + std::begin(ValidPrefixes), std::end(ValidPrefixes), + [&str](const char* prefix) -> bool { return cmHasPrefix(prefix, str); }); +} + +bool IsValidMacroNamespace(const std::string& str) +{ + return std::any_of( + std::begin(ValidPrefixes), std::end(ValidPrefixes), + [&str](const char* prefix) -> bool { return str == prefix; }); +} + +ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status, + const std::vector& macroExpanders, + int version); +ExpandMacroResult ExpandMacros( + std::string& out, const std::vector& macroExpanders, + int version); +ExpandMacroResult ExpandMacro(std::string& out, + const std::string& macroNamespace, + const std::string& macroName, + const std::vector& macroExpanders, + int version); + +bool ExpandMacros(const cmCMakePresetsGraph& graph, + const ConfigurePreset& preset, + cm::optional& out, + const std::vector& macroExpanders) +{ + std::string binaryDir = preset.BinaryDir; + CHECK_EXPAND(out, binaryDir, macroExpanders, graph.GetVersion(preset)); + + if (!binaryDir.empty()) { + if (!cmSystemTools::FileIsFullPath(binaryDir)) { + binaryDir = cmStrCat(graph.SourceDir, '/', binaryDir); + } + out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir); + cmSystemTools::ConvertToUnixSlashes(out->BinaryDir); + } + + if (!preset.InstallDir.empty()) { + std::string installDir = preset.InstallDir; + CHECK_EXPAND(out, installDir, macroExpanders, graph.GetVersion(preset)); + + if (!cmSystemTools::FileIsFullPath(installDir)) { + installDir = cmStrCat(graph.SourceDir, '/', installDir); + } + out->InstallDir = cmSystemTools::CollapseFullPath(installDir); + cmSystemTools::ConvertToUnixSlashes(out->InstallDir); + } + + if (!preset.ToolchainFile.empty()) { + std::string toolchain = preset.ToolchainFile; + CHECK_EXPAND(out, toolchain, macroExpanders, graph.GetVersion(preset)); + out->ToolchainFile = toolchain; + } + + for (auto& variable : out->CacheVariables) { + if (variable.second) { + CHECK_EXPAND(out, variable.second->Value, macroExpanders, + graph.GetVersion(preset)); + } + } + + return true; +} + +bool ExpandMacros(const cmCMakePresetsGraph& graph, const BuildPreset& preset, + cm::optional& out, + const std::vector& macroExpanders) +{ + for (auto& target : out->Targets) { + CHECK_EXPAND(out, target, macroExpanders, graph.GetVersion(preset)); + } + + for (auto& nativeToolOption : out->NativeToolOptions) { + CHECK_EXPAND(out, nativeToolOption, macroExpanders, + graph.GetVersion(preset)); + } + + return true; +} + +bool ExpandMacros(const cmCMakePresetsGraph& graph, const TestPreset& preset, + cm::optional& out, + const std::vector& macroExpanders) +{ + for (auto& overwrite : out->OverwriteConfigurationFile) { + CHECK_EXPAND(out, overwrite, macroExpanders, graph.GetVersion(preset)); + } + + if (out->Output) { + CHECK_EXPAND(out, out->Output->OutputLogFile, macroExpanders, + graph.GetVersion(preset)); + } + + if (out->Filter) { + if (out->Filter->Include) { + CHECK_EXPAND(out, out->Filter->Include->Name, macroExpanders, + graph.GetVersion(preset)); + CHECK_EXPAND(out, out->Filter->Include->Label, macroExpanders, + graph.GetVersion(preset)); + + if (out->Filter->Include->Index) { + CHECK_EXPAND(out, out->Filter->Include->Index->IndexFile, + macroExpanders, graph.GetVersion(preset)); + } + } + + if (out->Filter->Exclude) { + CHECK_EXPAND(out, out->Filter->Exclude->Name, macroExpanders, + graph.GetVersion(preset)); + CHECK_EXPAND(out, out->Filter->Exclude->Label, macroExpanders, + graph.GetVersion(preset)); + + if (out->Filter->Exclude->Fixtures) { + CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Any, macroExpanders, + graph.GetVersion(preset)); + CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Setup, + macroExpanders, graph.GetVersion(preset)); + CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Cleanup, + macroExpanders, graph.GetVersion(preset)); + } + } + } + + if (out->Execution) { + CHECK_EXPAND(out, out->Execution->ResourceSpecFile, macroExpanders, + graph.GetVersion(preset)); + } + + return true; +} + +template +bool ExpandMacros(const cmCMakePresetsGraph& graph, const T& preset, + cm::optional& out) +{ + out.emplace(preset); + + std::map envCycles; + for (auto const& v : out->Environment) { + envCycles[v.first] = CycleStatus::Unvisited; + } + + std::vector macroExpanders; + + MacroExpander defaultMacroExpander = + [&graph, &preset](const std::string& macroNamespace, + const std::string& macroName, std::string& macroOut, + int version) -> ExpandMacroResult { + if (macroNamespace.empty()) { + if (macroName == "sourceDir") { + macroOut += graph.SourceDir; + return ExpandMacroResult::Ok; + } + if (macroName == "sourceParentDir") { + macroOut += cmSystemTools::GetParentDirectory(graph.SourceDir); + return ExpandMacroResult::Ok; + } + if (macroName == "sourceDirName") { + macroOut += cmSystemTools::GetFilenameName(graph.SourceDir); + return ExpandMacroResult::Ok; + } + if (macroName == "presetName") { + macroOut += preset.Name; + return ExpandMacroResult::Ok; + } + if (macroName == "generator") { + // Generator only makes sense if preset is not hidden. + if (!preset.Hidden) { + macroOut += graph.GetGeneratorForPreset(preset.Name); + } + return ExpandMacroResult::Ok; + } + if (macroName == "dollar") { + macroOut += '$'; + return ExpandMacroResult::Ok; + } + if (macroName == "hostSystemName") { + if (version < 3) { + return ExpandMacroResult::Error; + } + macroOut += cmSystemTools::GetSystemName(); + return ExpandMacroResult::Ok; + } + } + + return ExpandMacroResult::Ignore; + }; + + MacroExpander environmentMacroExpander = + [¯oExpanders, &out, &envCycles]( + const std::string& macroNamespace, const std::string& macroName, + std::string& result, int version) -> ExpandMacroResult { + if (macroNamespace == "env" && !macroName.empty() && out) { + auto v = out->Environment.find(macroName); + if (v != out->Environment.end() && v->second) { + auto e = + VisitEnv(*v->second, envCycles[macroName], macroExpanders, version); + if (e != ExpandMacroResult::Ok) { + return e; + } + result += *v->second; + return ExpandMacroResult::Ok; + } + } + + if (macroNamespace == "env" || macroNamespace == "penv") { + if (macroName.empty()) { + return ExpandMacroResult::Error; + } + const char* value = std::getenv(macroName.c_str()); + if (value) { + result += value; + } + return ExpandMacroResult::Ok; + } + + return ExpandMacroResult::Ignore; + }; + + macroExpanders.push_back(defaultMacroExpander); + macroExpanders.push_back(environmentMacroExpander); + + for (auto& v : out->Environment) { + if (v.second) { + switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders, + graph.GetVersion(preset))) { + case ExpandMacroResult::Error: + return false; + case ExpandMacroResult::Ignore: + out.reset(); + return true; + case ExpandMacroResult::Ok: + break; + } + } + } + + if (preset.ConditionEvaluator) { + cm::optional result; + if (!preset.ConditionEvaluator->Evaluate( + macroExpanders, graph.GetVersion(preset), result)) { + return false; + } + if (!result) { + out.reset(); + return true; + } + out->ConditionResult = *result; + } + + return ExpandMacros(graph, preset, out, macroExpanders); +} + +ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status, + const std::vector& macroExpanders, + int version) +{ + if (status == CycleStatus::Verified) { + return ExpandMacroResult::Ok; + } + if (status == CycleStatus::InProgress) { + return ExpandMacroResult::Error; + } + + status = CycleStatus::InProgress; + auto e = ExpandMacros(value, macroExpanders, version); + if (e != ExpandMacroResult::Ok) { + return e; + } + status = CycleStatus::Verified; + return ExpandMacroResult::Ok; +} + +ExpandMacroResult ExpandMacros( + std::string& out, const std::vector& macroExpanders, + int version) +{ + std::string result; + std::string macroNamespace; + std::string macroName; + + enum class State + { + Default, + MacroNamespace, + MacroName, + } state = State::Default; + + for (auto c : out) { + switch (state) { + case State::Default: + if (c == '$') { + state = State::MacroNamespace; + } else { + result += c; + } + break; + + case State::MacroNamespace: + if (c == '{') { + if (IsValidMacroNamespace(macroNamespace)) { + state = State::MacroName; + } else { + result += '$'; + result += macroNamespace; + result += '{'; + macroNamespace.clear(); + state = State::Default; + } + } else { + macroNamespace += c; + if (!PrefixesValidMacroNamespace(macroNamespace)) { + result += '$'; + result += macroNamespace; + macroNamespace.clear(); + state = State::Default; + } + } + break; + + case State::MacroName: + if (c == '}') { + auto e = ExpandMacro(result, macroNamespace, macroName, + macroExpanders, version); + if (e != ExpandMacroResult::Ok) { + return e; + } + macroNamespace.clear(); + macroName.clear(); + state = State::Default; + } else { + macroName += c; + } + break; + } + } + + switch (state) { + case State::Default: + break; + case State::MacroNamespace: + result += '$'; + result += macroNamespace; + break; + case State::MacroName: + return ExpandMacroResult::Error; + } + + out = std::move(result); + return ExpandMacroResult::Ok; +} + +ExpandMacroResult ExpandMacro(std::string& out, + const std::string& macroNamespace, + const std::string& macroName, + const std::vector& macroExpanders, + int version) +{ + for (auto const& macroExpander : macroExpanders) { + auto result = macroExpander(macroNamespace, macroName, out, version); + if (result != ExpandMacroResult::Ignore) { + return result; + } + } + + if (macroNamespace == "vendor") { + return ExpandMacroResult::Ignore; + } + + return ExpandMacroResult::Error; +} +} + +bool cmCMakePresetsGraphInternal::EqualsCondition::Evaluate( + const std::vector& expanders, int version, + cm::optional& out) const +{ + std::string lhs = this->Lhs; + CHECK_EXPAND(out, lhs, expanders, version); + + std::string rhs = this->Rhs; + CHECK_EXPAND(out, rhs, expanders, version); + + out = (lhs == rhs); + return true; +} + +bool cmCMakePresetsGraphInternal::InListCondition::Evaluate( + const std::vector& expanders, int version, + cm::optional& out) const +{ + std::string str = this->String; + CHECK_EXPAND(out, str, expanders, version); + + for (auto item : this->List) { + CHECK_EXPAND(out, item, expanders, version); + if (str == item) { + out = true; + return true; + } + } + + out = false; + return true; +} + +bool cmCMakePresetsGraphInternal::MatchesCondition::Evaluate( + const std::vector& expanders, int version, + cm::optional& out) const +{ + std::string str = this->String; + CHECK_EXPAND(out, str, expanders, version); + std::string regexStr = this->Regex; + CHECK_EXPAND(out, regexStr, expanders, version); + + cmsys::RegularExpression regex; + if (!regex.compile(regexStr)) { + return false; + } + + out = regex.find(str); + return true; +} + +bool cmCMakePresetsGraphInternal::AnyAllOfCondition::Evaluate( + const std::vector& expanders, int version, + cm::optional& out) const +{ + for (auto const& condition : this->Conditions) { + cm::optional result; + if (!condition->Evaluate(expanders, version, result)) { + out.reset(); + return false; + } + + if (!result) { + out.reset(); + return true; + } + + if (result == this->StopValue) { + out = result; + return true; + } + } + + out = !this->StopValue; + return true; +} + +bool cmCMakePresetsGraphInternal::NotCondition::Evaluate( + const std::vector& expanders, int version, + cm::optional& out) const +{ + out.reset(); + if (!this->SubCondition->Evaluate(expanders, version, out)) { + out.reset(); + return false; + } + if (out) { + *out = !*out; + } + return true; +} + +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::ConfigurePreset::VisitPresetInherit( + const cmCMakePresetsGraph::Preset& parentPreset) +{ + auto& preset = *this; + const ConfigurePreset& parent = + static_cast(parentPreset); + InheritString(preset.Generator, parent.Generator); + InheritString(preset.Architecture, parent.Architecture); + InheritString(preset.Toolset, parent.Toolset); + if (!preset.ArchitectureStrategy) { + preset.ArchitectureStrategy = parent.ArchitectureStrategy; + } + if (!preset.ToolsetStrategy) { + preset.ToolsetStrategy = parent.ToolsetStrategy; + } + InheritString(preset.BinaryDir, parent.BinaryDir); + InheritString(preset.InstallDir, parent.InstallDir); + InheritString(preset.ToolchainFile, parent.ToolchainFile); + InheritOptionalValue(preset.WarnDev, parent.WarnDev); + InheritOptionalValue(preset.ErrorDev, parent.ErrorDev); + InheritOptionalValue(preset.WarnDeprecated, parent.WarnDeprecated); + InheritOptionalValue(preset.ErrorDeprecated, parent.ErrorDeprecated); + InheritOptionalValue(preset.WarnUninitialized, parent.WarnUninitialized); + InheritOptionalValue(preset.WarnUnusedCli, parent.WarnUnusedCli); + InheritOptionalValue(preset.WarnSystemVars, parent.WarnSystemVars); + + for (auto const& v : parent.CacheVariables) { + preset.CacheVariables.insert(v); + } + + return ReadFileResult::READ_OK; +} + +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::ConfigurePreset::VisitPresetBeforeInherit() +{ + auto& preset = *this; + if (preset.Environment.count("") != 0) { + return ReadFileResult::INVALID_PRESET; + } + + return ReadFileResult::READ_OK; +} + +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::ConfigurePreset::VisitPresetAfterInherit(int version) +{ + auto& preset = *this; + if (!preset.Hidden) { + if (version < 3) { + if (preset.Generator.empty()) { + return ReadFileResult::INVALID_PRESET; + } + if (preset.BinaryDir.empty()) { + return ReadFileResult::INVALID_PRESET; + } + } + + if (preset.WarnDev == false && preset.ErrorDev == true) { + return ReadFileResult::INVALID_PRESET; + } + if (preset.WarnDeprecated == false && preset.ErrorDeprecated == true) { + return ReadFileResult::INVALID_PRESET; + } + if (preset.CacheVariables.count("") != 0) { + return ReadFileResult::INVALID_PRESET; + } + } + + return ReadFileResult::READ_OK; +} + +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::BuildPreset::VisitPresetInherit( + const cmCMakePresetsGraph::Preset& parentPreset) +{ + auto& preset = *this; + const BuildPreset& parent = static_cast(parentPreset); + + InheritString(preset.ConfigurePreset, parent.ConfigurePreset); + InheritOptionalValue(preset.InheritConfigureEnvironment, + parent.InheritConfigureEnvironment); + InheritOptionalValue(preset.Jobs, parent.Jobs); + InheritVector(preset.Targets, parent.Targets); + InheritString(preset.Configuration, parent.Configuration); + InheritOptionalValue(preset.CleanFirst, parent.CleanFirst); + InheritOptionalValue(preset.Verbose, parent.Verbose); + InheritVector(preset.NativeToolOptions, parent.NativeToolOptions); + + return ReadFileResult::READ_OK; +} + +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::BuildPreset::VisitPresetAfterInherit(int /* version */) +{ + auto& preset = *this; + if (!preset.Hidden && preset.ConfigurePreset.empty()) { + return ReadFileResult::INVALID_PRESET; + } + return ReadFileResult::READ_OK; +} + +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::TestPreset::VisitPresetInherit( + const cmCMakePresetsGraph::Preset& parentPreset) +{ + auto& preset = *this; + const TestPreset& parent = static_cast(parentPreset); + + InheritString(preset.ConfigurePreset, parent.ConfigurePreset); + InheritOptionalValue(preset.InheritConfigureEnvironment, + parent.InheritConfigureEnvironment); + InheritString(preset.Configuration, parent.Configuration); + InheritVector(preset.OverwriteConfigurationFile, + parent.OverwriteConfigurationFile); + + if (parent.Output) { + if (preset.Output) { + auto& output = preset.Output.value(); + const auto& parentOutput = parent.Output.value(); + InheritOptionalValue(output.ShortProgress, parentOutput.ShortProgress); + InheritOptionalValue(output.Verbosity, parentOutput.Verbosity); + InheritOptionalValue(output.Debug, parentOutput.Debug); + InheritOptionalValue(output.OutputOnFailure, + parentOutput.OutputOnFailure); + InheritOptionalValue(output.Quiet, parentOutput.Quiet); + InheritString(output.OutputLogFile, parentOutput.OutputLogFile); + InheritOptionalValue(output.LabelSummary, parentOutput.LabelSummary); + InheritOptionalValue(output.SubprojectSummary, + parentOutput.SubprojectSummary); + InheritOptionalValue(output.MaxPassedTestOutputSize, + parentOutput.MaxPassedTestOutputSize); + InheritOptionalValue(output.MaxFailedTestOutputSize, + parentOutput.MaxFailedTestOutputSize); + InheritOptionalValue(output.MaxTestNameWidth, + parentOutput.MaxTestNameWidth); + } else { + preset.Output = parent.Output; + } + } + + if (parent.Filter) { + if (parent.Filter->Include) { + if (preset.Filter && preset.Filter->Include) { + auto& include = *preset.Filter->Include; + const auto& parentInclude = *parent.Filter->Include; + InheritString(include.Name, parentInclude.Name); + InheritString(include.Label, parentInclude.Label); + InheritOptionalValue(include.Index, parentInclude.Index); + } else { + if (!preset.Filter) { + preset.Filter.emplace(); + } + preset.Filter->Include = parent.Filter->Include; + } + } + + if (parent.Filter->Exclude) { + if (preset.Filter && preset.Filter->Exclude) { + auto& exclude = *preset.Filter->Exclude; + const auto& parentExclude = *parent.Filter->Exclude; + InheritString(exclude.Name, parentExclude.Name); + InheritString(exclude.Label, parentExclude.Label); + InheritOptionalValue(exclude.Fixtures, parentExclude.Fixtures); + } else { + if (!preset.Filter) { + preset.Filter.emplace(); + } + preset.Filter->Exclude = parent.Filter->Exclude; + } + } + } + + if (parent.Execution) { + if (preset.Execution) { + auto& execution = *preset.Execution; + const auto& parentExecution = *parent.Execution; + InheritOptionalValue(execution.StopOnFailure, + parentExecution.StopOnFailure); + InheritOptionalValue(execution.EnableFailover, + parentExecution.EnableFailover); + InheritOptionalValue(execution.Jobs, parentExecution.Jobs); + InheritString(execution.ResourceSpecFile, + parentExecution.ResourceSpecFile); + InheritOptionalValue(execution.TestLoad, parentExecution.TestLoad); + InheritOptionalValue(execution.ShowOnly, parentExecution.ShowOnly); + InheritOptionalValue(execution.Repeat, parentExecution.Repeat); + InheritOptionalValue(execution.InteractiveDebugging, + parentExecution.InteractiveDebugging); + InheritOptionalValue(execution.ScheduleRandom, + parentExecution.ScheduleRandom); + InheritOptionalValue(execution.Timeout, parentExecution.Timeout); + InheritOptionalValue(execution.NoTestsAction, + parentExecution.NoTestsAction); + } else { + preset.Execution = parent.Execution; + } + } + + return ReadFileResult::READ_OK; +} + +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::TestPreset::VisitPresetAfterInherit(int /* version */) +{ + auto& preset = *this; + if (!preset.Hidden && preset.ConfigurePreset.empty()) { + return ReadFileResult::INVALID_PRESET; + } + return ReadFileResult::READ_OK; +} + +std::string cmCMakePresetsGraph::GetFilename(const std::string& sourceDir) +{ + return cmStrCat(sourceDir, "/CMakePresets.json"); +} + +std::string cmCMakePresetsGraph::GetUserFilename(const std::string& sourceDir) +{ + return cmStrCat(sourceDir, "/CMakeUserPresets.json"); +} + +cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadProjectPresets( + const std::string& sourceDir, bool allowNoFiles) +{ + this->SourceDir = sourceDir; + this->ClearPresets(); + + auto result = this->ReadProjectPresetsInternal(allowNoFiles); + if (result != ReadFileResult::READ_OK) { + this->ClearPresets(); + } + + return result; +} + +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles) +{ + bool haveOneFile = false; + + std::string filename = GetUserFilename(this->SourceDir); + if (cmSystemTools::FileExists(filename)) { + auto result = this->ReadJSONFile(filename, true); + if (result != ReadFileResult::READ_OK) { + return result; + } + haveOneFile = true; + } + + filename = GetFilename(this->SourceDir); + if (cmSystemTools::FileExists(filename)) { + auto result = this->ReadJSONFile(filename, false); + if (result != ReadFileResult::READ_OK) { + return result; + } + haveOneFile = true; + } + + if (!haveOneFile) { + return allowNoFiles ? ReadFileResult::READ_OK + : ReadFileResult::FILE_NOT_FOUND; + } + + CHECK_OK(ComputePresetInheritance(this->ConfigurePresets, *this)); + CHECK_OK(ComputePresetInheritance(this->BuildPresets, *this)); + CHECK_OK(ComputePresetInheritance(this->TestPresets, *this)); + + for (auto& it : this->ConfigurePresets) { + if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) { + return ReadFileResult::INVALID_MACRO_EXPANSION; + } + } + + for (auto& it : this->BuildPresets) { + if (!it.second.Unexpanded.Hidden) { + const auto configurePreset = + this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset); + if (configurePreset == this->ConfigurePresets.end()) { + return ReadFileResult::INVALID_CONFIGURE_PRESET; + } + + if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) { + it.second.Unexpanded.Environment.insert( + configurePreset->second.Unexpanded.Environment.begin(), + configurePreset->second.Unexpanded.Environment.end()); + } + } + + if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) { + return ReadFileResult::INVALID_MACRO_EXPANSION; + } + } + + for (auto& it : this->TestPresets) { + if (!it.second.Unexpanded.Hidden) { + const auto configurePreset = + this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset); + if (configurePreset == this->ConfigurePresets.end()) { + return ReadFileResult::INVALID_CONFIGURE_PRESET; + } + + if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) { + it.second.Unexpanded.Environment.insert( + configurePreset->second.Unexpanded.Environment.begin(), + configurePreset->second.Unexpanded.Environment.end()); + } + } + + if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) { + return ReadFileResult::INVALID_MACRO_EXPANSION; + } + } + + return ReadFileResult::READ_OK; +} + +const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result) +{ + switch (result) { + case ReadFileResult::READ_OK: + return "OK"; + case ReadFileResult::FILE_NOT_FOUND: + return "File not found"; + case ReadFileResult::JSON_PARSE_ERROR: + return "JSON parse error"; + case ReadFileResult::INVALID_ROOT: + return "Invalid root object"; + case ReadFileResult::NO_VERSION: + return "No \"version\" field"; + case ReadFileResult::INVALID_VERSION: + return "Invalid \"version\" field"; + case ReadFileResult::UNRECOGNIZED_VERSION: + return "Unrecognized \"version\" field"; + case ReadFileResult::INVALID_CMAKE_VERSION: + return "Invalid \"cmakeMinimumRequired\" field"; + case ReadFileResult::UNRECOGNIZED_CMAKE_VERSION: + return "\"cmakeMinimumRequired\" version too new"; + case ReadFileResult::INVALID_PRESETS: + return "Invalid \"configurePresets\" field"; + case ReadFileResult::INVALID_PRESET: + return "Invalid preset"; + case ReadFileResult::INVALID_VARIABLE: + return "Invalid CMake variable definition"; + case ReadFileResult::DUPLICATE_PRESETS: + return "Duplicate presets"; + case ReadFileResult::CYCLIC_PRESET_INHERITANCE: + return "Cyclic preset inheritance"; + case ReadFileResult::USER_PRESET_INHERITANCE: + return "Project preset inherits from user preset"; + case ReadFileResult::INVALID_MACRO_EXPANSION: + return "Invalid macro expansion"; + case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED: + return "File version must be 2 or higher for build and test preset " + "support."; + case ReadFileResult::INVALID_CONFIGURE_PRESET: + return "Invalid \"configurePreset\" field"; + case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED: + return "File version must be 3 or higher for installDir preset " + "support."; + case ReadFileResult::INVALID_CONDITION: + return "Invalid preset condition"; + case ReadFileResult::CONDITION_UNSUPPORTED: + return "File version must be 3 or higher for condition support"; + case ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED: + return "File version must be 3 or higher for toolchainFile preset " + "support."; + } + + return "Unknown error"; +} + +void cmCMakePresetsGraph::ClearPresets() +{ + this->ConfigurePresets.clear(); + this->BuildPresets.clear(); + this->TestPresets.clear(); + + this->ConfigurePresetOrder.clear(); + this->BuildPresetOrder.clear(); + this->TestPresetOrder.clear(); +} + +void cmCMakePresetsGraph::PrintPresets( + const std::vector& presets) +{ + if (presets.empty()) { + return; + } + + auto longestPresetName = + std::max_element(presets.begin(), presets.end(), + [](const cmCMakePresetsGraph::Preset* a, + const cmCMakePresetsGraph::Preset* b) { + return a->Name.length() < b->Name.length(); + }); + auto longestLength = (*longestPresetName)->Name.length(); + + for (const auto* preset : presets) { + std::cout << " \"" << preset->Name << '"'; + const auto& description = preset->DisplayName; + if (!description.empty()) { + for (std::size_t i = 0; i < longestLength - preset->Name.length(); ++i) { + std::cout << ' '; + } + std::cout << " - " << description; + } + std::cout << '\n'; + } +} + +void cmCMakePresetsGraph::PrintConfigurePresetList() const +{ + PrintConfigurePresetList([](const ConfigurePreset&) { return true; }); +} + +void cmCMakePresetsGraph::PrintConfigurePresetList( + const std::function& filter) const +{ + std::vector presets; + for (auto const& p : this->ConfigurePresetOrder) { + auto const& preset = this->ConfigurePresets.at(p); + if (!preset.Unexpanded.Hidden && preset.Expanded && + preset.Expanded->ConditionResult && filter(preset.Unexpanded)) { + presets.push_back( + static_cast(&preset.Unexpanded)); + } + } + + if (!presets.empty()) { + std::cout << "Available configure presets:\n\n"; + cmCMakePresetsGraph::PrintPresets(presets); + } +} + +void cmCMakePresetsGraph::PrintBuildPresetList() const +{ + std::vector presets; + for (auto const& p : this->BuildPresetOrder) { + auto const& preset = this->BuildPresets.at(p); + if (!preset.Unexpanded.Hidden && preset.Expanded && + preset.Expanded->ConditionResult) { + presets.push_back( + static_cast(&preset.Unexpanded)); + } + } + + if (!presets.empty()) { + std::cout << "Available build presets:\n\n"; + cmCMakePresetsGraph::PrintPresets(presets); + } +} + +void cmCMakePresetsGraph::PrintTestPresetList() const +{ + std::vector presets; + for (auto const& p : this->TestPresetOrder) { + auto const& preset = this->TestPresets.at(p); + if (!preset.Unexpanded.Hidden && preset.Expanded && + preset.Expanded->ConditionResult) { + presets.push_back( + static_cast(&preset.Unexpanded)); + } + } + + if (!presets.empty()) { + std::cout << "Available test presets:\n\n"; + cmCMakePresetsGraph::PrintPresets(presets); + } +} + +void cmCMakePresetsGraph::PrintAllPresets() const +{ + this->PrintConfigurePresetList(); + std::cout << std::endl; + this->PrintBuildPresetList(); + std::cout << std::endl; + this->PrintTestPresetList(); +} diff --git a/Source/cmCMakePresetsGraph.h b/Source/cmCMakePresetsGraph.h new file mode 100644 index 0000000..937b281 --- /dev/null +++ b/Source/cmCMakePresetsGraph.h @@ -0,0 +1,378 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include +#include +#include +#include +#include +#include + +#include + +class cmCMakePresetsGraph +{ +public: + enum class ReadFileResult + { + READ_OK, + FILE_NOT_FOUND, + JSON_PARSE_ERROR, + INVALID_ROOT, + NO_VERSION, + INVALID_VERSION, + UNRECOGNIZED_VERSION, + INVALID_CMAKE_VERSION, + UNRECOGNIZED_CMAKE_VERSION, + INVALID_PRESETS, + INVALID_PRESET, + INVALID_VARIABLE, + DUPLICATE_PRESETS, + CYCLIC_PRESET_INHERITANCE, + USER_PRESET_INHERITANCE, + INVALID_MACRO_EXPANSION, + BUILD_TEST_PRESETS_UNSUPPORTED, + INVALID_CONFIGURE_PRESET, + INSTALL_PREFIX_UNSUPPORTED, + INVALID_CONDITION, + CONDITION_UNSUPPORTED, + TOOLCHAIN_FILE_UNSUPPORTED, + }; + + enum class ArchToolsetStrategy + { + Set, + External, + }; + + class CacheVariable + { + public: + std::string Type; + std::string Value; + }; + + class Condition; + + class Preset + { + public: + Preset() = default; + Preset(Preset&& /*other*/) = default; + Preset(const Preset& /*other*/) = default; + Preset& operator=(const Preset& /*other*/) = default; + virtual ~Preset() = default; +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + Preset& operator=(Preset&& /*other*/) = default; +#else + // The move assignment operators for several STL classes did not become + // noexcept until C++17, which causes some tools to warn about this move + // assignment operator throwing an exception when it shouldn't. + Preset& operator=(Preset&& /*other*/) = delete; +#endif + + std::string Name; + std::vector Inherits; + bool Hidden; + bool User; + std::string DisplayName; + std::string Description; + + std::shared_ptr ConditionEvaluator; + bool ConditionResult = true; + + std::map> Environment; + + virtual ReadFileResult VisitPresetInherit(const Preset& parent) = 0; + virtual ReadFileResult VisitPresetBeforeInherit() + { + return ReadFileResult::READ_OK; + } + + virtual ReadFileResult VisitPresetAfterInherit(int /* version */) + { + return ReadFileResult::READ_OK; + } + }; + + class ConfigurePreset : public Preset + { + public: + ConfigurePreset() = default; + ConfigurePreset(ConfigurePreset&& /*other*/) = default; + ConfigurePreset(const ConfigurePreset& /*other*/) = default; + ConfigurePreset& operator=(const ConfigurePreset& /*other*/) = default; + ~ConfigurePreset() override = default; +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + ConfigurePreset& operator=(ConfigurePreset&& /*other*/) = default; +#else + // The move assignment operators for several STL classes did not become + // noexcept until C++17, which causes some tools to warn about this move + // assignment operator throwing an exception when it shouldn't. + ConfigurePreset& operator=(ConfigurePreset&& /*other*/) = delete; +#endif + + std::string Generator; + std::string Architecture; + cm::optional ArchitectureStrategy; + std::string Toolset; + cm::optional ToolsetStrategy; + std::string ToolchainFile; + std::string BinaryDir; + std::string InstallDir; + + std::map> CacheVariables; + + cm::optional WarnDev; + cm::optional ErrorDev; + cm::optional WarnDeprecated; + cm::optional ErrorDeprecated; + cm::optional WarnUninitialized; + cm::optional WarnUnusedCli; + cm::optional WarnSystemVars; + + cm::optional DebugOutput; + cm::optional DebugTryCompile; + cm::optional DebugFind; + + ReadFileResult VisitPresetInherit(const Preset& parent) override; + ReadFileResult VisitPresetBeforeInherit() override; + ReadFileResult VisitPresetAfterInherit(int version) override; + }; + + class BuildPreset : public Preset + { + public: + BuildPreset() = default; + BuildPreset(BuildPreset&& /*other*/) = default; + BuildPreset(const BuildPreset& /*other*/) = default; + BuildPreset& operator=(const BuildPreset& /*other*/) = default; + ~BuildPreset() override = default; +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + BuildPreset& operator=(BuildPreset&& /*other*/) = default; +#else + // The move assignment operators for several STL classes did not become + // noexcept until C++17, which causes some tools to warn about this move + // assignment operator throwing an exception when it shouldn't. + BuildPreset& operator=(BuildPreset&& /*other*/) = delete; +#endif + + std::string ConfigurePreset; + cm::optional InheritConfigureEnvironment; + cm::optional Jobs; + std::vector Targets; + std::string Configuration; + cm::optional CleanFirst; + cm::optional Verbose; + std::vector NativeToolOptions; + + ReadFileResult VisitPresetInherit(const Preset& parent) override; + ReadFileResult VisitPresetAfterInherit(int /* version */) override; + }; + + class TestPreset : public Preset + { + public: + TestPreset() = default; + TestPreset(TestPreset&& /*other*/) = default; + TestPreset(const TestPreset& /*other*/) = default; + TestPreset& operator=(const TestPreset& /*other*/) = default; + ~TestPreset() override = default; +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + TestPreset& operator=(TestPreset&& /*other*/) = default; +#else + // The move assignment operators for several STL classes did not become + // noexcept until C++17, which causes some tools to warn about this move + // assignment operator throwing an exception when it shouldn't. + TestPreset& operator=(TestPreset&& /*other*/) = delete; +#endif + + struct OutputOptions + { + enum class VerbosityEnum + { + Default, + Verbose, + Extra + }; + + cm::optional ShortProgress; + cm::optional Verbosity; + cm::optional Debug; + cm::optional OutputOnFailure; + cm::optional Quiet; + std::string OutputLogFile; + cm::optional LabelSummary; + cm::optional SubprojectSummary; + cm::optional MaxPassedTestOutputSize; + cm::optional MaxFailedTestOutputSize; + cm::optional MaxTestNameWidth; + }; + + struct IncludeOptions + { + struct IndexOptions + { + cm::optional Start; + cm::optional End; + cm::optional Stride; + std::vector SpecificTests; + + std::string IndexFile; + }; + + std::string Name; + std::string Label; + cm::optional Index; + cm::optional UseUnion; + }; + + struct ExcludeOptions + { + struct FixturesOptions + { + std::string Any; + std::string Setup; + std::string Cleanup; + }; + + std::string Name; + std::string Label; + cm::optional Fixtures; + }; + + struct FilterOptions + { + cm::optional Include; + cm::optional Exclude; + }; + + struct ExecutionOptions + { + enum class ShowOnlyEnum + { + Human, + JsonV1 + }; + + struct RepeatOptions + { + enum class ModeEnum + { + UntilFail, + UntilPass, + AfterTimeout + }; + + ModeEnum Mode; + int Count; + }; + + enum class NoTestsActionEnum + { + Default, + Error, + Ignore + }; + + cm::optional StopOnFailure; + cm::optional EnableFailover; + cm::optional Jobs; + std::string ResourceSpecFile; + cm::optional TestLoad; + cm::optional ShowOnly; + + cm::optional Repeat; + cm::optional InteractiveDebugging; + cm::optional ScheduleRandom; + cm::optional Timeout; + cm::optional NoTestsAction; + }; + + std::string ConfigurePreset; + cm::optional InheritConfigureEnvironment; + std::string Configuration; + std::vector OverwriteConfigurationFile; + cm::optional Output; + cm::optional Filter; + cm::optional Execution; + + ReadFileResult VisitPresetInherit(const Preset& parent) override; + ReadFileResult VisitPresetAfterInherit(int /* version */) override; + }; + + template + class PresetPair + { + public: + T Unexpanded; + cm::optional Expanded; + }; + + std::map> ConfigurePresets; + std::map> BuildPresets; + std::map> TestPresets; + + std::vector ConfigurePresetOrder; + std::vector BuildPresetOrder; + std::vector TestPresetOrder; + + std::string SourceDir; + int Version; + int UserVersion; + + int GetVersion(const Preset& preset) const + { + return preset.User ? this->UserVersion : this->Version; + } + + static std::string GetFilename(const std::string& sourceDir); + static std::string GetUserFilename(const std::string& sourceDir); + ReadFileResult ReadProjectPresets(const std::string& sourceDir, + bool allowNoFiles = false); + static const char* ResultToString(ReadFileResult result); + + std::string GetGeneratorForPreset(const std::string& presetName) const + { + auto configurePresetName = presetName; + + auto buildPresetIterator = this->BuildPresets.find(presetName); + if (buildPresetIterator != this->BuildPresets.end()) { + configurePresetName = + buildPresetIterator->second.Unexpanded.ConfigurePreset; + } else { + auto testPresetIterator = this->TestPresets.find(presetName); + if (testPresetIterator != this->TestPresets.end()) { + configurePresetName = + testPresetIterator->second.Unexpanded.ConfigurePreset; + } + } + + auto configurePresetIterator = + this->ConfigurePresets.find(configurePresetName); + if (configurePresetIterator != this->ConfigurePresets.end()) { + return configurePresetIterator->second.Unexpanded.Generator; + } + + // This should only happen if the preset is hidden + // or (for build or test presets) if ConfigurePreset is invalid. + return ""; + } + + static void PrintPresets( + const std::vector& presets); + void PrintConfigurePresetList() const; + void PrintConfigurePresetList( + const std::function& filter) const; + void PrintBuildPresetList() const; + void PrintTestPresetList() const; + void PrintAllPresets() const; + +private: + ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles); + ReadFileResult ReadJSONFile(const std::string& filename, bool user); + void ClearPresets(); +}; diff --git a/Source/cmCMakePresetsGraphInternal.h b/Source/cmCMakePresetsGraphInternal.h new file mode 100644 index 0000000..b2e6791 --- /dev/null +++ b/Source/cmCMakePresetsGraphInternal.h @@ -0,0 +1,112 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include + +#include "cmCMakePresetsGraph.h" + +#define CHECK_OK(expr) \ + do { \ + auto _result = expr; \ + if (_result != ReadFileResult::READ_OK) \ + return _result; \ + } while (false) + +namespace cmCMakePresetsGraphInternal { +enum class ExpandMacroResult +{ + Ok, + Ignore, + Error, +}; + +using MacroExpander = std::function; +} + +class cmCMakePresetsGraph::Condition +{ +public: + virtual ~Condition() = default; + + virtual bool Evaluate( + const std::vector& expanders, + int version, cm::optional& out) const = 0; + virtual bool IsNull() const { return false; } +}; + +namespace cmCMakePresetsGraphInternal { + +class NullCondition : public cmCMakePresetsGraph::Condition +{ + bool Evaluate(const std::vector& /*expanders*/, + int /*version*/, cm::optional& out) const override + { + out = true; + return true; + } + + bool IsNull() const override { return true; } +}; + +class ConstCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector& /*expanders*/, + int /*version*/, cm::optional& out) const override + { + out = this->Value; + return true; + } + + bool Value; +}; + +class EqualsCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector& expanders, int version, + cm::optional& out) const override; + + std::string Lhs; + std::string Rhs; +}; + +class InListCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector& expanders, int version, + cm::optional& out) const override; + + std::string String; + std::vector List; +}; + +class MatchesCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector& expanders, int version, + cm::optional& out) const override; + + std::string String; + std::string Regex; +}; + +class AnyAllOfCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector& expanders, int version, + cm::optional& out) const override; + + std::vector> Conditions; + bool StopValue; +}; + +class NotCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector& expanders, int version, + cm::optional& out) const override; + + std::unique_ptr SubCondition; +}; +} diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx new file mode 100644 index 0000000..8a9e6a0 --- /dev/null +++ b/Source/cmCMakePresetsGraphReadJSON.cxx @@ -0,0 +1,1034 @@ +/* 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 "cmCMakePresetsGraph.h" +#include "cmCMakePresetsGraphInternal.h" +#include "cmJSONHelpers.h" +#include "cmVersion.h" + +namespace { +using ReadFileResult = cmCMakePresetsGraph::ReadFileResult; +using CacheVariable = cmCMakePresetsGraph::CacheVariable; +using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset; +using BuildPreset = cmCMakePresetsGraph::BuildPreset; +using TestPreset = cmCMakePresetsGraph::TestPreset; +using ArchToolsetStrategy = cmCMakePresetsGraph::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, &cmCMakePresetsGraphInternal::ConstCondition::Value, + ConditionBoolHelper, true); + +auto const EqualsConditionHelper = + cmJSONObjectHelper(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind("type"_s, nullptr, ConditionStringHelper, true) + .Bind("lhs"_s, &cmCMakePresetsGraphInternal::EqualsCondition::Lhs, + ConditionStringHelper, true) + .Bind("rhs"_s, &cmCMakePresetsGraphInternal::EqualsCondition::Rhs, + ConditionStringHelper, true); + +auto const InListConditionHelper = + cmJSONObjectHelper(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind("type"_s, nullptr, ConditionStringHelper, true) + .Bind("string"_s, &cmCMakePresetsGraphInternal::InListCondition::String, + ConditionStringHelper, true) + .Bind("list"_s, &cmCMakePresetsGraphInternal::InListCondition::List, + ConditionStringListHelper, true); + +auto const MatchesConditionHelper = + cmJSONObjectHelper(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind("type"_s, nullptr, ConditionStringHelper, true) + .Bind("string"_s, &cmCMakePresetsGraphInternal::MatchesCondition::String, + ConditionStringHelper, true) + .Bind("regex"_s, &cmCMakePresetsGraphInternal::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, + &cmCMakePresetsGraphInternal::AnyAllOfCondition::Conditions, + ListConditionVectorHelper); + +auto const NotConditionHelper = + cmJSONObjectHelper(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind("type"_s, nullptr, ConditionStringHelper, true) + .Bind("condition"_s, + &cmCMakePresetsGraphInternal::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); +} + +cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::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; +} diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 647dd87..a1e920e 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -38,7 +38,7 @@ # include // IWYU pragma: keep #endif -#include "cmCMakePresetsFile.h" +#include "cmCMakePresetsGraph.h" #include "cmCTestBuildAndTestHandler.h" #include "cmCTestBuildHandler.h" #include "cmCTestConfigureHandler.h" @@ -2327,12 +2327,12 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName, { const auto workingDirectory = cmSystemTools::GetCurrentWorkingDirectory(); - cmCMakePresetsFile settingsFile; + cmCMakePresetsGraph settingsFile; auto result = settingsFile.ReadProjectPresets(workingDirectory); - if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) { - cmSystemTools::Error(cmStrCat("Could not read presets from ", - workingDirectory, ": ", - cmCMakePresetsFile::ResultToString(result))); + if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) { + cmSystemTools::Error( + cmStrCat("Could not read presets from ", workingDirectory, ": ", + cmCMakePresetsGraph::ResultToString(result))); return false; } @@ -2422,15 +2422,15 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName, if (expandedPreset->Output->Verbosity) { const auto& verbosity = *expandedPreset->Output->Verbosity; switch (verbosity) { - case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum:: + case cmCMakePresetsGraph::TestPreset::OutputOptions::VerbosityEnum:: Extra: this->Impl->ExtraVerbose = true; CM_FALLTHROUGH; - case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum:: + case cmCMakePresetsGraph::TestPreset::OutputOptions::VerbosityEnum:: Verbose: this->Impl->Verbose = true; break; - case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum:: + case cmCMakePresetsGraph::TestPreset::OutputOptions::VerbosityEnum:: Default: default: // leave default settings @@ -2548,13 +2548,13 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName, this->Impl->ShowOnly = true; switch (*expandedPreset->Execution->ShowOnly) { - case cmCMakePresetsFile::TestPreset::ExecutionOptions::ShowOnlyEnum:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions::ShowOnlyEnum:: JsonV1: this->Impl->Quiet = true; this->Impl->OutputAsJson = true; this->Impl->OutputAsJsonVersion = 1; break; - case cmCMakePresetsFile::TestPreset::ExecutionOptions::ShowOnlyEnum:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions::ShowOnlyEnum:: Human: // intentional fallthrough (human is the default) default: @@ -2565,15 +2565,15 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName, if (expandedPreset->Execution->Repeat) { this->Impl->RepeatCount = expandedPreset->Execution->Repeat->Count; switch (expandedPreset->Execution->Repeat->Mode) { - case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions::RepeatOptions:: ModeEnum::UntilFail: this->Impl->RepeatMode = cmCTest::Repeat::UntilFail; break; - case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions::RepeatOptions:: ModeEnum::UntilPass: this->Impl->RepeatMode = cmCTest::Repeat::UntilPass; break; - case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions::RepeatOptions:: ModeEnum::AfterTimeout: this->Impl->RepeatMode = cmCTest::Repeat::AfterTimeout; break; @@ -2599,15 +2599,15 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName, if (expandedPreset->Execution->NoTestsAction) { switch (*expandedPreset->Execution->NoTestsAction) { - case cmCMakePresetsFile::TestPreset::ExecutionOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions:: NoTestsActionEnum::Error: this->Impl->NoTestsMode = cmCTest::NoTests::Error; break; - case cmCMakePresetsFile::TestPreset::ExecutionOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions:: NoTestsActionEnum::Ignore: this->Impl->NoTestsMode = cmCTest::NoTests::Ignore; break; - case cmCMakePresetsFile::TestPreset::ExecutionOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions:: NoTestsActionEnum::Default: break; default: diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 2a3ef9b..c708eb2 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -29,7 +29,7 @@ #include "cm_sys_stat.h" #include "cmCMakePath.h" -#include "cmCMakePresetsFile.h" +#include "cmCMakePresetsGraph.h" #include "cmCommandLineArgument.h" #include "cmCommands.h" #include "cmDocumentation.h" @@ -1239,43 +1239,43 @@ void cmake::SetArgs(const std::vector& args) #if !defined(CMAKE_BOOTSTRAP) if (listPresets != ListPresets::None || !presetName.empty()) { - cmCMakePresetsFile settingsFile; - auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory()); - if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) { + cmCMakePresetsGraph presetsGraph; + auto result = presetsGraph.ReadProjectPresets(this->GetHomeDirectory()); + if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) { cmSystemTools::Error( cmStrCat("Could not read presets from ", this->GetHomeDirectory(), - ": ", cmCMakePresetsFile::ResultToString(result))); + ": ", cmCMakePresetsGraph::ResultToString(result))); return; } if (listPresets != ListPresets::None) { if (listPresets == ListPresets::Configure) { - this->PrintPresetList(settingsFile); + this->PrintPresetList(presetsGraph); } else if (listPresets == ListPresets::Build) { - settingsFile.PrintBuildPresetList(); + presetsGraph.PrintBuildPresetList(); } else if (listPresets == ListPresets::Test) { - settingsFile.PrintTestPresetList(); + presetsGraph.PrintTestPresetList(); } else if (listPresets == ListPresets::All) { - settingsFile.PrintAllPresets(); + presetsGraph.PrintAllPresets(); } this->SetWorkingMode(WorkingMode::HELP_MODE); return; } - auto preset = settingsFile.ConfigurePresets.find(presetName); - if (preset == settingsFile.ConfigurePresets.end()) { + auto preset = presetsGraph.ConfigurePresets.find(presetName); + if (preset == presetsGraph.ConfigurePresets.end()) { cmSystemTools::Error(cmStrCat("No such preset in ", this->GetHomeDirectory(), ": \"", presetName, '"')); - this->PrintPresetList(settingsFile); + this->PrintPresetList(presetsGraph); return; } if (preset->second.Unexpanded.Hidden) { cmSystemTools::Error(cmStrCat("Cannot use hidden preset in ", this->GetHomeDirectory(), ": \"", presetName, '"')); - this->PrintPresetList(settingsFile); + this->PrintPresetList(presetsGraph); return; } auto const& expandedPreset = preset->second.Expanded; @@ -1319,14 +1319,14 @@ void cmake::SetArgs(const std::vector& args) if (!expandedPreset->ArchitectureStrategy || expandedPreset->ArchitectureStrategy == - cmCMakePresetsFile::ArchToolsetStrategy::Set) { + cmCMakePresetsGraph::ArchToolsetStrategy::Set) { if (!this->GeneratorPlatformSet) { this->SetGeneratorPlatform(expandedPreset->Architecture); } } if (!expandedPreset->ToolsetStrategy || expandedPreset->ToolsetStrategy == - cmCMakePresetsFile::ArchToolsetStrategy::Set) { + cmCMakePresetsGraph::ArchToolsetStrategy::Set) { if (!this->GeneratorToolsetSet) { this->SetGeneratorToolset(expandedPreset->Toolset); } @@ -1707,12 +1707,12 @@ bool cmake::CreateAndSetGlobalGenerator(const std::string& name, } #ifndef CMAKE_BOOTSTRAP -void cmake::PrintPresetList(const cmCMakePresetsFile& file) const +void cmake::PrintPresetList(const cmCMakePresetsGraph& graph) const { std::vector generators; this->GetRegisteredGenerators(generators, false); auto filter = - [&generators](const cmCMakePresetsFile::ConfigurePreset& preset) -> bool { + [&generators](const cmCMakePresetsGraph::ConfigurePreset& preset) -> bool { if (preset.Generator.empty()) { return true; } @@ -1723,7 +1723,7 @@ void cmake::PrintPresetList(const cmCMakePresetsFile& file) const return it != generators.end(); }; - file.PrintConfigurePresetList(filter); + graph.PrintConfigurePresetList(filter); } #endif @@ -3230,12 +3230,12 @@ int cmake::Build(int jobs, std::string dir, std::vector targets, this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory()); this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory()); - cmCMakePresetsFile settingsFile; + cmCMakePresetsGraph settingsFile; auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory()); - if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) { + if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) { cmSystemTools::Error( cmStrCat("Could not read presets from ", this->GetHomeDirectory(), - ": ", cmCMakePresetsFile::ResultToString(result))); + ": ", cmCMakePresetsGraph::ResultToString(result))); return 1; } diff --git a/Source/cmake.h b/Source/cmake.h index a356e65..b13cc96 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -31,7 +31,7 @@ # include -# include "cmCMakePresetsFile.h" +# include "cmCMakePresetsGraph.h" #endif class cmExternalMakefileProjectGeneratorFactory; @@ -248,7 +248,7 @@ public: #ifndef CMAKE_BOOTSTRAP //! Print list of configure presets - void PrintPresetList(const cmCMakePresetsFile& file) const; + void PrintPresetList(const cmCMakePresetsGraph& graph) const; #endif //! Return the global generator assigned to this instance of cmake @@ -691,7 +691,7 @@ private: std::string GraphVizFile; InstalledFilesMap InstalledFiles; #ifndef CMAKE_BOOTSTRAP - std::map> + std::map> UnprocessedPresetVariables; std::map> UnprocessedPresetEnvironment; -- cgit v0.12 From 84d440caace3f65ef6ddd197098f8d83c0ecef70 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Wed, 5 Jan 2022 13:57:48 -0500 Subject: Refactor: Split JSON processing into configure, build, and test presets Split up the file so that it won't be too big on some systems. --- Source/CMakeLists.txt | 3 + Source/cmCMakePresetsGraphInternal.h | 51 ++ Source/cmCMakePresetsGraphReadJSON.cxx | 703 +++------------------ Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx | 75 +++ ...cmCMakePresetsGraphReadJSONConfigurePresets.cxx | 228 +++++++ Source/cmCMakePresetsGraphReadJSONTestPresets.cxx | 360 +++++++++++ 6 files changed, 821 insertions(+), 599 deletions(-) create mode 100644 Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx create mode 100644 Source/cmCMakePresetsGraphReadJSONConfigurePresets.cxx create mode 100644 Source/cmCMakePresetsGraphReadJSONTestPresets.cxx diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e0c5ed9..1933b6a 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -165,6 +165,9 @@ set(SRCS cmCMakePresetsGraph.h cmCMakePresetsGraphInternal.h cmCMakePresetsGraphReadJSON.cxx + cmCMakePresetsGraphReadJSONBuildPresets.cxx + cmCMakePresetsGraphReadJSONConfigurePresets.cxx + cmCMakePresetsGraphReadJSONTestPresets.cxx cmCommandArgumentParserHelper.cxx cmCommonTargetGenerator.cxx cmCommonTargetGenerator.h diff --git a/Source/cmCMakePresetsGraphInternal.h b/Source/cmCMakePresetsGraphInternal.h index b2e6791..f7c7349 100644 --- a/Source/cmCMakePresetsGraphInternal.h +++ b/Source/cmCMakePresetsGraphInternal.h @@ -1,8 +1,13 @@ /* 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 "cmCMakePresetsGraph.h" +#include "cmJSONHelpers.h" #define CHECK_OK(expr) \ do { \ @@ -109,4 +114,50 @@ public: std::unique_ptr SubCondition; }; + +cmCMakePresetsGraph::ReadFileResult PresetStringHelper( + std::string& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetVectorStringHelper( + std::vector& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetBoolHelper(bool& out, + const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetOptionalBoolHelper( + cm::optional& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetIntHelper(int& out, + const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetOptionalIntHelper( + cm::optional& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetVectorIntHelper( + std::vector& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult ConfigurePresetsHelper( + std::vector& out, + const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult BuildPresetsHelper( + std::vector& out, + const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult TestPresetsHelper( + std::vector& out, const Json::Value* value); + +cmJSONHelper VendorHelper( + cmCMakePresetsGraph::ReadFileResult error); + +cmCMakePresetsGraph::ReadFileResult PresetConditionHelper( + std::shared_ptr& out, + const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetVectorOneOrMoreStringHelper( + std::vector& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper( + std::map>& out, + const Json::Value* value); } diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx index 8a9e6a0..3e002fe 100644 --- a/Source/cmCMakePresetsGraphReadJSON.cxx +++ b/Source/cmCMakePresetsGraphReadJSON.cxx @@ -219,16 +219,6 @@ ReadFileResult ConditionHelper( 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) @@ -242,20 +232,18 @@ ReadFileResult SubConditionHelper( return result; } -cmJSONHelper VendorHelper(ReadFileResult error) +ReadFileResult EnvironmentHelper(cm::optional& out, + const Json::Value* value) { - return [error](std::nullptr_t& /*out*/, - const Json::Value* value) -> ReadFileResult { - if (!value) { - return ReadFileResult::READ_OK; - } - - if (!value->isObject()) { - return error; - } - + 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 VersionIntHelper = cmJSONIntHelper( @@ -269,635 +257,152 @@ auto const RootVersionHelper = 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; - } +auto const CMakeVersionUIntHelper = cmJSONUIntHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION); - if (value->isBool()) { - out = value->asBool() ? "TRUE" : "FALSE"; - return ReadFileResult::READ_OK; - } +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); - return VariableStringHelper(out, value); +auto const RootPresetsHelper = + cmJSONObjectHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false) + .Bind("version"_s, nullptr, VersionHelper) + .Bind("configurePresets"_s, &RootPresets::ConfigurePresets, + cmCMakePresetsGraphInternal::ConfigurePresetsHelper, false) + .Bind("buildPresets"_s, &RootPresets::BuildPresets, + cmCMakePresetsGraphInternal::BuildPresetsHelper, false) + .Bind("testPresets"_s, &RootPresets::TestPresets, + cmCMakePresetsGraphInternal::TestPresetsHelper, false) + .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired, + CMakeVersionHelper, false) + .Bind( + "vendor"_s, nullptr, + cmCMakePresetsGraphInternal::VendorHelper(ReadFileResult::INVALID_ROOT), + false); } -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) +namespace cmCMakePresetsGraphInternal { +cmCMakePresetsGraph::ReadFileResult PresetStringHelper( + std::string& 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); + static auto const helper = cmJSONStringHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); -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; + return helper(out, value); } -auto const EnvironmentMapHelper = - cmJSONMapHelper, ReadFileResult>( +cmCMakePresetsGraph::ReadFileResult PresetVectorStringHelper( + std::vector& out, const Json::Value* value) +{ + static auto const helper = cmJSONVectorHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, - EnvironmentHelper); + cmCMakePresetsGraphInternal::PresetStringHelper); -auto const PresetVectorStringHelper = - cmJSONVectorHelper( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, - PresetStringHelper); + return helper(out, value); +} -ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector& out, - const Json::Value* value) +cmCMakePresetsGraph::ReadFileResult PresetBoolHelper(bool& 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; - } + static auto const helper = cmJSONBoolHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); - return PresetVectorStringHelper(out, value); + return helper(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) +cmCMakePresetsGraph::ReadFileResult PresetOptionalBoolHelper( + cm::optional& out, const Json::Value* value) { - if (!value) { - out = cm::nullopt; - return ReadFileResult::READ_OK; - } - - if (!value->isString()) { - return ReadFileResult::INVALID_PRESET; - } + static auto const helper = cmJSONOptionalHelper( + ReadFileResult::READ_OK, PresetBoolHelper); - 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; + return helper(out, value); } -std::function -ArchToolsetHelper( - std::string ConfigurePreset::*valueField, - cm::optional ConfigurePreset::*strategyField) +cmCMakePresetsGraph::ReadFileResult PresetIntHelper(int& out, + const Json::Value* value) { - 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); - } + static auto const helper = cmJSONIntHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); - return ReadFileResult::INVALID_PRESET; - }; + return helper(out, value); } -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) +cmCMakePresetsGraph::ReadFileResult PresetOptionalIntHelper( + cm::optional& out, const Json::Value* value) { - if (!value) { - out = TestPreset::OutputOptions::VerbosityEnum::Default; - return ReadFileResult::READ_OK; - } - - if (!value->isString()) { - return ReadFileResult::INVALID_PRESET; - } + static auto const helper = cmJSONOptionalHelper( + ReadFileResult::READ_OK, PresetIntHelper); - 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; + return helper(out, value); } -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) +cmCMakePresetsGraph::ReadFileResult PresetVectorIntHelper( + std::vector& 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); - } + static auto const helper = cmJSONVectorHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper); - return ReadFileResult::INVALID_PRESET; + return helper(out, value); } -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) +cmJSONHelper VendorHelper(ReadFileResult error) { - if (!value || !value->isString()) { - return ReadFileResult::INVALID_PRESET; - } + return [error](std::nullptr_t& /*out*/, + const Json::Value* value) -> ReadFileResult { + if (!value) { + return ReadFileResult::READ_OK; + } - if (value->asString() == "human") { - out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human; - return ReadFileResult::READ_OK; - } + if (!value->isObject()) { + return error; + } - 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, +ReadFileResult PresetConditionHelper( + std::shared_ptr& 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; + std::unique_ptr ptr; + auto result = ConditionHelper(ptr, value); + out = std::move(ptr); + return result; } -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) +ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector& out, + const Json::Value* value) { + out.clear(); 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; + if (value->isString()) { + out.push_back(value->asString()); return ReadFileResult::READ_OK; } - return ReadFileResult::INVALID_PRESET; + return PresetVectorStringHelper(out, value); } -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); +cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper( + std::map>& out, + const Json::Value* value) +{ + static auto const helper = + cmJSONMapHelper, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, + EnvironmentHelper); -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); + return helper(out, value); +} } cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( diff --git a/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx b/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx new file mode 100644 index 0000000..ef605d1 --- /dev/null +++ b/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx @@ -0,0 +1,75 @@ +/* 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 "cmCMakePresetsGraph.h" +#include "cmCMakePresetsGraphInternal.h" +#include "cmJSONHelpers.h" + +namespace { +using ReadFileResult = cmCMakePresetsGraph::ReadFileResult; +using BuildPreset = cmCMakePresetsGraph::BuildPreset; + +auto const BuildPresetHelper = + cmJSONObjectHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("name"_s, &BuildPreset::Name, + cmCMakePresetsGraphInternal::PresetStringHelper) + .Bind("inherits"_s, &BuildPreset::Inherits, + cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper, + false) + .Bind("hidden"_s, &BuildPreset::Hidden, + cmCMakePresetsGraphInternal::PresetBoolHelper, false) + .Bind("vendor"_s, nullptr, + cmCMakePresetsGraphInternal::VendorHelper( + ReadFileResult::INVALID_PRESET), + false) + .Bind("displayName"_s, &BuildPreset::DisplayName, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("description"_s, &BuildPreset::Description, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("environment"_s, &BuildPreset::Environment, + cmCMakePresetsGraphInternal::EnvironmentMapHelper, false) + .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("inheritConfigureEnvironment"_s, + &BuildPreset::InheritConfigureEnvironment, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("jobs"_s, &BuildPreset::Jobs, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("targets"_s, &BuildPreset::Targets, + cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper, + false) + .Bind("configuration"_s, &BuildPreset::Configuration, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("verbose"_s, &BuildPreset::Verbose, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions, + cmCMakePresetsGraphInternal::PresetVectorStringHelper, false) + .Bind("condition"_s, &BuildPreset::ConditionEvaluator, + cmCMakePresetsGraphInternal::PresetConditionHelper, false); +} + +namespace cmCMakePresetsGraphInternal { +ReadFileResult BuildPresetsHelper(std::vector& out, + const Json::Value* value) +{ + static auto const helper = cmJSONVectorHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, + BuildPresetHelper); + + return helper(out, value); +} +} diff --git a/Source/cmCMakePresetsGraphReadJSONConfigurePresets.cxx b/Source/cmCMakePresetsGraphReadJSONConfigurePresets.cxx new file mode 100644 index 0000000..0f44546 --- /dev/null +++ b/Source/cmCMakePresetsGraphReadJSONConfigurePresets.cxx @@ -0,0 +1,228 @@ +/* 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 "cmCMakePresetsGraph.h" +#include "cmCMakePresetsGraphInternal.h" +#include "cmJSONHelpers.h" + +namespace { +using ReadFileResult = cmCMakePresetsGraph::ReadFileResult; +using CacheVariable = cmCMakePresetsGraph::CacheVariable; +using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset; +using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy; + +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, + cmCMakePresetsGraphInternal::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 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 PresetWarningsHelper = + cmJSONObjectHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("dev"_s, &ConfigurePreset::WarnDev, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false); + +auto const PresetErrorsHelper = + cmJSONObjectHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("dev"_s, &ConfigurePreset::ErrorDev, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false); + +auto const PresetDebugHelper = + cmJSONObjectHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("output"_s, &ConfigurePreset::DebugOutput, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("find"_s, &ConfigurePreset::DebugFind, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false); + +auto const ConfigurePresetHelper = + cmJSONObjectHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("name"_s, &ConfigurePreset::Name, + cmCMakePresetsGraphInternal::PresetStringHelper) + .Bind("inherits"_s, &ConfigurePreset::Inherits, + cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper, + false) + .Bind("hidden"_s, &ConfigurePreset::Hidden, + cmCMakePresetsGraphInternal::PresetBoolHelper, false) + .Bind("vendor"_s, nullptr, + cmCMakePresetsGraphInternal::VendorHelper( + ReadFileResult::INVALID_PRESET), + false) + .Bind("displayName"_s, &ConfigurePreset::DisplayName, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("description"_s, &ConfigurePreset::Description, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("generator"_s, &ConfigurePreset::Generator, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("architecture"_s, ArchitectureHelper, false) + .Bind("toolset"_s, ToolsetHelper, false) + .Bind("toolchainFile"_s, &ConfigurePreset::ToolchainFile, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("installDir"_s, &ConfigurePreset::InstallDir, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("cmakeExecutable"_s, nullptr, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables, + VariablesHelper, false) + .Bind("environment"_s, &ConfigurePreset::Environment, + cmCMakePresetsGraphInternal::EnvironmentMapHelper, false) + .Bind("warnings"_s, PresetWarningsHelper, false) + .Bind("errors"_s, PresetErrorsHelper, false) + .Bind("debug"_s, PresetDebugHelper, false) + .Bind("condition"_s, &ConfigurePreset::ConditionEvaluator, + cmCMakePresetsGraphInternal::PresetConditionHelper, false); +} + +namespace cmCMakePresetsGraphInternal { +ReadFileResult ConfigurePresetsHelper(std::vector& out, + const Json::Value* value) +{ + static auto const helper = + cmJSONVectorHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, + ConfigurePresetHelper); + + return helper(out, value); +} +} diff --git a/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx new file mode 100644 index 0000000..4d6474a --- /dev/null +++ b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx @@ -0,0 +1,360 @@ +/* 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 "cmCMakePresetsGraph.h" +#include "cmCMakePresetsGraphInternal.h" +#include "cmJSONHelpers.h" + +namespace { +using ReadFileResult = cmCMakePresetsGraph::ReadFileResult; +using TestPreset = cmCMakePresetsGraph::TestPreset; + +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, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity, + TestPresetOptionalOutputVerbosityHelper, false) + .Bind("debug"_s, &TestPreset::OutputOptions::Debug, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("subprojectSummary"_s, + &TestPreset::OutputOptions::SubprojectSummary, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("maxPassedTestOutputSize"_s, + &TestPreset::OutputOptions::MaxPassedTestOutputSize, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("maxFailedTestOutputSize"_s, + &TestPreset::OutputOptions::MaxFailedTestOutputSize, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)); + +auto const TestPresetOptionalFilterIncludeIndexObjectHelper = + cmJSONOptionalHelper( + ReadFileResult::READ_OK, + cmJSONObjectHelper(ReadFileResult::READ_OK, + ReadFileResult::INVALID_PRESET) + .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("specificTests"_s, + &TestPreset::IncludeOptions::IndexOptions::SpecificTests, + cmCMakePresetsGraphInternal::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, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("label"_s, &TestPreset::IncludeOptions::Label, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("index"_s, &TestPreset::IncludeOptions::Index, + TestPresetOptionalFilterIncludeIndexHelper, false) + .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)); + +auto const TestPresetOptionalFilterExcludeFixturesHelper = + cmJSONOptionalHelper( + ReadFileResult::READ_OK, + cmJSONObjectHelper(ReadFileResult::READ_OK, + ReadFileResult::INVALID_PRESET) + .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup, + cmCMakePresetsGraphInternal::PresetStringHelper, false)); + +auto const TestPresetOptionalFilterExcludeHelper = + cmJSONOptionalHelper( + ReadFileResult::READ_OK, + cmJSONObjectHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) + .Bind("name"_s, &TestPreset::ExcludeOptions::Name, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("label"_s, &TestPreset::ExcludeOptions::Label, + cmCMakePresetsGraphInternal::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, + cmCMakePresetsGraphInternal::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, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("resourceSpecFile"_s, + &TestPreset::ExecutionOptions::ResourceSpecFile, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly, + TestPresetOptionalExecutionShowOnlyHelper, false) + .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat, + TestPresetOptionalExecutionRepeatHelper, false) + .Bind("interactiveDebugging"_s, + &TestPreset::ExecutionOptions::InteractiveDebugging, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout, + cmCMakePresetsGraphInternal::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, + cmCMakePresetsGraphInternal::PresetStringHelper) + .Bind("inherits"_s, &TestPreset::Inherits, + cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper, + false) + .Bind("hidden"_s, &TestPreset::Hidden, + cmCMakePresetsGraphInternal::PresetBoolHelper, false) + .Bind("vendor"_s, nullptr, + cmCMakePresetsGraphInternal::VendorHelper( + ReadFileResult::INVALID_PRESET), + false) + .Bind("displayName"_s, &TestPreset::DisplayName, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("description"_s, &TestPreset::Description, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("environment"_s, &TestPreset::Environment, + cmCMakePresetsGraphInternal::EnvironmentMapHelper, false) + .Bind("configurePreset"_s, &TestPreset::ConfigurePreset, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("inheritConfigureEnvironment"_s, + &TestPreset::InheritConfigureEnvironment, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("configuration"_s, &TestPreset::Configuration, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("overwriteConfigurationFile"_s, + &TestPreset::OverwriteConfigurationFile, + cmCMakePresetsGraphInternal::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, + cmCMakePresetsGraphInternal::PresetConditionHelper, false); +} + +namespace cmCMakePresetsGraphInternal { +cmCMakePresetsGraph::ReadFileResult TestPresetsHelper( + std::vector& out, const Json::Value* value) +{ + static auto const helper = cmJSONVectorHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, + TestPresetHelper); + + return helper(out, value); +} +} -- cgit v0.12 From a239f23a987a063852c8f29040ef4eaeaebf3b9c Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Tue, 21 Dec 2021 17:12:51 -0500 Subject: Refactor: Generalize file graph in CMakePresets Before this refactoring, presets had a simple flag that marked them as "user" or "not user", and checking the file graph of two files was as simple as checking this flag. This only allowed for two files in the graph. Generalize the code to allow for arbitrarily many files in the graph. --- Source/cmCMakePresetsGraph.cxx | 36 +++++++----- Source/cmCMakePresetsGraph.h | 37 ++++++++++-- Source/cmCMakePresetsGraphReadJSON.cxx | 66 +++++++++++++++++++--- .../CMakePresets/UserInheritance-stderr.txt | 2 +- 4 files changed, 112 insertions(+), 29 deletions(-) diff --git a/Source/cmCMakePresetsGraph.cxx b/Source/cmCMakePresetsGraph.cxx index ebc243b..a8aad12 100644 --- a/Source/cmCMakePresetsGraph.cxx +++ b/Source/cmCMakePresetsGraph.cxx @@ -3,6 +3,7 @@ #include "cmCMakePresetsGraph.h" #include +#include #include #include #include @@ -106,8 +107,8 @@ ReadFileResult VisitPreset( } auto& parentPreset = parent->second.Unexpanded; - if (!preset.User && parentPreset.User) { - return ReadFileResult::USER_PRESET_INHERITANCE; + if (!preset.OriginFile->ReachableFiles.count(parentPreset.OriginFile)) { + return ReadFileResult::PRESET_UNREACHABLE_FROM_FILE; } auto result = VisitPreset(parentPreset, presets, cycleStatus, graph); @@ -876,23 +877,28 @@ cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles) { bool haveOneFile = false; + File* file; std::string filename = GetUserFilename(this->SourceDir); + std::vector inProgressFiles; if (cmSystemTools::FileExists(filename)) { - auto result = this->ReadJSONFile(filename, true); + auto result = this->ReadJSONFile(filename, RootType::User, + ReadReason::Root, inProgressFiles, file); if (result != ReadFileResult::READ_OK) { return result; } haveOneFile = true; - } - - filename = GetFilename(this->SourceDir); - if (cmSystemTools::FileExists(filename)) { - auto result = this->ReadJSONFile(filename, false); - if (result != ReadFileResult::READ_OK) { - return result; + } else { + filename = GetFilename(this->SourceDir); + if (cmSystemTools::FileExists(filename)) { + auto result = this->ReadJSONFile( + filename, RootType::Project, ReadReason::Root, inProgressFiles, file); + if (result != ReadFileResult::READ_OK) { + return result; + } + haveOneFile = true; } - haveOneFile = true; } + assert(inProgressFiles.empty()); if (!haveOneFile) { return allowNoFiles ? ReadFileResult::READ_OK @@ -983,8 +989,8 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result) return "Duplicate presets"; case ReadFileResult::CYCLIC_PRESET_INHERITANCE: return "Cyclic preset inheritance"; - case ReadFileResult::USER_PRESET_INHERITANCE: - return "Project preset inherits from user preset"; + case ReadFileResult::PRESET_UNREACHABLE_FROM_FILE: + return "Inherited preset is unreachable from preset's file"; case ReadFileResult::INVALID_MACRO_EXPANSION: return "Invalid macro expansion"; case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED: @@ -1002,6 +1008,8 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result) case ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED: return "File version must be 3 or higher for toolchainFile preset " "support."; + case ReadFileResult::CYCLIC_INCLUDE: + return "Cyclic include among preset files"; } return "Unknown error"; @@ -1016,6 +1024,8 @@ void cmCMakePresetsGraph::ClearPresets() this->ConfigurePresetOrder.clear(); this->BuildPresetOrder.clear(); this->TestPresetOrder.clear(); + + this->Files.clear(); } void cmCMakePresetsGraph::PrintPresets( diff --git a/Source/cmCMakePresetsGraph.h b/Source/cmCMakePresetsGraph.h index 937b281..c27a611 100644 --- a/Source/cmCMakePresetsGraph.h +++ b/Source/cmCMakePresetsGraph.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -32,7 +33,7 @@ public: INVALID_VARIABLE, DUPLICATE_PRESETS, CYCLIC_PRESET_INHERITANCE, - USER_PRESET_INHERITANCE, + PRESET_UNREACHABLE_FROM_FILE, INVALID_MACRO_EXPANSION, BUILD_TEST_PRESETS_UNSUPPORTED, INVALID_CONFIGURE_PRESET, @@ -40,6 +41,7 @@ public: INVALID_CONDITION, CONDITION_UNSUPPORTED, TOOLCHAIN_FILE_UNSUPPORTED, + CYCLIC_INCLUDE, }; enum class ArchToolsetStrategy @@ -57,6 +59,15 @@ public: class Condition; + class File + { + public: + std::string Filename; + int Version; + + std::unordered_set ReachableFiles; + }; + class Preset { public: @@ -77,7 +88,7 @@ public: std::string Name; std::vector Inherits; bool Hidden; - bool User; + File* OriginFile; std::string DisplayName; std::string Description; @@ -321,12 +332,11 @@ public: std::vector TestPresetOrder; std::string SourceDir; - int Version; - int UserVersion; + std::vector> Files; int GetVersion(const Preset& preset) const { - return preset.User ? this->UserVersion : this->Version; + return preset.OriginFile->Version; } static std::string GetFilename(const std::string& sourceDir); @@ -372,7 +382,22 @@ public: void PrintAllPresets() const; private: + enum class RootType + { + Project, + User, + }; + + enum class ReadReason + { + Root, + Included, + }; + ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles); - ReadFileResult ReadJSONFile(const std::string& filename, bool user); + ReadFileResult ReadJSONFile(const std::string& filename, RootType rootType, + ReadReason readReason, + std::vector& inProgressFiles, + File*& file); void ClearPresets(); }; diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx index 3e002fe..aa5c9d4 100644 --- a/Source/cmCMakePresetsGraphReadJSON.cxx +++ b/Source/cmCMakePresetsGraphReadJSON.cxx @@ -1,8 +1,10 @@ /* 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 @@ -18,6 +20,8 @@ #include "cmCMakePresetsGraph.h" #include "cmCMakePresetsGraphInternal.h" #include "cmJSONHelpers.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" #include "cmVersion.h" namespace { @@ -406,8 +410,21 @@ cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper( } cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( - const std::string& filename, bool user) + const std::string& filename, RootType rootType, ReadReason readReason, + std::vector& inProgressFiles, File*& file) { + for (auto const& f : this->Files) { + if (cmSystemTools::SameFile(filename, f->Filename)) { + file = f.get(); + auto fileIt = + std::find(inProgressFiles.begin(), inProgressFiles.end(), file); + if (fileIt != inProgressFiles.end()) { + return cmCMakePresetsGraph::ReadFileResult::CYCLIC_INCLUDE; + } + return cmCMakePresetsGraph::ReadFileResult::READ_OK; + } + } + cmsys::ifstream fin(filename.c_str()); if (!fin) { return ReadFileResult::FILE_NOT_FOUND; @@ -430,11 +447,6 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( 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 && @@ -460,8 +472,16 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION; } + auto filePtr = cm::make_unique(); + file = filePtr.get(); + this->Files.emplace_back(std::move(filePtr)); + inProgressFiles.emplace_back(file); + file->Filename = filename; + file->Version = v; + file->ReachableFiles.insert(file); + for (auto& preset : presets.ConfigurePresets) { - preset.User = user; + preset.OriginFile = file; if (preset.Name.empty()) { return ReadFileResult::INVALID_PRESET; } @@ -494,7 +514,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( } for (auto& preset : presets.BuildPresets) { - preset.User = user; + preset.OriginFile = file; if (preset.Name.empty()) { return ReadFileResult::INVALID_PRESET; } @@ -515,7 +535,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( } for (auto& preset : presets.TestPresets) { - preset.User = user; + preset.OriginFile = file; if (preset.Name.empty()) { return ReadFileResult::INVALID_PRESET; } @@ -535,5 +555,33 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( this->TestPresetOrder.push_back(preset.Name); } + auto const includeFile = [this, &inProgressFiles, file]( + const std::string& include, RootType rootType2, + ReadReason readReason2) -> ReadFileResult { + ReadFileResult r; + File* includedFile; + if ((r = this->ReadJSONFile(include, rootType2, readReason2, + inProgressFiles, includedFile)) != + ReadFileResult::READ_OK) { + return r; + } + + file->ReachableFiles.insert(includedFile->ReachableFiles.begin(), + includedFile->ReachableFiles.end()); + return ReadFileResult::READ_OK; + }; + + if (rootType == RootType::User && readReason == ReadReason::Root) { + auto cmakePresetsFilename = GetFilename(this->SourceDir); + if (cmSystemTools::FileExists(cmakePresetsFilename)) { + if ((result = includeFile(cmakePresetsFilename, RootType::Project, + ReadReason::Root)) != + ReadFileResult::READ_OK) { + return result; + } + } + } + + inProgressFiles.pop_back(); return ReadFileResult::READ_OK; } diff --git a/Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt b/Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt index 213215a..5ad8b4b 100644 --- a/Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt +++ b/Tests/RunCMake/CMakePresets/UserInheritance-stderr.txt @@ -1,2 +1,2 @@ ^CMake Error: Could not read presets from [^ -]*/Tests/RunCMake/CMakePresets/UserInheritance: Project preset inherits from user preset$ +]*/Tests/RunCMake/CMakePresets/UserInheritance: Inherited preset is unreachable from preset's file$ -- cgit v0.12 From 26a5512c0f952333f089a08b0df84e3efa7fb063 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Wed, 22 Dec 2021 16:49:38 -0500 Subject: CMakePresets: Add include field Fixes: #21331 --- Help/manual/cmake-presets.7.rst | 28 ++++++++-- Help/manual/presets/example.json | 2 +- Help/manual/presets/schema.json | 22 ++++++++ Help/release/dev/cmake-presets-include.rst | 6 +++ Source/cmCMakePresetsGraph.cxx | 6 +++ Source/cmCMakePresetsGraph.h | 3 ++ Source/cmCMakePresetsGraphReadJSON.cxx | 60 ++++++++++++++++++++-- Tests/RunCMake/CMakePresets/Include-stdout.txt | 8 +++ Tests/RunCMake/CMakePresets/Include.json.in | 16 ++++++ Tests/RunCMake/CMakePresets/IncludeCommon.json.in | 8 +++ .../RunCMake/CMakePresets/IncludeCycle-result.txt | 1 + .../RunCMake/CMakePresets/IncludeCycle-stderr.txt | 2 + Tests/RunCMake/CMakePresets/IncludeCycle.json.in | 11 ++++ .../CMakePresets/IncludeCycle3Files-result.txt | 1 + .../CMakePresets/IncludeCycle3Files-stderr.txt | 2 + .../CMakePresets/IncludeCycle3Files.json.in | 6 +++ .../CMakePresets/IncludeCycle3Files2.json.in | 6 +++ .../CMakePresets/IncludeCycle3Files3.json.in | 6 +++ .../RunCMake/CMakePresets/IncludeCycleUser.json.in | 3 ++ .../CMakePresets/IncludeNotFound-result.txt | 1 + .../CMakePresets/IncludeNotFound-stderr.txt | 2 + .../RunCMake/CMakePresets/IncludeNotFound.json.in | 11 ++++ .../CMakePresets/IncludeOutsideProject-result.txt | 1 + .../CMakePresets/IncludeOutsideProject-stderr.txt | 2 + .../CMakePresets/IncludeOutsideProject.json.in | 11 ++++ .../CMakePresets/IncludeOutsideProjectInclude.json | 3 ++ .../IncludeOutsideProjectIntermediate.json.in | 6 +++ .../CMakePresets/IncludeOutsideProjectUser.json.in | 6 +++ Tests/RunCMake/CMakePresets/IncludeUser.json.in | 15 ++++++ .../CMakePresets/IncludeUserCommon.json.in | 8 +++ .../CMakePresets/IncludeUserOutsideProject.cmake | 0 .../IncludeUserOutsideProjectUser.json.in | 11 ++++ Tests/RunCMake/CMakePresets/IncludeV3-result.txt | 1 + Tests/RunCMake/CMakePresets/IncludeV3-stderr.txt | 2 + Tests/RunCMake/CMakePresets/IncludeV3.json.in | 4 ++ Tests/RunCMake/CMakePresets/IncludeV4V3-result.txt | 1 + Tests/RunCMake/CMakePresets/IncludeV4V3-stderr.txt | 2 + Tests/RunCMake/CMakePresets/IncludeV4V3.json.in | 6 +++ .../RunCMake/CMakePresets/IncludeV4V3Extra.json.in | 4 ++ Tests/RunCMake/CMakePresets/RunCMakeTest.cmake | 45 ++++++++++++++++ Tests/RunCMake/CMakePresets/check.cmake | 7 +++ .../CMakePresets/subdir/CMakePresets.json.in | 12 +++++ 42 files changed, 351 insertions(+), 7 deletions(-) create mode 100644 Help/release/dev/cmake-presets-include.rst create mode 100644 Tests/RunCMake/CMakePresets/Include-stdout.txt create mode 100644 Tests/RunCMake/CMakePresets/Include.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeCommon.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeCycle-result.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeCycle-stderr.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeCycle.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeCycle3Files-result.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeCycle3Files-stderr.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeCycle3Files.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeCycle3Files2.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeCycle3Files3.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeCycleUser.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeNotFound-result.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeNotFound-stderr.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeNotFound.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeOutsideProject-result.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeOutsideProject-stderr.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeOutsideProject.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeOutsideProjectInclude.json create mode 100644 Tests/RunCMake/CMakePresets/IncludeOutsideProjectIntermediate.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeOutsideProjectUser.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeUser.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeUserCommon.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeUserOutsideProject.cmake create mode 100644 Tests/RunCMake/CMakePresets/IncludeUserOutsideProjectUser.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeV3-result.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeV3-stderr.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeV3.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeV4V3-result.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeV4V3-stderr.txt create mode 100644 Tests/RunCMake/CMakePresets/IncludeV4V3.json.in create mode 100644 Tests/RunCMake/CMakePresets/IncludeV4V3Extra.json.in create mode 100644 Tests/RunCMake/CMakePresets/subdir/CMakePresets.json.in diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst index 74e9fae..474e1aa 100644 --- a/Help/manual/cmake-presets.7.rst +++ b/Help/manual/cmake-presets.7.rst @@ -12,9 +12,10 @@ Introduction One problem that CMake users often face is sharing settings with other people for common ways to configure a project. This may be done to support CI builds, -or for users who frequently use the same build. CMake supports two files, +or for users who frequently use the same build. CMake supports two main files, ``CMakePresets.json`` and ``CMakeUserPresets.json``, that allow users to -specify common configure options and share them with others. +specify common configure options and share them with others. CMake also +supports files included with the ``include`` field. ``CMakePresets.json`` and ``CMakeUserPresets.json`` live in the project's root directory. They both have exactly the same format, and both are optional @@ -26,6 +27,21 @@ builds. ``CMakePresets.json`` may be checked into a version control system, and is using Git, ``CMakePresets.json`` may be tracked, and ``CMakeUserPresets.json`` should be added to the ``.gitignore``. +``CMakePresets.json`` and ``CMakeUserPresets.json`` can include other files +with the ``include`` field in file version ``4`` and later. Files included by +these files can also include other files. If a preset file contains presets +that inherit from presets in another file, the file must include the other file +either directly or indirectly. Include cycles are not allowed among files (if +``a.json`` includes ``b.json``, ``b.json`` cannot include ``a.json``). However, +a file may be included multiple times from the same file or from different +files. If ``CMakePresets.json`` and ``CMakeUserPresets.json`` are both present, +``CMakeUserPresets.json`` implicitly includes ``CMakePresets.json``, even with +no ``include`` field, in all versions of the format. Files directly or +indirectly included from ``CMakePresets.json`` must be inside the project +directory. This restriction does not apply to ``CMakeUserPresets.json`` and +files that it includes, unless those files are also included by +``CMakePresets.json``. + Format ====== @@ -39,7 +55,7 @@ The root object recognizes the following fields: ``version`` A required integer representing the version of the JSON schema. - The supported versions are ``1``, ``2``, and ``3``. + The supported versions are ``1``, ``2``, ``3``, and ``4``. ``cmakeMinimumRequired`` @@ -82,6 +98,12 @@ The root object recognizes the following fields: An optional array of `Test Preset`_ objects. This is allowed in preset files specifying version ``2`` or above. +``include`` + + An optional array of strings representing files to include. If the filenames + are not absolute, they are considered relative to the current file. + This is allowed in preset files specifying version ``4`` or above. + Configure Preset ^^^^^^^^^^^^^^^^ diff --git a/Help/manual/presets/example.json b/Help/manual/presets/example.json index b08445a..a7ec10e 100644 --- a/Help/manual/presets/example.json +++ b/Help/manual/presets/example.json @@ -1,5 +1,5 @@ { - "version": 3, + "version": 4, "cmakeMinimumRequired": { "major": 3, "minor": 21, diff --git a/Help/manual/presets/schema.json b/Help/manual/presets/schema.json index 7852550..327291d 100644 --- a/Help/manual/presets/schema.json +++ b/Help/manual/presets/schema.json @@ -42,6 +42,21 @@ "testPresets": { "$ref": "#/definitions/testPresetsV3"} }, "additionalProperties": false + }, + { + "properties": { + "version": { + "const": 4, + "description": "A required integer representing the version of the JSON schema." + }, + "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"}, + "vendor": { "$ref": "#/definitions/vendor" }, + "configurePresets": { "$ref": "#/definitions/configurePresetsV3"}, + "buildPresets": { "$ref": "#/definitions/buildPresetsV3"}, + "testPresets": { "$ref": "#/definitions/testPresetsV3"}, + "include": { "$ref": "#/definitions/include"} + }, + "additionalProperties": false } ], "required": [ @@ -1235,6 +1250,13 @@ "description": "Null indicates that the condition always evaluates to true and is not inherited." } ] + }, + "include": { + "type": "array", + "description": "An optional array of strings representing files to include. If the filenames are not absolute, they are considered relative to the current file.", + "items": { + "type": "string" + } } } } diff --git a/Help/release/dev/cmake-presets-include.rst b/Help/release/dev/cmake-presets-include.rst new file mode 100644 index 0000000..51219bd --- /dev/null +++ b/Help/release/dev/cmake-presets-include.rst @@ -0,0 +1,6 @@ +cmake-presets-include +--------------------- + +* :manual:`cmake-presets(7)` files now support schema version ``4``. +* :manual:`cmake-presets(7)` files now have an optional ``include`` field, + which allows the files to include other files. diff --git a/Source/cmCMakePresetsGraph.cxx b/Source/cmCMakePresetsGraph.cxx index a8aad12..58dca36 100644 --- a/Source/cmCMakePresetsGraph.cxx +++ b/Source/cmCMakePresetsGraph.cxx @@ -996,6 +996,10 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result) case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED: return "File version must be 2 or higher for build and test preset " "support."; + case ReadFileResult::INCLUDE_UNSUPPORTED: + return "File version must be 4 or higher for include support"; + case ReadFileResult::INVALID_INCLUDE: + return "Invalid \"include\" field"; case ReadFileResult::INVALID_CONFIGURE_PRESET: return "Invalid \"configurePreset\" field"; case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED: @@ -1010,6 +1014,8 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result) "support."; case ReadFileResult::CYCLIC_INCLUDE: return "Cyclic include among preset files"; + case ReadFileResult::INCLUDE_OUTSIDE_PROJECT: + return "File included from outside project directory"; } return "Unknown error"; diff --git a/Source/cmCMakePresetsGraph.h b/Source/cmCMakePresetsGraph.h index c27a611..02c506f 100644 --- a/Source/cmCMakePresetsGraph.h +++ b/Source/cmCMakePresetsGraph.h @@ -36,12 +36,15 @@ public: PRESET_UNREACHABLE_FROM_FILE, INVALID_MACRO_EXPANSION, BUILD_TEST_PRESETS_UNSUPPORTED, + INCLUDE_UNSUPPORTED, + INVALID_INCLUDE, INVALID_CONFIGURE_PRESET, INSTALL_PREFIX_UNSUPPORTED, INVALID_CONDITION, CONDITION_UNSUPPORTED, TOOLCHAIN_FILE_UNSUPPORTED, CYCLIC_INCLUDE, + INCLUDE_OUTSIDE_PROJECT, }; enum class ArchToolsetStrategy diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx index aa5c9d4..ca34124 100644 --- a/Source/cmCMakePresetsGraphReadJSON.cxx +++ b/Source/cmCMakePresetsGraphReadJSON.cxx @@ -33,7 +33,7 @@ using TestPreset = cmCMakePresetsGraph::TestPreset; using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy; constexpr int MIN_VERSION = 1; -constexpr int MAX_VERSION = 3; +constexpr int MAX_VERSION = 4; struct CMakeVersion { @@ -48,6 +48,7 @@ struct RootPresets std::vector ConfigurePresets; std::vector BuildPresets; std::vector TestPresets; + std::vector Include; }; std::unique_ptr InvertCondition( @@ -271,6 +272,13 @@ auto const CMakeVersionHelper = .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false) .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false); +auto const IncludeHelper = cmJSONStringHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_INCLUDE); + +auto const IncludeVectorHelper = + cmJSONVectorHelper( + ReadFileResult::READ_OK, ReadFileResult::INVALID_INCLUDE, IncludeHelper); + auto const RootPresetsHelper = cmJSONObjectHelper( ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false) @@ -283,6 +291,7 @@ auto const RootPresetsHelper = cmCMakePresetsGraphInternal::TestPresetsHelper, false) .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired, CMakeVersionHelper, false) + .Bind("include"_s, &RootPresets::Include, IncludeVectorHelper, false) .Bind( "vendor"_s, nullptr, cmCMakePresetsGraphInternal::VendorHelper(ReadFileResult::INVALID_ROOT), @@ -413,6 +422,19 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( const std::string& filename, RootType rootType, ReadReason readReason, std::vector& inProgressFiles, File*& file) { + ReadFileResult result; + + if (rootType == RootType::Project) { + auto normalizedFilename = cmSystemTools::CollapseFullPath(filename); + + auto normalizedProjectDir = + cmSystemTools::CollapseFullPath(this->SourceDir); + if (!cmSystemTools::IsSubDirectory(normalizedFilename, + normalizedProjectDir)) { + return ReadFileResult::INCLUDE_OUTSIDE_PROJECT; + } + } + for (auto const& f : this->Files) { if (cmSystemTools::SameFile(filename, f->Filename)) { file = f.get(); @@ -421,6 +443,22 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( if (fileIt != inProgressFiles.end()) { return cmCMakePresetsGraph::ReadFileResult::CYCLIC_INCLUDE; } + + // Check files included by this file again to make sure they're in the + // project directory. + if (rootType == RootType::Project) { + for (auto* f2 : file->ReachableFiles) { + if (!cmSystemTools::SameFile(filename, f2->Filename)) { + File* file2; + if ((result = this->ReadJSONFile( + f2->Filename, rootType, ReadReason::Included, + inProgressFiles, file2)) != ReadFileResult::READ_OK) { + return result; + } + } + } + } + return cmCMakePresetsGraph::ReadFileResult::READ_OK; } } @@ -440,8 +478,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( } int v = 0; - auto result = RootVersionHelper(v, &root); - if (result != ReadFileResult::READ_OK) { + if ((result = RootVersionHelper(v, &root)) != ReadFileResult::READ_OK) { return result; } if (v < MIN_VERSION || v > MAX_VERSION) { @@ -454,6 +491,11 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED; } + // Support for include added in version 4. + if (v < 4 && root.isMember("include")) { + return ReadFileResult::INCLUDE_UNSUPPORTED; + } + RootPresets presets; if ((result = RootPresetsHelper(presets, &root)) != ReadFileResult::READ_OK) { @@ -571,6 +613,18 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( return ReadFileResult::READ_OK; }; + for (auto include : presets.Include) { + if (!cmSystemTools::FileIsFullPath(include)) { + auto directory = cmSystemTools::GetFilenamePath(filename); + include = cmStrCat(directory, '/', include); + } + + if ((result = includeFile(include, rootType, ReadReason::Included)) != + ReadFileResult::READ_OK) { + return result; + } + } + if (rootType == RootType::User && readReason == ReadReason::Root) { auto cmakePresetsFilename = GetFilename(this->SourceDir); if (cmSystemTools::FileExists(cmakePresetsFilename)) { diff --git a/Tests/RunCMake/CMakePresets/Include-stdout.txt b/Tests/RunCMake/CMakePresets/Include-stdout.txt new file mode 100644 index 0000000..6ba1170 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/Include-stdout.txt @@ -0,0 +1,8 @@ +^Not searching for unused variables given on the command line\. +Available configure presets: + + "IncludeUser" + "IncludeUserCommon" + "Include" + "Subdir" + "IncludeCommon"$ diff --git a/Tests/RunCMake/CMakePresets/Include.json.in b/Tests/RunCMake/CMakePresets/Include.json.in new file mode 100644 index 0000000..3687d3c --- /dev/null +++ b/Tests/RunCMake/CMakePresets/Include.json.in @@ -0,0 +1,16 @@ +{ + "version": 4, + "include": [ + "subdir/CMakePresets.json", + "@RunCMake_TEST_SOURCE_DIR@/IncludeCommon.json" + ], + "configurePresets": [ + { + "name": "Include", + "inherits": [ + "IncludeCommon", + "Subdir" + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeCommon.json.in b/Tests/RunCMake/CMakePresets/IncludeCommon.json.in new file mode 100644 index 0000000..eeae723 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeCommon.json.in @@ -0,0 +1,8 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "IncludeCommon" + } + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeCycle-result.txt b/Tests/RunCMake/CMakePresets/IncludeCycle-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeCycle-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresets/IncludeCycle-stderr.txt b/Tests/RunCMake/CMakePresets/IncludeCycle-stderr.txt new file mode 100644 index 0000000..3343204 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeCycle-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresets/IncludeCycle: Cyclic include among preset files$ diff --git a/Tests/RunCMake/CMakePresets/IncludeCycle.json.in b/Tests/RunCMake/CMakePresets/IncludeCycle.json.in new file mode 100644 index 0000000..b35b6ff --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeCycle.json.in @@ -0,0 +1,11 @@ +{ + "version": 4, + "include": [ + "CMakeUserPresets.json" + ], + "configurePresets": [ + { + "name": "IncludeCycle" + } + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeCycle3Files-result.txt b/Tests/RunCMake/CMakePresets/IncludeCycle3Files-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeCycle3Files-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresets/IncludeCycle3Files-stderr.txt b/Tests/RunCMake/CMakePresets/IncludeCycle3Files-stderr.txt new file mode 100644 index 0000000..35aea4c --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeCycle3Files-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresets/IncludeCycle3Files: Cyclic include among preset files$ diff --git a/Tests/RunCMake/CMakePresets/IncludeCycle3Files.json.in b/Tests/RunCMake/CMakePresets/IncludeCycle3Files.json.in new file mode 100644 index 0000000..8174ff0 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeCycle3Files.json.in @@ -0,0 +1,6 @@ +{ + "version": 4, + "include": [ + "IncludeCycle3Files2.json" + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeCycle3Files2.json.in b/Tests/RunCMake/CMakePresets/IncludeCycle3Files2.json.in new file mode 100644 index 0000000..952e875 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeCycle3Files2.json.in @@ -0,0 +1,6 @@ +{ + "version": 4, + "include": [ + "IncludeCycle3Files3.json" + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeCycle3Files3.json.in b/Tests/RunCMake/CMakePresets/IncludeCycle3Files3.json.in new file mode 100644 index 0000000..8dbf3ad --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeCycle3Files3.json.in @@ -0,0 +1,6 @@ +{ + "version": 4, + "include": [ + "CMakePresets.json" + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeCycleUser.json.in b/Tests/RunCMake/CMakePresets/IncludeCycleUser.json.in new file mode 100644 index 0000000..cd2f236 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeCycleUser.json.in @@ -0,0 +1,3 @@ +{ + "version": 3 +} diff --git a/Tests/RunCMake/CMakePresets/IncludeNotFound-result.txt b/Tests/RunCMake/CMakePresets/IncludeNotFound-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeNotFound-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresets/IncludeNotFound-stderr.txt b/Tests/RunCMake/CMakePresets/IncludeNotFound-stderr.txt new file mode 100644 index 0000000..7ccabab --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeNotFound-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresets/IncludeNotFound: File not found$ diff --git a/Tests/RunCMake/CMakePresets/IncludeNotFound.json.in b/Tests/RunCMake/CMakePresets/IncludeNotFound.json.in new file mode 100644 index 0000000..a72b183 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeNotFound.json.in @@ -0,0 +1,11 @@ +{ + "version": 4, + "include": [ + "NotFound.json" + ], + "configurePresets": [ + { + "name": "IncludeNotFound" + } + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeOutsideProject-result.txt b/Tests/RunCMake/CMakePresets/IncludeOutsideProject-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeOutsideProject-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresets/IncludeOutsideProject-stderr.txt b/Tests/RunCMake/CMakePresets/IncludeOutsideProject-stderr.txt new file mode 100644 index 0000000..2aa3f59 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeOutsideProject-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresets/IncludeOutsideProject: File included from outside project directory$ diff --git a/Tests/RunCMake/CMakePresets/IncludeOutsideProject.json.in b/Tests/RunCMake/CMakePresets/IncludeOutsideProject.json.in new file mode 100644 index 0000000..cf1928f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeOutsideProject.json.in @@ -0,0 +1,11 @@ +{ + "version": 4, + "include": [ + "IncludeOutsideProjectIntermediate.json" + ], + "configurePresets": [ + { + "name": "IncludeOutsideProject" + } + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeOutsideProjectInclude.json b/Tests/RunCMake/CMakePresets/IncludeOutsideProjectInclude.json new file mode 100644 index 0000000..f13e55c --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeOutsideProjectInclude.json @@ -0,0 +1,3 @@ +{ + "version": 4 +} diff --git a/Tests/RunCMake/CMakePresets/IncludeOutsideProjectIntermediate.json.in b/Tests/RunCMake/CMakePresets/IncludeOutsideProjectIntermediate.json.in new file mode 100644 index 0000000..7c140c6 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeOutsideProjectIntermediate.json.in @@ -0,0 +1,6 @@ +{ + "version": 4, + "include": [ + "@RunCMake_SOURCE_DIR@/IncludeOutsideProjectInclude.json" + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeOutsideProjectUser.json.in b/Tests/RunCMake/CMakePresets/IncludeOutsideProjectUser.json.in new file mode 100644 index 0000000..f4f540e --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeOutsideProjectUser.json.in @@ -0,0 +1,6 @@ +{ + "version": 4, + "include": [ + "IncludeOutsideProjectIntermediate.json" + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeUser.json.in b/Tests/RunCMake/CMakePresets/IncludeUser.json.in new file mode 100644 index 0000000..46d23fd --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeUser.json.in @@ -0,0 +1,15 @@ +{ + "version": 4, + "include": [ + "IncludeUserCommon.json" + ], + "configurePresets": [ + { + "name": "IncludeUser", + "inherits": [ + "Include", + "IncludeUserCommon" + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeUserCommon.json.in b/Tests/RunCMake/CMakePresets/IncludeUserCommon.json.in new file mode 100644 index 0000000..5a1bd36 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeUserCommon.json.in @@ -0,0 +1,8 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "IncludeUserCommon" + } + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeUserOutsideProject.cmake b/Tests/RunCMake/CMakePresets/IncludeUserOutsideProject.cmake new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/CMakePresets/IncludeUserOutsideProjectUser.json.in b/Tests/RunCMake/CMakePresets/IncludeUserOutsideProjectUser.json.in new file mode 100644 index 0000000..5b5427a --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeUserOutsideProjectUser.json.in @@ -0,0 +1,11 @@ +{ + "version": 4, + "include": [ + "@RunCMake_SOURCE_DIR@/IncludeOutsideProjectInclude.json" + ], + "configurePresets": [ + { + "name": "IncludeUserOutsideProject" + } + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeV3-result.txt b/Tests/RunCMake/CMakePresets/IncludeV3-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeV3-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresets/IncludeV3-stderr.txt b/Tests/RunCMake/CMakePresets/IncludeV3-stderr.txt new file mode 100644 index 0000000..1869b6d --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeV3-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresets/IncludeV3: File version must be 4 or higher for include support$ diff --git a/Tests/RunCMake/CMakePresets/IncludeV3.json.in b/Tests/RunCMake/CMakePresets/IncludeV3.json.in new file mode 100644 index 0000000..b28cad8 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeV3.json.in @@ -0,0 +1,4 @@ +{ + "version": 3, + "include": [] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeV4V3-result.txt b/Tests/RunCMake/CMakePresets/IncludeV4V3-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeV4V3-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresets/IncludeV4V3-stderr.txt b/Tests/RunCMake/CMakePresets/IncludeV4V3-stderr.txt new file mode 100644 index 0000000..89e3e3d --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeV4V3-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresets/IncludeV4V3: File version must be 4 or higher for include support$ diff --git a/Tests/RunCMake/CMakePresets/IncludeV4V3.json.in b/Tests/RunCMake/CMakePresets/IncludeV4V3.json.in new file mode 100644 index 0000000..4afa319 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeV4V3.json.in @@ -0,0 +1,6 @@ +{ + "version": 4, + "include": [ + "IncludeV4V3Extra.json" + ] +} diff --git a/Tests/RunCMake/CMakePresets/IncludeV4V3Extra.json.in b/Tests/RunCMake/CMakePresets/IncludeV4V3Extra.json.in new file mode 100644 index 0000000..b28cad8 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/IncludeV4V3Extra.json.in @@ -0,0 +1,4 @@ +{ + "version": 3, + "include": [] +} diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake index c31a645..51e786e 100644 --- a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake +++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake @@ -44,6 +44,20 @@ function(run_cmake_presets name) configure_file("${CMakeUserPresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" @ONLY) endif() + set(_CMakePresets_EXTRA_FILES_OUT) + set(_CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS) + foreach(_extra_file IN LISTS CMakePresets_EXTRA_FILES) + cmake_path(RELATIVE_PATH _extra_file + BASE_DIRECTORY "${RunCMake_SOURCE_DIR}" + OUTPUT_VARIABLE _extra_file_relative + ) + string(REGEX REPLACE "\\.in$" "" _extra_file_out_relative "${_extra_file_relative}") + set(_extra_file_out "${RunCMake_TEST_SOURCE_DIR}/${_extra_file_out_relative}") + configure_file("${_extra_file}" "${_extra_file_out}") + list(APPEND _CMakePresets_EXTRA_FILES_OUT "${_extra_file_out}") + list(APPEND _CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS 0) + endforeach() + set(_s_arg -S) if(CMakePresets_NO_S_ARG) set(_s_arg) @@ -319,6 +333,37 @@ run_cmake_presets(OptionalBinaryDirFieldNoS) unset(CMakePresets_SOURCE_ARG) unset(CMakePresets_NO_S_ARG) +# Test include field +set(CMakePresets_SCHEMA_EXPECTED_RESULT 1) +run_cmake_presets(IncludeV3) +set(CMakePresets_SCHEMA_EXPECTED_RESULT 0) +set(CMakePresets_EXTRA_FILES + "${RunCMake_SOURCE_DIR}/IncludeV4V3Extra.json.in" + ) +set(CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS 1) +run_cmake_presets(IncludeV4V3) +unset(CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS) +set(CMakePresets_EXTRA_FILES + "${RunCMake_SOURCE_DIR}/IncludeCommon.json.in" + "${RunCMake_SOURCE_DIR}/IncludeUserCommon.json.in" + "${RunCMake_SOURCE_DIR}/subdir/CMakePresets.json.in" + ) +run_cmake_presets(Include --list-presets) +unset(CMakePresets_EXTRA_FILES) +run_cmake_presets(IncludeNotFound) +run_cmake_presets(IncludeCycle) +set(CMakePresets_EXTRA_FILES + "${RunCMake_SOURCE_DIR}/IncludeCycle3Files2.json.in" + "${RunCMake_SOURCE_DIR}/IncludeCycle3Files3.json.in" + ) +run_cmake_presets(IncludeCycle3Files) +set(CMakePresets_EXTRA_FILES + "${RunCMake_SOURCE_DIR}/IncludeOutsideProjectIntermediate.json.in" + ) +run_cmake_presets(IncludeOutsideProject) +unset(CMakePresets_EXTRA_FILES) +run_cmake_presets(IncludeUserOutsideProject) + # Test the example from the documentation file(READ "${RunCMake_SOURCE_DIR}/../../../Help/manual/presets/example.json" _example) string(REPLACE "\"generator\": \"Ninja\"" "\"generator\": \"@RunCMake_GENERATOR@\"" _example "${_example}") diff --git a/Tests/RunCMake/CMakePresets/check.cmake b/Tests/RunCMake/CMakePresets/check.cmake index bf43c7e..cef43f4 100644 --- a/Tests/RunCMake/CMakePresets/check.cmake +++ b/Tests/RunCMake/CMakePresets/check.cmake @@ -12,4 +12,11 @@ if(PYTHON_EXECUTABLE AND CMake_TEST_JSON_SCHEMA) if(EXISTS "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json") validate_schema("${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" "${CMakeUserPresets_SCHEMA_EXPECTED_RESULT}") endif() + + if(NOT CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS) + set(CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS "${_CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS}") + endif() + foreach(_f _r IN ZIP_LISTS _CMakePresets_EXTRA_FILES_OUT CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS) + validate_schema("${_f}" "${_r}") + endforeach() endif() diff --git a/Tests/RunCMake/CMakePresets/subdir/CMakePresets.json.in b/Tests/RunCMake/CMakePresets/subdir/CMakePresets.json.in new file mode 100644 index 0000000..deb9084 --- /dev/null +++ b/Tests/RunCMake/CMakePresets/subdir/CMakePresets.json.in @@ -0,0 +1,12 @@ +{ + "version": 4, + "include": [ + "../IncludeCommon.json" + ], + "configurePresets": [ + { + "name": "Subdir", + "inherits": "IncludeCommon" + } + ] +} -- cgit v0.12