From e3168128841485a0a579ad3b9125fdae5e12eec8 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Thu, 8 Sep 2022 18:24:28 -0400 Subject: CMakePresets.json: Add workflow presets to schema --- Source/CMakeLists.txt | 1 + Source/cmCMakePresetsGraph.cxx | 139 +++++++++++++++++++++ Source/cmCMakePresetsGraph.h | 45 ++++++- Source/cmCMakePresetsGraphInternal.h | 4 + Source/cmCMakePresetsGraphReadJSON.cxx | 37 +++++- .../cmCMakePresetsGraphReadJSONWorkflowPresets.cxx | 95 ++++++++++++++ 6 files changed, 316 insertions(+), 5 deletions(-) create mode 100644 Source/cmCMakePresetsGraphReadJSONWorkflowPresets.cxx diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 32bd341..8f2a5cb 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -148,6 +148,7 @@ add_library( cmCMakePresetsGraphReadJSONConfigurePresets.cxx cmCMakePresetsGraphReadJSONPackagePresets.cxx cmCMakePresetsGraphReadJSONTestPresets.cxx + cmCMakePresetsGraphReadJSONWorkflowPresets.cxx cmCommandArgumentParserHelper.cxx cmCommonTargetGenerator.cxx cmCommonTargetGenerator.h diff --git a/Source/cmCMakePresetsGraph.cxx b/Source/cmCMakePresetsGraph.cxx index 7fbcdab..fb3d042 100644 --- a/Source/cmCMakePresetsGraph.cxx +++ b/Source/cmCMakePresetsGraph.cxx @@ -44,6 +44,9 @@ using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset; using BuildPreset = cmCMakePresetsGraph::BuildPreset; using TestPreset = cmCMakePresetsGraph::TestPreset; using PackagePreset = cmCMakePresetsGraph::PackagePreset; +using WorkflowPreset = cmCMakePresetsGraph::WorkflowPreset; +template +using PresetPair = cmCMakePresetsGraph::PresetPair; using ExpandMacroResult = cmCMakePresetsGraphInternal::ExpandMacroResult; using MacroExpander = cmCMakePresetsGraphInternal::MacroExpander; @@ -324,6 +327,14 @@ bool ExpandMacros(const cmCMakePresetsGraph& graph, return true; } +bool ExpandMacros(const cmCMakePresetsGraph& /*graph*/, + const WorkflowPreset& /*preset*/, + cm::optional& /*out*/, + const std::vector& /*macroExpanders*/) +{ + return true; +} + template bool ExpandMacros(const cmCMakePresetsGraph& graph, const T& preset, cm::optional& out) @@ -579,6 +590,42 @@ ExpandMacroResult ExpandMacro(std::string& out, return ExpandMacroResult::Error; } + +template +ReadFileResult SetupWorkflowConfigurePreset( + const T& preset, const ConfigurePreset*& configurePreset) +{ + if (preset.ConfigurePreset != configurePreset->Name) { + return ReadFileResult::INVALID_WORKFLOW_STEPS; + } + return ReadFileResult::READ_OK; +} + +template <> +ReadFileResult SetupWorkflowConfigurePreset( + const ConfigurePreset& preset, const ConfigurePreset*& configurePreset) +{ + configurePreset = &preset; + return ReadFileResult::READ_OK; +} + +template +ReadFileResult TryReachPresetFromWorkflow( + const WorkflowPreset& origin, + const std::map>& presets, const std::string& name, + const ConfigurePreset*& configurePreset) +{ + auto it = presets.find(name); + if (it == presets.end()) { + return ReadFileResult::INVALID_WORKFLOW_STEPS; + } + if (!origin.OriginFile->ReachableFiles.count( + it->second.Unexpanded.OriginFile)) { + return ReadFileResult::WORKFLOW_STEP_UNREACHABLE_FROM_FILE; + } + return SetupWorkflowConfigurePreset(it->second.Unexpanded, + configurePreset); +} } bool cmCMakePresetsGraphInternal::EqualsCondition::Evaluate( @@ -929,6 +976,19 @@ cmCMakePresetsGraph::PackagePreset::VisitPresetAfterInherit(int /* version */) return ReadFileResult::READ_OK; } +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::WorkflowPreset::VisitPresetInherit( + const cmCMakePresetsGraph::Preset& /*parentPreset*/) +{ + return ReadFileResult::READ_OK; +} + +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::WorkflowPreset::VisitPresetAfterInherit(int /* version */) +{ + return ReadFileResult::READ_OK; +} + std::string cmCMakePresetsGraph::GetFilename(const std::string& sourceDir) { return cmStrCat(sourceDir, "/CMakePresets.json"); @@ -992,6 +1052,7 @@ cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles) CHECK_OK(ComputePresetInheritance(this->BuildPresets, *this)); CHECK_OK(ComputePresetInheritance(this->TestPresets, *this)); CHECK_OK(ComputePresetInheritance(this->PackagePresets, *this)); + CHECK_OK(ComputePresetInheritance(this->WorkflowPresets, *this)); for (auto& it : this->ConfigurePresets) { if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) { @@ -1071,6 +1132,55 @@ cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles) } } + for (auto& it : this->WorkflowPresets) { + using Type = WorkflowPreset::WorkflowStep::Type; + + const ConfigurePreset* configurePreset = nullptr; + for (auto const& step : it.second.Unexpanded.Steps) { + if (configurePreset == nullptr && step.PresetType != Type::Configure) { + return ReadFileResult::INVALID_WORKFLOW_STEPS; + } + if (configurePreset != nullptr && step.PresetType == Type::Configure) { + return ReadFileResult::INVALID_WORKFLOW_STEPS; + } + + ReadFileResult result; + switch (step.PresetType) { + case Type::Configure: + result = TryReachPresetFromWorkflow( + it.second.Unexpanded, this->ConfigurePresets, step.PresetName, + configurePreset); + break; + case Type::Build: + result = TryReachPresetFromWorkflow( + it.second.Unexpanded, this->BuildPresets, step.PresetName, + configurePreset); + break; + case Type::Test: + result = + TryReachPresetFromWorkflow(it.second.Unexpanded, this->TestPresets, + step.PresetName, configurePreset); + break; + case Type::Package: + result = TryReachPresetFromWorkflow( + it.second.Unexpanded, this->PackagePresets, step.PresetName, + configurePreset); + break; + } + if (result != ReadFileResult::READ_OK) { + return result; + } + } + + if (configurePreset == nullptr) { + return ReadFileResult::INVALID_WORKFLOW_STEPS; + } + + if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) { + return ReadFileResult::INVALID_MACRO_EXPANSION; + } + } + return ReadFileResult::READ_OK; } @@ -1116,6 +1226,8 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result) "support."; case ReadFileResult::PACKAGE_PRESETS_UNSUPPORTED: return "File version must be 6 or higher for package preset support"; + case ReadFileResult::WORKFLOW_PRESETS_UNSUPPORTED: + return "File version must be 6 or higher for workflow preset support"; case ReadFileResult::INCLUDE_UNSUPPORTED: return "File version must be 4 or higher for include support"; case ReadFileResult::INVALID_INCLUDE: @@ -1137,6 +1249,10 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result) case ReadFileResult::TEST_OUTPUT_TRUNCATION_UNSUPPORTED: return "File version must be 5 or higher for testOutputTruncation " "preset support."; + case ReadFileResult::INVALID_WORKFLOW_STEPS: + return "Invalid workflow steps"; + case ReadFileResult::WORKFLOW_STEP_UNREACHABLE_FROM_FILE: + return "Workflow step is unreachable from preset's file"; } return "Unknown error"; @@ -1148,11 +1264,13 @@ void cmCMakePresetsGraph::ClearPresets() this->BuildPresets.clear(); this->TestPresets.clear(); this->PackagePresets.clear(); + this->WorkflowPresets.clear(); this->ConfigurePresetOrder.clear(); this->BuildPresetOrder.clear(); this->TestPresetOrder.clear(); this->PackagePresetOrder.clear(); + this->WorkflowPresetOrder.clear(); this->Files.clear(); } @@ -1291,6 +1409,26 @@ void cmCMakePresetsGraph::PrintPackagePresetList( } } +void cmCMakePresetsGraph::PrintWorkflowPresetList( + PrintPrecedingNewline* newline) const +{ + std::vector presets; + for (auto const& p : this->WorkflowPresetOrder) { + auto const& preset = this->WorkflowPresets.at(p); + if (!preset.Unexpanded.Hidden && preset.Expanded && + preset.Expanded->ConditionResult) { + presets.push_back( + static_cast(&preset.Unexpanded)); + } + } + + if (!presets.empty()) { + printPrecedingNewline(newline); + std::cout << "Available workflow presets:\n\n"; + cmCMakePresetsGraph::PrintPresets(presets); + } +} + void cmCMakePresetsGraph::PrintAllPresets() const { PrintPrecedingNewline newline = PrintPrecedingNewline::False; @@ -1298,4 +1436,5 @@ void cmCMakePresetsGraph::PrintAllPresets() const this->PrintBuildPresetList(&newline); this->PrintTestPresetList(&newline); this->PrintPackagePresetList(&newline); + this->PrintWorkflowPresetList(&newline); } diff --git a/Source/cmCMakePresetsGraph.h b/Source/cmCMakePresetsGraph.h index 806a36d..5b3e812 100644 --- a/Source/cmCMakePresetsGraph.h +++ b/Source/cmCMakePresetsGraph.h @@ -42,6 +42,7 @@ public: INVALID_MACRO_EXPANSION, BUILD_TEST_PRESETS_UNSUPPORTED, PACKAGE_PRESETS_UNSUPPORTED, + WORKFLOW_PRESETS_UNSUPPORTED, INCLUDE_UNSUPPORTED, INVALID_INCLUDE, INVALID_CONFIGURE_PRESET, @@ -51,6 +52,8 @@ public: TOOLCHAIN_FILE_UNSUPPORTED, CYCLIC_INCLUDE, TEST_OUTPUT_TRUNCATION_UNSUPPORTED, + INVALID_WORKFLOW_STEPS, + WORKFLOW_STEP_UNREACHABLE_FROM_FILE, }; std::string errors; @@ -97,7 +100,7 @@ public: std::string Name; std::vector Inherits; - bool Hidden; + bool Hidden = false; File* OriginFile; std::string DisplayName; std::string Description; @@ -363,6 +366,43 @@ public: ReadFileResult VisitPresetAfterInherit(int /* version */) override; }; + class WorkflowPreset : public Preset + { + public: + WorkflowPreset() = default; + WorkflowPreset(WorkflowPreset&& /*other*/) = default; + WorkflowPreset(const WorkflowPreset& /*other*/) = default; + WorkflowPreset& operator=(const WorkflowPreset& /*other*/) = default; + ~WorkflowPreset() override = default; +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + WorkflowPreset& operator=(WorkflowPreset&& /*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. + WorkflowPreset& operator=(WorkflowPreset&& /*other*/) = delete; +#endif + + class WorkflowStep + { + public: + enum class Type + { + Configure, + Build, + Test, + Package, + }; + Type PresetType; + std::string PresetName; + }; + + std::vector Steps; + + ReadFileResult VisitPresetInherit(const Preset& parent) override; + ReadFileResult VisitPresetAfterInherit(int /* version */) override; + }; + template class PresetPair { @@ -375,11 +415,13 @@ public: std::map> BuildPresets; std::map> TestPresets; std::map> PackagePresets; + std::map> WorkflowPresets; std::vector ConfigurePresetOrder; std::vector BuildPresetOrder; std::vector TestPresetOrder; std::vector PackagePresetOrder; + std::vector WorkflowPresetOrder; std::string SourceDir; std::vector> Files; @@ -442,6 +484,7 @@ public: void PrintPackagePresetList( const std::function& filter, PrintPrecedingNewline* newline = nullptr) const; + void PrintWorkflowPresetList(PrintPrecedingNewline* newline = nullptr) const; void PrintAllPresets() const; private: diff --git a/Source/cmCMakePresetsGraphInternal.h b/Source/cmCMakePresetsGraphInternal.h index 40af356..9e47a69 100644 --- a/Source/cmCMakePresetsGraphInternal.h +++ b/Source/cmCMakePresetsGraphInternal.h @@ -151,6 +151,10 @@ cmCMakePresetsGraph::ReadFileResult PackagePresetsHelper( std::vector& out, const Json::Value* value); +cmCMakePresetsGraph::ReadFileResult WorkflowPresetsHelper( + std::vector& out, + const Json::Value* value); + cmJSONHelper VendorHelper( cmCMakePresetsGraph::ReadFileResult error); diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx index 4fba7d9..5aa4284 100644 --- a/Source/cmCMakePresetsGraphReadJSON.cxx +++ b/Source/cmCMakePresetsGraphReadJSON.cxx @@ -30,6 +30,8 @@ using CacheVariable = cmCMakePresetsGraph::CacheVariable; using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset; using BuildPreset = cmCMakePresetsGraph::BuildPreset; using TestPreset = cmCMakePresetsGraph::TestPreset; +using PackagePreset = cmCMakePresetsGraph::PackagePreset; +using WorkflowPreset = cmCMakePresetsGraph::WorkflowPreset; using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy; using JSONHelperBuilder = cmJSONHelperBuilder; @@ -46,10 +48,11 @@ struct CMakeVersion struct RootPresets { CMakeVersion CMakeMinimumRequired; - std::vector ConfigurePresets; - std::vector BuildPresets; - std::vector TestPresets; - std::vector PackagePresets; + std::vector ConfigurePresets; + std::vector BuildPresets; + std::vector TestPresets; + std::vector PackagePresets; + std::vector WorkflowPresets; std::vector Include; }; @@ -284,6 +287,8 @@ auto const RootPresetsHelper = cmCMakePresetsGraphInternal::TestPresetsHelper, false) .Bind("packagePresets"_s, &RootPresets::PackagePresets, cmCMakePresetsGraphInternal::PackagePresetsHelper, false) + .Bind("workflowPresets"_s, &RootPresets::WorkflowPresets, + cmCMakePresetsGraphInternal::WorkflowPresetsHelper, false) .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired, CMakeVersionHelper, false) .Bind("include"_s, &RootPresets::Include, IncludeVectorHelper, false) @@ -466,6 +471,11 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( return ReadFileResult::PACKAGE_PRESETS_UNSUPPORTED; } + // Support for workflow presets added in version 6. + if (v < 6 && root.isMember("workflowPresets")) { + return ReadFileResult::WORKFLOW_PRESETS_UNSUPPORTED; + } + // Support for include added in version 4. if (v < 4 && root.isMember("include")) { return ReadFileResult::INCLUDE_UNSUPPORTED; @@ -600,6 +610,25 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( this->PackagePresetOrder.push_back(preset.Name); } + for (auto& preset : presets.WorkflowPresets) { + preset.OriginFile = file; + if (preset.Name.empty()) { + return ReadFileResult::INVALID_PRESET; + } + + PresetPair presetPair; + presetPair.Unexpanded = preset; + presetPair.Expanded = cm::nullopt; + if (!this->WorkflowPresets.emplace(preset.Name, presetPair).second) { + return ReadFileResult::DUPLICATE_PRESETS; + } + + // Support for conditions added in version 3, but this requires version 6 + // already, so no action needed. + + this->WorkflowPresetOrder.push_back(preset.Name); + } + auto const includeFile = [this, &inProgressFiles, file]( const std::string& include, RootType rootType2, ReadReason readReason2, diff --git a/Source/cmCMakePresetsGraphReadJSONWorkflowPresets.cxx b/Source/cmCMakePresetsGraphReadJSONWorkflowPresets.cxx new file mode 100644 index 0000000..33680a1 --- /dev/null +++ b/Source/cmCMakePresetsGraphReadJSONWorkflowPresets.cxx @@ -0,0 +1,95 @@ +/* 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 "cmCMakePresetsGraph.h" +#include "cmCMakePresetsGraphInternal.h" +#include "cmJSONHelpers.h" + +namespace { +using ReadFileResult = cmCMakePresetsGraph::ReadFileResult; +using WorkflowPreset = cmCMakePresetsGraph::WorkflowPreset; + +ReadFileResult WorkflowStepTypeHelper(WorkflowPreset::WorkflowStep::Type& out, + const Json::Value* value) +{ + if (!value) { + return ReadFileResult::INVALID_PRESET; + } + + if (!value->isString()) { + return ReadFileResult::INVALID_PRESET; + } + + if (value->asString() == "configure") { + out = WorkflowPreset::WorkflowStep::Type::Configure; + return ReadFileResult::READ_OK; + } + + if (value->asString() == "build") { + out = WorkflowPreset::WorkflowStep::Type::Build; + return ReadFileResult::READ_OK; + } + + if (value->asString() == "test") { + out = WorkflowPreset::WorkflowStep::Type::Test; + return ReadFileResult::READ_OK; + } + + if (value->asString() == "package") { + out = WorkflowPreset::WorkflowStep::Type::Package; + return ReadFileResult::READ_OK; + } + + return ReadFileResult::INVALID_PRESET; +} + +auto const WorkflowStepHelper = + cmJSONHelperBuilder::Object( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("type"_s, &WorkflowPreset::WorkflowStep::PresetType, + WorkflowStepTypeHelper) + .Bind("name"_s, &WorkflowPreset::WorkflowStep::PresetName, + cmCMakePresetsGraphInternal::PresetStringHelper); + +auto const WorkflowStepsHelper = + cmJSONHelperBuilder::Vector( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, + WorkflowStepHelper); + +auto const WorkflowPresetHelper = + cmJSONHelperBuilder::Object( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("name"_s, &WorkflowPreset::Name, + cmCMakePresetsGraphInternal::PresetStringHelper) + .Bind("vendor"_s, nullptr, + cmCMakePresetsGraphInternal::VendorHelper( + ReadFileResult::INVALID_PRESET), + false) + .Bind("displayName"_s, &WorkflowPreset::DisplayName, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("description"_s, &WorkflowPreset::Description, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("steps"_s, &WorkflowPreset::Steps, WorkflowStepsHelper); +} + +namespace cmCMakePresetsGraphInternal { +cmCMakePresetsGraph::ReadFileResult WorkflowPresetsHelper( + std::vector& out, + const Json::Value* value) +{ + static auto const helper = + cmJSONHelperBuilder::Vector( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, + WorkflowPresetHelper); + + return helper(out, value); +} +} -- cgit v0.12