From 374d82bbcd461a5ee8d1d9d3a94abd8a26759c37 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Fri, 16 Sep 2022 15:17:27 -0400 Subject: cmake: Add --workflow mode Fixes: #23118 --- Help/manual/cmake-presets.7.rst | 56 +++++- Help/manual/cmake.1.rst | 22 +++ Help/manual/presets/example.json | 23 +++ Help/manual/presets/schema.json | 85 ++++++++- Help/release/dev/cmake-presets-workflow.rst | 4 + Source/cmake.cxx | 209 +++++++++++++++++++++ Source/cmake.h | 14 ++ Source/cmakemain.cxx | 65 +++++++ Tests/RunCMake/CMakeLists.txt | 4 + .../DocumentationExampleListAllPresets-stdout.txt | 4 + .../CMakePresetsWorkflow/BadExitCode-result.txt | 1 + .../CMakePresetsWorkflow/BadExitCode-stderr.txt | 4 + .../CMakePresetsWorkflow/BadExitCode-stdout.txt | 17 ++ .../CMakePresetsWorkflow/BadExitCode.cmake | 8 + .../CMakePresetsWorkflow/BadExitCodeTest.cmake | 1 + .../CMakePresetsWorkflow/CMakeLists.txt.in | 3 + .../ConfigureStepMismatch-result.txt | 1 + .../ConfigureStepMismatch-stderr.txt | 2 + .../ConfigureStepMismatch.json.in | 32 ++++ .../FirstStepNotConfigure-result.txt | 0 .../FirstStepNotConfigure-stderr.txt | 2 + .../FirstStepNotConfigure.json.in | 27 +++ .../RunCMake/CMakePresetsWorkflow/Good-stdout.txt | 19 ++ Tests/RunCMake/CMakePresetsWorkflow/Good.cmake | 8 + Tests/RunCMake/CMakePresetsWorkflow/Good.json.in | 87 +++++++++ .../CMakePresetsWorkflow/GoodUser-stdout.txt | 2 + Tests/RunCMake/CMakePresetsWorkflow/GoodUser.cmake | 1 + .../RunCMake/CMakePresetsWorkflow/GoodUser.json.in | 14 ++ .../CMakePresetsWorkflow/ListPresets-stdout.txt | 4 + .../CMakePresetsWorkflow/ListPresets.json.in | 30 +++ .../NoWorkflowSteps-result.txt | 1 + .../NoWorkflowSteps-stderr.txt | 2 + .../CMakePresetsWorkflow/NoWorkflowSteps.json.in | 9 + .../NonexistentStep-result.txt | 1 + .../NonexistentStep-stderr.txt | 2 + .../CMakePresetsWorkflow/NonexistentStep.json.in | 14 ++ .../CMakePresetsWorkflow/RunCMakeTest.cmake | 79 ++++++++ .../SecondStepConfigure-result.txt | 1 + .../SecondStepConfigure-stderr.txt | 2 + .../SecondStepConfigure.json.in | 25 +++ .../UnreachableStep-result.txt | 1 + .../UnreachableStep-stderr.txt | 2 + .../CMakePresetsWorkflow/UnreachableStep.json.in | 14 ++ .../UnreachableStepUser.json.in | 8 + .../UnsupportedVersion-result.txt | 1 + .../UnsupportedVersion-stderr.txt | 2 + .../UnsupportedVersion.json.in | 4 + .../WorkflowStepDisabled-result.txt | 1 + .../WorkflowStepDisabled-stderr.txt | 2 + .../WorkflowStepDisabled.json.in | 23 +++ .../WorkflowStepHidden-result.txt | 1 + .../WorkflowStepHidden-stderr.txt | 2 + .../WorkflowStepHidden.json.in | 20 ++ .../WorkflowStepInvalidMacro-result.txt | 1 + .../WorkflowStepInvalidMacro-stderr.txt | 1 + .../WorkflowStepInvalidMacro.json.in | 20 ++ Tests/RunCMake/CMakePresetsWorkflow/check.cmake | 3 + .../CMakePresetsWorkflow/cpack_staging.cmake.in | 1 + 58 files changed, 981 insertions(+), 11 deletions(-) create mode 100644 Help/release/dev/cmake-presets-workflow.rst create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-result.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stdout.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/BadExitCode.cmake create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/BadExitCodeTest.cmake create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/CMakeLists.txt.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-result.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure-result.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/Good-stdout.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/Good.cmake create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/Good.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/GoodUser-stdout.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/GoodUser.cmake create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/GoodUser.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/ListPresets-stdout.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/ListPresets.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-result.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-result.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-result.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-result.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/UnreachableStepUser.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-result.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-result.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-result.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-result.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-stderr.txt create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro.json.in create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/check.cmake create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/cpack_staging.cmake.in diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst index d5319f2..93f929e 100644 --- a/Help/manual/cmake-presets.7.rst +++ b/Help/manual/cmake-presets.7.rst @@ -106,6 +106,10 @@ The root object recognizes the following fields: An optional array of `Package Preset`_ objects. This is allowed in preset files specifying version ``6`` or above. +``workflowPresets`` + An optional array of `Workflow Preset`_ objects. + This is allowed in preset files specifying version ``6`` or above. + Includes ^^^^^^^^ @@ -137,8 +141,8 @@ that may contain the following fields: This identifier is used in the :ref:`cmake --preset ` option. There must not be two configure presets in the union of ``CMakePresets.json`` and ``CMakeUserPresets.json`` in the same directory with the same name. - However, a configure preset may have the same name as a build, test, or - package preset. + However, a configure preset may have the same name as a build, test, + package, or workflow preset. ``hidden`` An optional boolean specifying whether or not a preset should be hidden. @@ -364,8 +368,8 @@ that may contain the following fields: :ref:`cmake --build --preset ` option. There must not be two build presets in the union of ``CMakePresets.json`` and ``CMakeUserPresets.json`` in the same directory with the same name. - However, a build preset may have the same name as a configure, test, or - package preset. + However, a build preset may have the same name as a configure, test, + package, or workflow preset. ``hidden`` An optional boolean specifying whether or not a preset should be hidden. @@ -525,8 +529,8 @@ that may contain the following fields: This identifier is used in the :option:`ctest --preset` option. There must not be two test presets in the union of ``CMakePresets.json`` and ``CMakeUserPresets.json`` in the same directory with the same name. - However, a test preset may have the same name as a configure, build, or - package preset. + However, a test preset may have the same name as a configure, build, + package, or workflow preset. ``hidden`` An optional boolean specifying whether or not a preset should be hidden. @@ -861,8 +865,8 @@ fields: This identifier is used in the :option:`cpack --preset` option. There must not be two package presets in the union of ``CMakePresets.json`` and ``CMakeUserPresets.json`` in the same directory with the same name. - However, a package preset may have the same name as a configure, build, or - test preset. + However, a package preset may have the same name as a configure, build, + test, or workflow preset. ``hidden`` An optional boolean specifying whether or not a preset should be hidden. @@ -977,6 +981,42 @@ fields: ``vendorName`` An optional string representing the vendor name. +Workflow Preset +^^^^^^^^^^^^^^^ + +Workflow presets may be used in schema version ``6`` or above. Each entry of +the ``workflowPresets`` array is a JSON object that may contain the following +fields: + +``name`` + A required string representing the machine-friendly name of the preset. + This identifier is used in the + :ref:`cmake --workflow --preset ` option. There must not be + two workflow presets in the union of ``CMakePresets.json`` and + ``CMakeUserPresets.json`` in the same directory with the same name. However, + a workflow preset may have the same name as a configure, build, test, or + package preset. + +``displayName`` + An optional string with a human-friendly name of the preset. + +``description`` + An optional string with a human-friendly description of the preset. + +``steps`` + A required array of objects describing the steps of the workflow. The first + step must be a configure preset, and all subsequent steps must be non- + configure presets whose ``configurePreset`` field matches the starting + configure preset. Each object may contain the following fields: + + ``type`` + A required string. The first step must be ``configure``. Subsequent steps + must be either ``build``, ``test``, or ``package``. + + ``name`` + A required string representing the name of the configure, build, test, or + package preset to run as this workflow step. + Condition ^^^^^^^^^ diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 98655e5..c05f3c8 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -30,6 +30,9 @@ Synopsis `Run the Find-Package Tool`_ cmake --find-package [] + `Run a Workflow Preset`_ + cmake --workflow [] + `View Help`_ cmake --help[-] @@ -1177,6 +1180,25 @@ autoconf-based projects (via ``share/aclocal/cmake.m4``). This mode is not well-supported due to some technical limitations. It is kept for compatibility but should not be used in new projects. +.. _`Workflow Mode`: + +Run a Workflow Preset +===================== + +:manual:`CMake Presets ` provides a way to execute multiple +build steps in order: + +.. option:: --preset , --preset= + + Use a workflow preset to specify a workflow. The project binary directory + is inferred from the initial configure preset. The current working directory + must contain CMake preset files. + See :manual:`preset ` for more details. + +.. option:: --list-presets + + Lists the available workflow presets. The current working directory must + contain CMake preset files. View Help ========= diff --git a/Help/manual/presets/example.json b/Help/manual/presets/example.json index 06a1112..696ab47 100644 --- a/Help/manual/presets/example.json +++ b/Help/manual/presets/example.json @@ -75,6 +75,29 @@ ] } ], + "workflowPresets": [ + { + "name": "default", + "steps": [ + { + "type": "configure", + "name": "default" + }, + { + "type": "build", + "name": "default" + }, + { + "type": "test", + "name": "default" + }, + { + "type": "package", + "name": "default" + } + ] + } + ], "vendor": { "example.com/ExampleIDE/1.0": { "autoFormat": false diff --git a/Help/manual/presets/schema.json b/Help/manual/presets/schema.json index f3a7532..b4db700 100644 --- a/Help/manual/presets/schema.json +++ b/Help/manual/presets/schema.json @@ -85,6 +85,7 @@ "buildPresets": { "$ref": "#/definitions/buildPresetsV4"}, "testPresets": { "$ref": "#/definitions/testPresetsV5"}, "packagePresets": { "$ref": "#/definitions/packagePresetsV6"}, + "workflowPresets": { "$ref": "#/definitions/workflowPresetsV6" }, "include": { "$ref": "#/definitions/include"} }, "additionalProperties": false @@ -492,7 +493,7 @@ "properties": { "name": { "type": "string", - "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, or package) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.", + "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.", "minLength": 1 }, "hidden": { @@ -744,7 +745,7 @@ "properties": { "name": { "type": "string", - "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, or package) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.", + "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.", "minLength": 1 }, "hidden": { @@ -1153,7 +1154,7 @@ "properties": { "name": { "type": "string", - "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, or package) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.", + "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.", "minLength": 1 }, "hidden": { @@ -1321,6 +1322,84 @@ "additionalProperties": false } }, + "workflowPresetsItemsV6": { + "type": "array", + "description": "An optional array of workflow preset objects. Used to execute configure, build, test, and package presets in order. Available in version 6 and higher.", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.", + "minLength": 1 + }, + "vendor": { + "type": "object", + "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field.", + "properties": {} + }, + "displayName": { + "type": "string", + "description": "An optional string with a human-friendly name of the preset." + }, + "description": { + "type": "string", + "description": "An optional string with a human-friendly description of the preset." + }, + "steps": { + "type": "array", + "description": "A required array of objects describing the steps of the workflow. The first step must be a configure preset, and all subsequent steps must be non-configure presets whose configurePreset field matches the starting configure preset.", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "A required string. The first step must be configure. Subsequent steps must be either build, test, or package.", + "enum": ["configure", "build", "test", "package"] + }, + "name": { + "type": "string", + "description": "A required string representing the name of the configure, build, test, or package preset to run as this workflow step.", + "minLength": 1 + } + }, + "required": [ + "type", + "name" + ], + "additionalProperties": false + } + } + }, + "required": [ + "name", + "steps" + ], + "additionalProperties": false + } + }, + "workflowPresetsV6": { + "type": "array", + "description": "An optional array of workflow preset objects. Used to execute configure, build, test, and package presets in order. Available in version 6 and higher.", + "allOf": [ + { "$ref": "#/definitions/workflowPresetsItemsV6" } + ], + "items": { + "type": "object", + "properties": { + "name": {}, + "vendor": {}, + "displayName": {}, + "description": {}, + "steps": {} + }, + "required": [ + "name", + "steps" + ], + "additionalProperties": false + } + }, "condition": { "anyOf": [ { diff --git a/Help/release/dev/cmake-presets-workflow.rst b/Help/release/dev/cmake-presets-workflow.rst new file mode 100644 index 0000000..db93d72 --- /dev/null +++ b/Help/release/dev/cmake-presets-workflow.rst @@ -0,0 +1,4 @@ +cmake-presets-workflow +---------------------- + +* The :manual:`cmake-presets(7)` format now supports a ``workflowPresets`` field. diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 3b105e3..7f30bb4 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -23,6 +23,10 @@ #include #include +#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32) +# include +#endif + #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" @@ -56,6 +60,7 @@ #include "cmSystemTools.h" #include "cmTarget.h" #include "cmTargetLinkLibraryType.h" +#include "cmUVProcessChain.h" #include "cmUtils.hxx" #include "cmVersionConfig.h" #include "cmWorkingDirectory.h" @@ -3665,6 +3670,210 @@ bool cmake::Open(const std::string& dir, bool dryRun) return gen->Open(dir, *cachedProjectName, dryRun); } +#if !defined(CMAKE_BOOTSTRAP) +template +const T* cmake::FindPresetForWorkflow( + cm::static_string_view type, + const std::map>& presets, + const cmCMakePresetsGraph::WorkflowPreset::WorkflowStep& step) +{ + auto it = presets.find(step.PresetName); + if (it == presets.end()) { + cmSystemTools::Error(cmStrCat("No such ", type, " preset in ", + this->GetHomeDirectory(), ": \"", + step.PresetName, '"')); + return nullptr; + } + + if (it->second.Unexpanded.Hidden) { + cmSystemTools::Error(cmStrCat("Cannot use hidden ", type, " preset in ", + this->GetHomeDirectory(), ": \"", + step.PresetName, '"')); + return nullptr; + } + + if (!it->second.Expanded) { + cmSystemTools::Error(cmStrCat("Could not evaluate ", type, " preset \"", + step.PresetName, + "\": Invalid macro expansion")); + return nullptr; + } + + if (!it->second.Expanded->ConditionResult) { + cmSystemTools::Error(cmStrCat("Cannot use disabled ", type, " preset in ", + this->GetHomeDirectory(), ": \"", + step.PresetName, '"')); + return nullptr; + } + + return &*it->second.Expanded; +} + +std::function cmake::BuildWorkflowStep( + const std::vector& args) +{ + cmUVProcessChainBuilder builder; + builder + .AddCommand(args) +# ifdef _WIN32 + .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, _fileno(stdout)) + .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, _fileno(stderr)); +# else + .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, STDOUT_FILENO) + .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, STDERR_FILENO); +# endif + return [builder]() -> int { + auto chain = builder.Start(); + chain.Wait(); + return static_cast(chain.GetStatus().front()->ExitStatus); + }; +} +#endif + +int cmake::Workflow(const std::string& presetName, bool listPresets) +{ +#ifndef CMAKE_BOOTSTRAP + this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory()); + this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory()); + + cmCMakePresetsGraph settingsFile; + auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory()); + if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) { + cmSystemTools::Error( + cmStrCat("Could not read presets from ", this->GetHomeDirectory(), ": ", + cmCMakePresetsGraph::ResultToString(result))); + return 1; + } + + if (listPresets) { + settingsFile.PrintWorkflowPresetList(); + return 0; + } + + auto presetPair = settingsFile.WorkflowPresets.find(presetName); + if (presetPair == settingsFile.WorkflowPresets.end()) { + cmSystemTools::Error(cmStrCat("No such workflow preset in ", + this->GetHomeDirectory(), ": \"", presetName, + '"')); + settingsFile.PrintWorkflowPresetList(); + return 1; + } + + if (presetPair->second.Unexpanded.Hidden) { + cmSystemTools::Error(cmStrCat("Cannot use hidden workflow preset in ", + this->GetHomeDirectory(), ": \"", presetName, + '"')); + settingsFile.PrintWorkflowPresetList(); + return 1; + } + + auto const& expandedPreset = presetPair->second.Expanded; + if (!expandedPreset) { + cmSystemTools::Error(cmStrCat("Could not evaluate workflow preset \"", + presetName, "\": Invalid macro expansion")); + settingsFile.PrintWorkflowPresetList(); + return 1; + } + + if (!expandedPreset->ConditionResult) { + cmSystemTools::Error(cmStrCat("Cannot use disabled workflow preset in ", + this->GetHomeDirectory(), ": \"", presetName, + '"')); + settingsFile.PrintWorkflowPresetList(); + return 1; + } + + struct CalculatedStep + { + int StepNumber; + cm::static_string_view Type; + std::string Name; + std::function Action; + + CalculatedStep(int stepNumber, cm::static_string_view type, + std::string name, std::function action) + : StepNumber(stepNumber) + , Type(type) + , Name(std::move(name)) + , Action(std::move(action)) + { + } + }; + + std::vector steps; + steps.reserve(expandedPreset->Steps.size()); + int stepNumber = 1; + for (auto const& step : expandedPreset->Steps) { + switch (step.PresetType) { + case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type:: + Configure: { + auto const* configurePreset = this->FindPresetForWorkflow( + "configure"_s, settingsFile.ConfigurePresets, step); + if (!configurePreset) { + return 1; + } + steps.emplace_back( + stepNumber, "configure"_s, step.PresetName, + this->BuildWorkflowStep({ cmSystemTools::GetCMakeCommand(), + "--preset", step.PresetName })); + } break; + case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Build: { + auto const* buildPreset = this->FindPresetForWorkflow( + "build"_s, settingsFile.BuildPresets, step); + if (!buildPreset) { + return 1; + } + steps.emplace_back( + stepNumber, "build"_s, step.PresetName, + this->BuildWorkflowStep({ cmSystemTools::GetCMakeCommand(), + "--build", "--preset", step.PresetName })); + } break; + case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Test: { + auto const* testPreset = this->FindPresetForWorkflow( + "test"_s, settingsFile.TestPresets, step); + if (!testPreset) { + return 1; + } + steps.emplace_back( + stepNumber, "test"_s, step.PresetName, + this->BuildWorkflowStep({ cmSystemTools::GetCTestCommand(), + "--preset", step.PresetName })); + } break; + case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Package: { + auto const* packagePreset = this->FindPresetForWorkflow( + "package"_s, settingsFile.PackagePresets, step); + if (!packagePreset) { + return 1; + } + steps.emplace_back( + stepNumber, "package"_s, step.PresetName, + this->BuildWorkflowStep({ cmSystemTools::GetCPackCommand(), + "--preset", step.PresetName })); + } break; + } + stepNumber++; + } + + int stepResult; + bool first = true; + for (auto const& step : steps) { + if (!first) { + std::cout << "\n"; + } + std::cout << "Executing workflow step " << step.StepNumber << " of " + << steps.size() << ": " << step.Type << " preset \"" << step.Name + << "\"\n\n" + << std::flush; + if ((stepResult = step.Action()) != 0) { + return stepResult; + } + first = false; + } +#endif + + return 0; +} + void cmake::WatchUnusedCli(const std::string& var) { #ifndef CMAKE_BOOTSTRAP diff --git a/Source/cmake.h b/Source/cmake.h index 8c0fece..54d0bb5 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -16,6 +16,7 @@ #include #include +#include #include "cmGeneratedFileStream.h" #include "cmInstalledFile.h" @@ -600,6 +601,9 @@ public: //! run the --open option bool Open(const std::string& dir, bool dryRun); + //! run the --workflow option + int Workflow(const std::string& presetName, bool listPresets); + void UnwatchUnusedCli(const std::string& var); void WatchUnusedCli(const std::string& var); @@ -740,6 +744,16 @@ private: void AppendExtraGeneratorsDocumentation(std::vector&); #if !defined(CMAKE_BOOTSTRAP) + template + const T* FindPresetForWorkflow( + cm::static_string_view type, + const std::map>& presets, + const cmCMakePresetsGraph::WorkflowPreset::WorkflowStep& step); + + std::function BuildWorkflowStep(const std::vector& args); +#endif + +#if !defined(CMAKE_BOOTSTRAP) std::unique_ptr ProfilingOutput; #endif }; diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 6f3d0eb..b754b72 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -911,6 +911,68 @@ int do_install(int ac, char const* const* av) #endif } +int do_workflow(int ac, char const* const* av) +{ +#ifdef CMAKE_BOOTSTRAP + std::cerr << "This cmake does not support --workflow\n"; + return -1; +#else + std::string presetName; + bool listPresets = false; + + using CommandArgument = + cmCommandLineArgument; + + std::vector arguments = { + CommandArgument{ "--preset", CommandArgument::Values::One, + CommandArgument::setToValue(presetName) }, + CommandArgument{ "--list-presets", CommandArgument::Values::Zero, + CommandArgument::setToTrue(listPresets) } + }; + + std::vector inputArgs; + + inputArgs.reserve(ac - 2); + cm::append(inputArgs, av + 2, av + ac); + + decltype(inputArgs.size()) i = 0; + for (; i < inputArgs.size(); ++i) { + std::string const& arg = inputArgs[i]; + bool matched = false; + bool parsed = false; + for (auto const& m : arguments) { + matched = m.matches(arg); + if (matched) { + parsed = m.parse(arg, i, inputArgs); + break; + } + } + if (!(matched && parsed)) { + if (!matched) { + std::cerr << "Unknown argument " << arg << std::endl; + } + break; + } + } + + if (presetName.empty() && !listPresets) { + std::cerr << "TODO: Usage\n"; + return 1; + } + + cmake cm(cmake::RoleInternal, cmState::Project); + cmSystemTools::SetMessageCallback( + [&cm](const std::string& msg, const cmMessageMetadata& md) { + cmakemainMessageCallback(msg, md, &cm); + }); + cm.SetProgressCallback([&cm](const std::string& msg, float prog) { + cmakemainProgressCallback(msg, prog, &cm); + }); + + return cm.Workflow(presetName, listPresets); +#endif +} + int do_open(int ac, char const* const* av) { #ifdef CMAKE_BOOTSTRAP @@ -980,6 +1042,9 @@ int main(int ac, char const* const* av) if (strcmp(av[1], "--open") == 0) { return do_open(ac, av); } + if (strcmp(av[1], "--workflow") == 0) { + return do_workflow(ac, av); + } if (strcmp(av[1], "-E") == 0) { return do_command(ac, av, std::move(consoleBuf)); } diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 2f5bc87..4a42bda 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -1008,6 +1008,10 @@ add_RunCMake_test(CMakePresetsPackage -DPython_EXECUTABLE=${Python_EXECUTABLE} -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA} ) +add_RunCMake_test(CMakePresetsWorkflow + -DPython_EXECUTABLE=${Python_EXECUTABLE} + -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA} + ) add_RunCMake_test(VerifyHeaderSets) diff --git a/Tests/RunCMake/CMakePresets/DocumentationExampleListAllPresets-stdout.txt b/Tests/RunCMake/CMakePresets/DocumentationExampleListAllPresets-stdout.txt index b1fcc28..57b714d 100644 --- a/Tests/RunCMake/CMakePresets/DocumentationExampleListAllPresets-stdout.txt +++ b/Tests/RunCMake/CMakePresets/DocumentationExampleListAllPresets-stdout.txt @@ -15,4 +15,8 @@ Available test presets: Available package presets: + "default" + +Available workflow presets: + "default"$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-result.txt b/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-result.txt new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-result.txt @@ -0,0 +1 @@ +8 diff --git a/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stderr.txt b/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stderr.txt new file mode 100644 index 0000000..0690c69 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stderr.txt @@ -0,0 +1,4 @@ +^Errors while running CTest +Output from these tests are in: [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode/build/Testing/Temporary/LastTest\.log +Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely\.$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stdout.txt b/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stdout.txt new file mode 100644 index 0000000..2f23f88 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode-stdout.txt @@ -0,0 +1,17 @@ +^Executing workflow step 1 of 4: configure preset "default" + +.*Testing the configure step at [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode/build.* + +Executing workflow step 2 of 4: build preset "default" + +.*Testing the build step at [^ +]*[\\/]Tests[\\/]RunCMake[\\/]CMakePresetsWorkflow[\\/]BadExitCode[\\/]build.* + +Executing workflow step 3 of 4: test preset "default" + +.*Testing the test step at [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode/build.* + +The following tests FAILED: +.* +1 - EchoTest \(Failed\)$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode.cmake b/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode.cmake new file mode 100644 index 0000000..10b46e3 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/BadExitCode.cmake @@ -0,0 +1,8 @@ +message(STATUS "Testing the configure step at ${CMAKE_BINARY_DIR}") + +add_custom_target(echo_test ALL COMMAND ${CMAKE_COMMAND} -E echo "Testing the build step at ${CMAKE_BINARY_DIR}") + +enable_testing() +add_test(NAME EchoTest COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_LIST_DIR}/BadExitCodeTest.cmake") + +include(CPack) diff --git a/Tests/RunCMake/CMakePresetsWorkflow/BadExitCodeTest.cmake b/Tests/RunCMake/CMakePresetsWorkflow/BadExitCodeTest.cmake new file mode 100644 index 0000000..59f683e --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/BadExitCodeTest.cmake @@ -0,0 +1 @@ +message(FATAL_ERROR " Testing the test step at ${CMAKE_BINARY_DIR}") diff --git a/Tests/RunCMake/CMakePresetsWorkflow/CMakeLists.txt.in b/Tests/RunCMake/CMakePresetsWorkflow/CMakeLists.txt.in new file mode 100644 index 0000000..129184a --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/CMakeLists.txt.in @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.19) +project("@CASE_NAME@" NONE) +include("@CASE_SOURCE_DIR@/@CASE_NAME@.cmake") diff --git a/Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-result.txt b/Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-stderr.txt b/Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-stderr.txt new file mode 100644 index 0000000..22ca94d --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch: Invalid workflow steps$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch.json.in b/Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch.json.in new file mode 100644 index 0000000..0864149 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/ConfigureStepMismatch.json.in @@ -0,0 +1,32 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "default" + }, + { + "name": "mismatch" + } + ], + "buildPresets": [ + { + "name": "mismatch", + "configurePreset": "mismatch" + } + ], + "workflowPresets": [ + { + "name": "default", + "steps": [ + { + "type": "configure", + "name": "default" + }, + { + "type": "build", + "name": "mismatch" + } + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure-result.txt b/Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure-result.txt new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure-stderr.txt b/Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure-stderr.txt new file mode 100644 index 0000000..cbfee5a --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure: Invalid workflow steps$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure.json.in b/Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure.json.in new file mode 100644 index 0000000..2c121a8 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/FirstStepNotConfigure.json.in @@ -0,0 +1,27 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "default", + "binaryDir": "${sourceDir}/build", + "generator": "@RunCMake_GENERATOR@" + } + ], + "buildPresets": [ + { + "name": "default", + "configurePreset": "default" + } + ], + "workflowPresets": [ + { + "name": "default", + "steps": [ + { + "type": "build", + "name": "default" + } + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/Good-stdout.txt b/Tests/RunCMake/CMakePresetsWorkflow/Good-stdout.txt new file mode 100644 index 0000000..a04d7ea --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/Good-stdout.txt @@ -0,0 +1,19 @@ +^Executing workflow step 1 of 4: configure preset "default" + +.*Testing the configure step at [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/Good/build.* + +Executing workflow step 2 of 4: build preset "default" + +.*Testing the build step at [^ +]*[\\/]Tests[\\/]RunCMake[\\/]CMakePresetsWorkflow[\\/]Good[\\/]build.* + +Executing workflow step 3 of 4: test preset "default" + +.*Testing the test step at [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/Good/build.* + +Executing workflow step 4 of 4: package preset "default" + +.*Testing the package step at [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/Good/build.* diff --git a/Tests/RunCMake/CMakePresetsWorkflow/Good.cmake b/Tests/RunCMake/CMakePresetsWorkflow/Good.cmake new file mode 100644 index 0000000..31ce7ff --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/Good.cmake @@ -0,0 +1,8 @@ +message(STATUS "Testing the configure step at ${CMAKE_BINARY_DIR}") + +add_custom_target(echo_test ALL COMMAND ${CMAKE_COMMAND} -E echo "Testing the build step at ${CMAKE_BINARY_DIR}") + +enable_testing() +add_test(NAME EchoTest COMMAND ${CMAKE_COMMAND} -E echo "Testing the test step at ${CMAKE_BINARY_DIR}") + +include(CPack) diff --git a/Tests/RunCMake/CMakePresetsWorkflow/Good.json.in b/Tests/RunCMake/CMakePresetsWorkflow/Good.json.in new file mode 100644 index 0000000..87e2936 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/Good.json.in @@ -0,0 +1,87 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "default", + "binaryDir": "${sourceDir}/build", + "generator": "@RunCMake_GENERATOR@" + } + ], + "buildPresets": [ + { + "name": "default", + "configurePreset": "default", + "configuration": "Debug" + } + ], + "testPresets": [ + { + "name": "default", + "configurePreset": "default", + "output": { + "verbosity": "verbose" + }, + "configuration": "Debug" + } + ], + "packagePresets": [ + { + "name": "default", + "configurePreset": "default", + "generators": [ + "External" + ], + "variables": { + "CPACK_EXTERNAL_PACKAGE_SCRIPT": "${sourceDir}/cpack_staging.cmake" + }, + "configurations": ["Debug"] + } + ], + "workflowPresets": [ + { + "name": "Good", + "displayName": "Good Workflow Preset", + "description": "This workflow preset works properly.", + "vendor": {}, + "steps": [ + { + "type": "configure", + "name": "default" + }, + { + "type": "build", + "name": "default" + }, + { + "type": "test", + "name": "default" + }, + { + "type": "package", + "name": "default" + } + ] + }, + { + "name": "BadExitCode", + "steps": [ + { + "type": "configure", + "name": "default" + }, + { + "type": "build", + "name": "default" + }, + { + "type": "test", + "name": "default" + }, + { + "type": "package", + "name": "default" + } + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/GoodUser-stdout.txt b/Tests/RunCMake/CMakePresetsWorkflow/GoodUser-stdout.txt new file mode 100644 index 0000000..1014915 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/GoodUser-stdout.txt @@ -0,0 +1,2 @@ +-- Testing the configure step at [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/GoodUser/build diff --git a/Tests/RunCMake/CMakePresetsWorkflow/GoodUser.cmake b/Tests/RunCMake/CMakePresetsWorkflow/GoodUser.cmake new file mode 100644 index 0000000..9143e00 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/GoodUser.cmake @@ -0,0 +1 @@ +message(STATUS "Testing the configure step at ${CMAKE_BINARY_DIR}") diff --git a/Tests/RunCMake/CMakePresetsWorkflow/GoodUser.json.in b/Tests/RunCMake/CMakePresetsWorkflow/GoodUser.json.in new file mode 100644 index 0000000..e71b4ea --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/GoodUser.json.in @@ -0,0 +1,14 @@ +{ + "version": 6, + "workflowPresets": [ + { + "name": "GoodUser", + "steps": [ + { + "type": "configure", + "name": "default" + } + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/ListPresets-stdout.txt b/Tests/RunCMake/CMakePresetsWorkflow/ListPresets-stdout.txt new file mode 100644 index 0000000..57f30a4 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/ListPresets-stdout.txt @@ -0,0 +1,4 @@ +^Available workflow presets: + + "default" + "with-description" - With Description$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/ListPresets.json.in b/Tests/RunCMake/CMakePresetsWorkflow/ListPresets.json.in new file mode 100644 index 0000000..9a7d5a6 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/ListPresets.json.in @@ -0,0 +1,30 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "default" + } + ], + "workflowPresets": [ + { + "name": "default", + "steps": [ + { + "type": "configure", + "name": "default" + } + ] + }, + { + "name": "with-description", + "displayName": "With Description", + "description": "This preset has a description.", + "steps": [ + { + "type": "configure", + "name": "default" + } + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-result.txt b/Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-stderr.txt b/Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-stderr.txt new file mode 100644 index 0000000..049ed6b --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps: Invalid workflow steps$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps.json.in b/Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps.json.in new file mode 100644 index 0000000..2757197 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/NoWorkflowSteps.json.in @@ -0,0 +1,9 @@ +{ + "version": 6, + "workflowPresets": [ + { + "name": "default", + "steps": [] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-result.txt b/Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-stderr.txt b/Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-stderr.txt new file mode 100644 index 0000000..c522b84 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep: Invalid workflow steps$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep.json.in b/Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep.json.in new file mode 100644 index 0000000..235398b --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/NonexistentStep.json.in @@ -0,0 +1,14 @@ +{ + "version": 6, + "workflowPresets": [ + { + "name": "default", + "steps": [ + { + "type": "configure", + "name": "default" + } + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsWorkflow/RunCMakeTest.cmake new file mode 100644 index 0000000..b89a11a --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/RunCMakeTest.cmake @@ -0,0 +1,79 @@ +include(RunCMake) + +# Presets do not support legacy VS generator name architecture suffix. +if(RunCMake_GENERATOR MATCHES "^(Visual Studio [0-9]+ [0-9]+) ") + set(RunCMake_GENERATOR "${CMAKE_MATCH_1}") +endif() + +function(run_cmake_workflow_presets name) + set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${name}") + set(RunCMake_TEST_BINARY_DIR "${RunCMake_TEST_SOURCE_DIR}/build") + set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}") + + set(RunCMake_TEST_NO_CLEAN TRUE) + + file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}") + + set(CASE_NAME "${name}") + set(CASE_SOURCE_DIR "${RunCMake_SOURCE_DIR}") + configure_file("${RunCMake_SOURCE_DIR}/CMakeLists.txt.in" "${RunCMake_TEST_SOURCE_DIR}/CMakeLists.txt" @ONLY) + + if(NOT CMakePresets_FILE) + set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/${name}.json.in") + endif() + if(EXISTS "${CMakePresets_FILE}") + configure_file("${CMakePresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json" @ONLY) + endif() + + if(NOT CMakeUserPresets_FILE) + set(CMakeUserPresets_FILE "${RunCMake_SOURCE_DIR}/${name}User.json.in") + endif() + if(EXISTS "${CMakeUserPresets_FILE}") + configure_file("${CMakeUserPresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" @ONLY) + endif() + + foreach(ASSET ${CMakePresets_ASSETS}) + configure_file("${RunCMake_SOURCE_DIR}/${ASSET}.in" "${RunCMake_TEST_SOURCE_DIR}/${ASSET}" @ONLY) + endforeach() + + if(EXISTS "${RunCMake_SOURCE_DIR}/${name}-check.cmake") + set(RunCMake-check-file "${name}-check.cmake") + else() + set(RunCMake-check-file "check.cmake") + endif() + + if(eq) + set(eq 0 PARENT_SCOPE) + set(preset_arg "--preset=${name}") + else() + set(eq 1 PARENT_SCOPE) + set(preset_arg "--preset" "${name}") + endif() + run_cmake_command("${name}" "${CMAKE_COMMAND}" "--workflow" ${preset_arg} ${ARGN}) +endfunction() + +set(CMakePresets_SCHEMA_EXPECTED_RESULT 1) +run_cmake_workflow_presets(UnsupportedVersion) +set(CMakePresets_SCHEMA_EXPECTED_RESULT 0) +run_cmake_workflow_presets(NoWorkflowSteps) +run_cmake_workflow_presets(FirstStepNotConfigure) +run_cmake_workflow_presets(SecondStepConfigure) +run_cmake_workflow_presets(NonexistentStep) +run_cmake_workflow_presets(UnreachableStep) +run_cmake_workflow_presets(WorkflowStepHidden) +run_cmake_workflow_presets(WorkflowStepDisabled) +run_cmake_workflow_presets(WorkflowStepInvalidMacro) +run_cmake_workflow_presets(ConfigureStepMismatch) + +set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Good.json.in") +set(CMakeUserPresets_FILE "${RunCMake_SOURCE_DIR}/GoodUser.json.in") +set(CMakePresets_ASSETS cpack_staging.cmake) +run_cmake_workflow_presets(Good) +run_cmake_workflow_presets(GoodUser) +run_cmake_workflow_presets(BadExitCode) +unset(CMakePresets_FILE) +unset(CMakeUserPresets_FILE) +unset(CMakePresets_ASSETS) + +run_cmake_workflow_presets(ListPresets --list-presets) diff --git a/Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-result.txt b/Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-stderr.txt b/Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-stderr.txt new file mode 100644 index 0000000..b0ad7d5 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure: Invalid workflow steps$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure.json.in b/Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure.json.in new file mode 100644 index 0000000..44e1582 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/SecondStepConfigure.json.in @@ -0,0 +1,25 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "default", + "binaryDir": "${sourceDir}/build", + "generator": "@RunCMake_GENERATOR@" + } + ], + "workflowPresets": [ + { + "name": "default", + "steps": [ + { + "type": "configure", + "name": "default" + }, + { + "type": "configure", + "name": "default" + } + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-result.txt b/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-stderr.txt b/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-stderr.txt new file mode 100644 index 0000000..425e719 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep: Workflow step is unreachable from preset's file$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep.json.in b/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep.json.in new file mode 100644 index 0000000..235398b --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStep.json.in @@ -0,0 +1,14 @@ +{ + "version": 6, + "workflowPresets": [ + { + "name": "default", + "steps": [ + { + "type": "configure", + "name": "default" + } + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStepUser.json.in b/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStepUser.json.in new file mode 100644 index 0000000..39b6835 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/UnreachableStepUser.json.in @@ -0,0 +1,8 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "default" + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-result.txt b/Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-stderr.txt b/Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-stderr.txt new file mode 100644 index 0000000..5cf01aa --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Could not read presets from [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion: File version must be 6 or higher for workflow preset support$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion.json.in b/Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion.json.in new file mode 100644 index 0000000..4ebaa8e --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/UnsupportedVersion.json.in @@ -0,0 +1,4 @@ +{ + "version": 5, + "workflowPresets": [] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-result.txt b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-stderr.txt b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-stderr.txt new file mode 100644 index 0000000..b598b27 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Cannot use disabled configure preset in [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled: "default"$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled.json.in b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled.json.in new file mode 100644 index 0000000..a3b6783 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepDisabled.json.in @@ -0,0 +1,23 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "default", + "condition": { + "type": "const", + "value": false + } + } + ], + "workflowPresets": [ + { + "name": "WorkflowStepDisabled", + "steps": [ + { + "type": "configure", + "name": "default" + } + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-result.txt b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-stderr.txt b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-stderr.txt new file mode 100644 index 0000000..838ded5 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden-stderr.txt @@ -0,0 +1,2 @@ +^CMake Error: Cannot use hidden configure preset in [^ +]*/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden: "default"$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden.json.in b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden.json.in new file mode 100644 index 0000000..07c4105 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepHidden.json.in @@ -0,0 +1,20 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "default", + "hidden": true + } + ], + "workflowPresets": [ + { + "name": "WorkflowStepHidden", + "steps": [ + { + "type": "configure", + "name": "default" + } + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-result.txt b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-stderr.txt b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-stderr.txt new file mode 100644 index 0000000..f132a93 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro-stderr.txt @@ -0,0 +1 @@ +^CMake Error: Could not evaluate configure preset "default": Invalid macro expansion$ diff --git a/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro.json.in b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro.json.in new file mode 100644 index 0000000..6aec0e3 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/WorkflowStepInvalidMacro.json.in @@ -0,0 +1,20 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "default", + "binaryDir": "$vendor{invalidMacro}" + } + ], + "workflowPresets": [ + { + "name": "WorkflowStepInvalidMacro", + "steps": [ + { + "type": "configure", + "name": "default" + } + ] + } + ] +} diff --git a/Tests/RunCMake/CMakePresetsWorkflow/check.cmake b/Tests/RunCMake/CMakePresetsWorkflow/check.cmake new file mode 100644 index 0000000..e79c4f1 --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/check.cmake @@ -0,0 +1,3 @@ +set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.py") +include("${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.cmake") +include("${RunCMake_SOURCE_DIR}/../CMakePresets/check.cmake") diff --git a/Tests/RunCMake/CMakePresetsWorkflow/cpack_staging.cmake.in b/Tests/RunCMake/CMakePresetsWorkflow/cpack_staging.cmake.in new file mode 100644 index 0000000..4030dfb --- /dev/null +++ b/Tests/RunCMake/CMakePresetsWorkflow/cpack_staging.cmake.in @@ -0,0 +1 @@ +message(STATUS "Testing the package step at @RunCMake_TEST_BINARY_DIR@") -- cgit v0.12