From 7ecbe324b0ef02f63676f8431dbbbe8b4217f64f Mon Sep 17 00:00:00 2001
From: Kyle Edwards <kyle.edwards@kitware.com>
Date: Tue, 25 Oct 2022 11:13:35 -0400
Subject: cmake --workflow: add --fresh option

Fixes: #24073
---
 Help/manual/cmake.1.rst                             |  6 ++++++
 Source/cmake.cxx                                    | 13 ++++++++-----
 Source/cmake.h                                      |  8 +++++++-
 Source/cmakemain.cxx                                | 11 ++++++++++-
 Tests/RunCMake/CMakePresetsWorkflow/Fresh.cmake     |  4 ++++
 Tests/RunCMake/CMakePresetsWorkflow/Fresh.json.in   | 21 +++++++++++++++++++++
 .../CMakePresetsWorkflow/RunCMakeTest.cmake         | 15 ++++++++++++---
 7 files changed, 68 insertions(+), 10 deletions(-)
 create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/Fresh.cmake
 create mode 100644 Tests/RunCMake/CMakePresetsWorkflow/Fresh.json.in

diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 35bd05f..b31ad11 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -1286,6 +1286,12 @@ The options are:
   Lists the available workflow presets. The current working directory must
   contain CMake preset files.
 
+.. option:: --fresh
+
+  Perform a fresh configuration of the build tree.
+  This removes any existing ``CMakeCache.txt`` file and associated
+  ``CMakeFiles/`` directory, and recreates them from scratch.
+
 View Help
 =========
 
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 169bf9e..013a87b 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -3733,7 +3733,7 @@ std::function<int()> cmake::BuildWorkflowStep(
 #endif
 
 int cmake::Workflow(const std::string& presetName,
-                    WorkflowListPresets listPresets)
+                    WorkflowListPresets listPresets, WorkflowFresh fresh)
 {
 #ifndef CMAKE_BOOTSTRAP
   this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
@@ -3815,10 +3815,13 @@ int cmake::Workflow(const std::string& presetName,
         if (!configurePreset) {
           return 1;
         }
-        steps.emplace_back(
-          stepNumber, "configure"_s, step.PresetName,
-          this->BuildWorkflowStep({ cmSystemTools::GetCMakeCommand(),
-                                    "--preset", step.PresetName }));
+        std::vector<std::string> args{ cmSystemTools::GetCMakeCommand(),
+                                       "--preset", step.PresetName };
+        if (fresh == WorkflowFresh::Yes) {
+          args.emplace_back("--fresh");
+        }
+        steps.emplace_back(stepNumber, "configure"_s, step.PresetName,
+                           this->BuildWorkflowStep(args));
       } break;
       case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Build: {
         auto const* buildPreset = this->FindPresetForWorkflow(
diff --git a/Source/cmake.h b/Source/cmake.h
index b3b9f19..3183577 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -607,7 +607,13 @@ public:
     No,
     Yes,
   };
-  int Workflow(const std::string& presetName, WorkflowListPresets listPresets);
+  enum class WorkflowFresh
+  {
+    No,
+    Yes,
+  };
+  int Workflow(const std::string& presetName, WorkflowListPresets listPresets,
+               WorkflowFresh fresh);
 
   void UnwatchUnusedCli(const std::string& var);
   void WatchUnusedCli(const std::string& var);
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index a6938bc..723932e 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -918,8 +918,10 @@ int do_workflow(int ac, char const* const* av)
   return -1;
 #else
   using WorkflowListPresets = cmake::WorkflowListPresets;
+  using WorkflowFresh = cmake::WorkflowFresh;
   std::string presetName;
   auto listPresets = WorkflowListPresets::No;
+  auto fresh = WorkflowFresh::No;
 
   using CommandArgument =
     cmCommandLineArgument<bool(std::string const& value)>;
@@ -932,6 +934,11 @@ int do_workflow(int ac, char const* const* av)
                        listPresets = WorkflowListPresets::Yes;
                        return true;
                      } },
+    CommandArgument{ "--fresh", CommandArgument::Values::Zero,
+                     [&fresh](const std::string&) -> bool {
+                       fresh = WorkflowFresh::Yes;
+                       return true;
+                     } },
   };
 
   std::vector<std::string> inputArgs;
@@ -968,6 +975,8 @@ int do_workflow(int ac, char const* const* av)
       "Options:\n"
       "  --preset <preset> = Workflow preset to execute.\n"
       "  --list-presets    = List available workflow presets.\n"
+      "  --fresh           = Configure a fresh build tree, removing any "
+                            "existing cache file.\n"
       ;
     /* clang-format on */
     return 1;
@@ -982,7 +991,7 @@ int do_workflow(int ac, char const* const* av)
     cmakemainProgressCallback(msg, prog, &cm);
   });
 
-  return cm.Workflow(presetName, listPresets);
+  return cm.Workflow(presetName, listPresets, fresh);
 #endif
 }
 
diff --git a/Tests/RunCMake/CMakePresetsWorkflow/Fresh.cmake b/Tests/RunCMake/CMakePresetsWorkflow/Fresh.cmake
new file mode 100644
index 0000000..4cf999f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsWorkflow/Fresh.cmake
@@ -0,0 +1,4 @@
+option(FRESH_CONFIGURE "" ON)
+if(NOT FRESH_CONFIGURE)
+  message(FATAL_ERROR "FRESH_CONFIGURE is ${FRESH_CONFIGURE}, should be ON")
+endif()
diff --git a/Tests/RunCMake/CMakePresetsWorkflow/Fresh.json.in b/Tests/RunCMake/CMakePresetsWorkflow/Fresh.json.in
new file mode 100644
index 0000000..4ce0ca5
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsWorkflow/Fresh.json.in
@@ -0,0 +1,21 @@
+{
+  "version": 6,
+  "configurePresets": [
+    {
+      "name": "default",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build"
+    }
+  ],
+  "workflowPresets": [
+    {
+      "name": "Fresh",
+      "steps": [
+        {
+          "type": "configure",
+          "name": "default"
+        }
+      ]
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresetsWorkflow/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsWorkflow/RunCMakeTest.cmake
index c620595..550600a 100644
--- a/Tests/RunCMake/CMakePresetsWorkflow/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresetsWorkflow/RunCMakeTest.cmake
@@ -10,10 +10,12 @@ function(run_cmake_workflow_presets 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)
+  if(NOT RunCMake_TEST_NO_CLEAN)
+    file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
+    file(MAKE_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
+  endif()
 
-  file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
-  file(MAKE_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
+  set(RunCMake_TEST_NO_CLEAN TRUE)
 
   set(CASE_NAME "${name}")
   set(CASE_SOURCE_DIR "${RunCMake_SOURCE_DIR}")
@@ -78,3 +80,10 @@ unset(CMakePresets_ASSETS)
 
 run_cmake_workflow_presets(ListPresets --list-presets)
 run_cmake_workflow_presets(InvalidOption -DINVALID_OPTION)
+
+set(RunCMake_TEST_NO_CLEAN TRUE)
+file(REMOVE_RECURSE "${RunCMake_BINARY_DIR}/Fresh")
+file(MAKE_DIRECTORY "${RunCMake_BINARY_DIR}/Fresh/build")
+file(WRITE "${RunCMake_BINARY_DIR}/Fresh/build/CMakeCache.txt" "FRESH_CONFIGURE:BOOL=OFF\n")
+run_cmake_workflow_presets(Fresh --fresh)
+unset(RunCMake_TEST_NO_CLEAN)
-- 
cgit v0.12