CMakePresets.json: Add workflow presets to schema

This commit is contained in:
Kyle Edwards 2022-09-08 18:24:28 -04:00
parent eb6e2ef7f6
commit e316812884
6 changed files with 316 additions and 5 deletions

View File

@ -148,6 +148,7 @@ add_library(
cmCMakePresetsGraphReadJSONConfigurePresets.cxx
cmCMakePresetsGraphReadJSONPackagePresets.cxx
cmCMakePresetsGraphReadJSONTestPresets.cxx
cmCMakePresetsGraphReadJSONWorkflowPresets.cxx
cmCommandArgumentParserHelper.cxx
cmCommonTargetGenerator.cxx
cmCommonTargetGenerator.h

View File

@ -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 <typename T>
using PresetPair = cmCMakePresetsGraph::PresetPair<T>;
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<WorkflowPreset>& /*out*/,
const std::vector<MacroExpander>& /*macroExpanders*/)
{
return true;
}
template <class T>
bool ExpandMacros(const cmCMakePresetsGraph& graph, const T& preset,
cm::optional<T>& out)
@ -579,6 +590,42 @@ ExpandMacroResult ExpandMacro(std::string& out,
return ExpandMacroResult::Error;
}
template <typename T>
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<ConfigurePreset>(
const ConfigurePreset& preset, const ConfigurePreset*& configurePreset)
{
configurePreset = &preset;
return ReadFileResult::READ_OK;
}
template <typename T>
ReadFileResult TryReachPresetFromWorkflow(
const WorkflowPreset& origin,
const std::map<std::string, PresetPair<T>>& 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<T>(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<const cmCMakePresetsGraph::Preset*> 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<const cmCMakePresetsGraph::Preset*>(&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);
}

View File

@ -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<std::string> 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<WorkflowStep> Steps;
ReadFileResult VisitPresetInherit(const Preset& parent) override;
ReadFileResult VisitPresetAfterInherit(int /* version */) override;
};
template <class T>
class PresetPair
{
@ -375,11 +415,13 @@ public:
std::map<std::string, PresetPair<BuildPreset>> BuildPresets;
std::map<std::string, PresetPair<TestPreset>> TestPresets;
std::map<std::string, PresetPair<PackagePreset>> PackagePresets;
std::map<std::string, PresetPair<WorkflowPreset>> WorkflowPresets;
std::vector<std::string> ConfigurePresetOrder;
std::vector<std::string> BuildPresetOrder;
std::vector<std::string> TestPresetOrder;
std::vector<std::string> PackagePresetOrder;
std::vector<std::string> WorkflowPresetOrder;
std::string SourceDir;
std::vector<std::unique_ptr<File>> Files;
@ -442,6 +484,7 @@ public:
void PrintPackagePresetList(
const std::function<bool(const PackagePreset&)>& filter,
PrintPrecedingNewline* newline = nullptr) const;
void PrintWorkflowPresetList(PrintPrecedingNewline* newline = nullptr) const;
void PrintAllPresets() const;
private:

View File

@ -151,6 +151,10 @@ cmCMakePresetsGraph::ReadFileResult PackagePresetsHelper(
std::vector<cmCMakePresetsGraph::PackagePreset>& out,
const Json::Value* value);
cmCMakePresetsGraph::ReadFileResult WorkflowPresetsHelper(
std::vector<cmCMakePresetsGraph::WorkflowPreset>& out,
const Json::Value* value);
cmJSONHelper<std::nullptr_t, cmCMakePresetsGraph::ReadFileResult> VendorHelper(
cmCMakePresetsGraph::ReadFileResult error);

View File

@ -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<ReadFileResult>;
@ -46,10 +48,11 @@ struct CMakeVersion
struct RootPresets
{
CMakeVersion CMakeMinimumRequired;
std::vector<cmCMakePresetsGraph::ConfigurePreset> ConfigurePresets;
std::vector<cmCMakePresetsGraph::BuildPreset> BuildPresets;
std::vector<cmCMakePresetsGraph::TestPreset> TestPresets;
std::vector<cmCMakePresetsGraph::PackagePreset> PackagePresets;
std::vector<ConfigurePreset> ConfigurePresets;
std::vector<BuildPreset> BuildPresets;
std::vector<TestPreset> TestPresets;
std::vector<PackagePreset> PackagePresets;
std::vector<WorkflowPreset> WorkflowPresets;
std::vector<std::string> 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<WorkflowPreset> 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,

View File

@ -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 <cstddef>
#include <functional>
#include <string>
#include <vector>
#include <cmext/string_view>
#include <cm3p/json/value.h>
#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<ReadFileResult>::Object<WorkflowPreset::WorkflowStep>(
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<ReadFileResult>::Vector<WorkflowPreset::WorkflowStep>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
WorkflowStepHelper);
auto const WorkflowPresetHelper =
cmJSONHelperBuilder<ReadFileResult>::Object<WorkflowPreset>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
.Bind("name"_s, &WorkflowPreset::Name,
cmCMakePresetsGraphInternal::PresetStringHelper)
.Bind<std::nullptr_t>("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<cmCMakePresetsGraph::WorkflowPreset>& out,
const Json::Value* value)
{
static auto const helper =
cmJSONHelperBuilder<ReadFileResult>::Vector<WorkflowPreset>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
WorkflowPresetHelper);
return helper(out, value);
}
}