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