From 59681e8d7a539cae5bbeff3394ac0dc0372f1d2a Mon Sep 17 00:00:00 2001
From: alandefreitas <alandefreitas@gmail.com>
Date: Mon, 22 Jan 2024 19:00:24 -0300
Subject: [PATCH] refactor: remove cmake temp files

---
 src/lib/Lib/CMakeExecution.cpp | 77 +++++++++++++++++++++++++++++-----
 1 file changed, 67 insertions(+), 10 deletions(-)

diff --git a/src/lib/Lib/CMakeExecution.cpp b/src/lib/Lib/CMakeExecution.cpp
index c9f475793..314f64bfb 100644
--- a/src/lib/Lib/CMakeExecution.cpp
+++ b/src/lib/Lib/CMakeExecution.cpp
@@ -9,6 +9,7 @@
 //
 
 #include "lib/Lib/CMakeExecution.hpp"
+#include "lib/Support/Path.hpp"
 
 #include <llvm/Support/FileSystem.h>
 #include <llvm/Support/MemoryBuffer.h>
@@ -20,9 +21,45 @@ namespace mrdocs {
 
 namespace {
 
+class ScopedTempFile
+{
+    clang::mrdocs::SmallPathString path_;
+    bool ok_ = false;
+public:
+    ~ScopedTempFile()
+    {
+        if (ok_)
+        {
+            llvm::sys::fs::remove(path_);
+        }
+    }
+
+    ScopedTempFile(llvm::StringRef prefix, llvm::StringRef ext)
+    {
+        llvm::SmallString<128> tempPath;
+        ok_ = !llvm::sys::fs::createTemporaryFile(prefix, ext, tempPath);
+        if (ok_)
+        {
+            path_ = tempPath;
+        }
+    }
+
+    operator
+    bool() const
+    {
+        return ok_;
+    }
+
+    llvm::StringRef path() const
+    {
+        return path_;
+    }
+};
+
 Expected<std::string>
-getCmakePath() {
-    auto const path = llvm::sys::findProgramByName("cmake");
+getCmakePath()
+{
+    llvm::ErrorOr<std::string> const path = llvm::sys::findProgramByName("cmake");
     MRDOCS_CHECK(path, "CMake executable not found");
     std::optional<llvm::StringRef> const redirects[] = {llvm::StringRef(), llvm::StringRef(), llvm::StringRef()};
     std::vector<llvm::StringRef> const args = {*path, "--version"};
@@ -34,18 +71,38 @@ getCmakePath() {
 Expected<std::string>
 executeCmakeHelp(llvm::StringRef cmakePath)
 {
-    llvm::SmallString<128> outputPath;
-    MRDOCS_CHECK(!llvm::sys::fs::createTemporaryFile("cmake-help", "txt", outputPath), 
-        "Failed to create temporary file");
-    std::optional<llvm::StringRef> const redirects[] = {llvm::StringRef(), outputPath.str(), llvm::StringRef()};
+    ScopedTempFile const outputPath("cmake-help", "txt");
+    MRDOCS_CHECK(outputPath, "Failed to create temporary file");
+    ScopedTempFile const errOutputPath("cmake-help-err", "txt");
+    MRDOCS_CHECK(errOutputPath, "Failed to create temporary file");
+    std::optional<llvm::StringRef> const redirects[] = {llvm::StringRef(), outputPath.path(), errOutputPath.path()};
     std::vector<llvm::StringRef> const args = {cmakePath, "--help"};
     llvm::ArrayRef<llvm::StringRef> emptyEnv;
     int const result = llvm::sys::ExecuteAndWait(cmakePath, args, emptyEnv, redirects);
-    MRDOCS_CHECK(result == 0, "CMake execution failed when trying to get help");
-
-    auto const bufferOrError = llvm::MemoryBuffer::getFile(outputPath);
+    if (result != 0)
+    {
+        auto const bufferOrError = llvm::MemoryBuffer::getFile(errOutputPath.path());
+        MRDOCS_CHECK(bufferOrError, "CMake execution failed (no error output available)");
+        auto const bufferOrError2 = llvm::MemoryBuffer::getFile(errOutputPath.path());
+        MRDOCS_CHECK(bufferOrError2, "CMake execution failed (no error output available)");
+        // Concatenate both outputs
+        std::string output;
+        if (bufferOrError.get()->getBuffer().str().empty())
+        {
+            output = bufferOrError2.get()->getBuffer().str();
+        }
+        else if (bufferOrError2.get()->getBuffer().str().empty())
+        {
+            output = bufferOrError.get()->getBuffer().str();
+        }
+        else
+        {
+            output = bufferOrError.get()->getBuffer().str() + "\n" + bufferOrError2.get()->getBuffer().str();
+        }
+        return Unexpected(Error("CMake --help execution failed: \n" + output));
+    }
+    auto const bufferOrError = llvm::MemoryBuffer::getFile(outputPath.path());
     MRDOCS_CHECK(bufferOrError, "Failed to read CMake help output");
-
     return bufferOrError.get()->getBuffer().str();
 }