Browse Source

presets: Detect abnormal termination of workflow step commands

If the command for a step (cmake, ctest, or cpack) terminates abnormally,
libuv sets the exit code to 0 and reports the process termination signal
in a separate struct member. That carries through to the structure we use
to track the process and ultimately give back to the workflow step loop.
Don't rely on the exit code alone to test for failure, also check for spawning
errors and abnormal termination too.

Fixes: #27273
Craig Scott 2 months ago
parent
commit
2f653056af
2 changed files with 26 additions and 17 deletions
  1. 26 15
      Source/cmake.cxx
  2. 0 2
      Source/cmake.h

+ 26 - 15
Source/cmake.cxx

@@ -4174,19 +4174,23 @@ T const* cmake::FindPresetForWorkflow(
   return &*it->second.Expanded;
 }
 
-std::function<int()> cmake::BuildWorkflowStep(
+namespace {
+
+std::function<cmUVProcessChain::Status()> buildWorkflowStep(
   std::vector<std::string> const& args)
 {
   cmUVProcessChainBuilder builder;
   builder.AddCommand(args)
     .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, stdout)
     .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, stderr);
-  return [builder]() -> int {
+  return [builder]() -> cmUVProcessChain::Status {
     auto chain = builder.Start();
     chain.Wait();
-    return static_cast<int>(chain.GetStatus(0).ExitStatus);
+    return chain.GetStatus(0);
   };
 }
+
+}
 #endif
 
 int cmake::Workflow(std::string const& presetName,
@@ -4248,10 +4252,11 @@ int cmake::Workflow(std::string const& presetName,
     int StepNumber;
     cm::static_string_view Type;
     std::string Name;
-    std::function<int()> Action;
+    std::function<cmUVProcessChain::Status()> Action;
 
     CalculatedStep(int stepNumber, cm::static_string_view type,
-                   std::string name, std::function<int()> action)
+                   std::string name,
+                   std::function<cmUVProcessChain::Status()> action)
       : StepNumber(stepNumber)
       , Type(type)
       , Name(std::move(name))
@@ -4278,7 +4283,7 @@ int cmake::Workflow(std::string const& presetName,
           args.emplace_back("--fresh");
         }
         steps.emplace_back(stepNumber, "configure"_s, step.PresetName,
-                           this->BuildWorkflowStep(args));
+                           buildWorkflowStep(args));
       } break;
       case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Build: {
         auto const* buildPreset = this->FindPresetForWorkflow(
@@ -4288,8 +4293,8 @@ int cmake::Workflow(std::string const& presetName,
         }
         steps.emplace_back(
           stepNumber, "build"_s, step.PresetName,
-          this->BuildWorkflowStep({ cmSystemTools::GetCMakeCommand(),
-                                    "--build", "--preset", step.PresetName }));
+          buildWorkflowStep({ cmSystemTools::GetCMakeCommand(), "--build",
+                              "--preset", step.PresetName }));
       } break;
       case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Test: {
         auto const* testPreset = this->FindPresetForWorkflow(
@@ -4299,8 +4304,8 @@ int cmake::Workflow(std::string const& presetName,
         }
         steps.emplace_back(
           stepNumber, "test"_s, step.PresetName,
-          this->BuildWorkflowStep({ cmSystemTools::GetCTestCommand(),
-                                    "--preset", step.PresetName }));
+          buildWorkflowStep({ cmSystemTools::GetCTestCommand(), "--preset",
+                              step.PresetName }));
       } break;
       case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::Package: {
         auto const* packagePreset = this->FindPresetForWorkflow(
@@ -4310,14 +4315,13 @@ int cmake::Workflow(std::string const& presetName,
         }
         steps.emplace_back(
           stepNumber, "package"_s, step.PresetName,
-          this->BuildWorkflowStep({ cmSystemTools::GetCPackCommand(),
-                                    "--preset", step.PresetName }));
+          buildWorkflowStep({ cmSystemTools::GetCPackCommand(), "--preset",
+                              step.PresetName }));
       } break;
     }
     stepNumber++;
   }
 
-  int stepResult;
   bool first = true;
   for (auto const& step : steps) {
     if (!first) {
@@ -4327,8 +4331,15 @@ int cmake::Workflow(std::string const& presetName,
               << steps.size() << ": " << step.Type << " preset \"" << step.Name
               << "\"\n\n"
               << std::flush;
-    if ((stepResult = step.Action()) != 0) {
-      return stepResult;
+    cmUVProcessChain::Status const status = step.Action();
+    if (status.ExitStatus != 0) {
+      return static_cast<int>(status.ExitStatus);
+    }
+    auto const codeReasonPair = status.GetException();
+    if (codeReasonPair.first != cmUVProcessChain::ExceptionCode::None) {
+      std::cout << "Step command ended abnormally: " << codeReasonPair.second
+                << std::endl;
+      return status.SpawnResult != 0 ? status.SpawnResult : status.TermSignal;
     }
     first = false;
   }

+ 0 - 2
Source/cmake.h

@@ -910,8 +910,6 @@ private:
     cm::static_string_view type,
     std::map<std::string, cmCMakePresetsGraph::PresetPair<T>> const& presets,
     cmCMakePresetsGraph::WorkflowPreset::WorkflowStep const& step);
-
-  std::function<int()> BuildWorkflowStep(std::vector<std::string> const& args);
 #endif
 
 #if !defined(CMAKE_BOOTSTRAP)