From ec80090ce347f639fc893d0f56385da3c2ad28ec Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Fri, 26 May 2023 15:52:01 -0400 Subject: cmUVProcessChain: Add option for merged output and error --- Source/cmUVProcessChain.cxx | 59 +++++++++++++++++++++------------- Source/cmUVProcessChain.h | 2 ++ Tests/CMakeLib/testUVProcessChain.cxx | 60 +++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 22 deletions(-) diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx index 5d00544..257c054 100644 --- a/Source/cmUVProcessChain.cxx +++ b/Source/cmUVProcessChain.cxx @@ -140,6 +140,12 @@ cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream( return *this; } +cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetMergedBuiltinStreams() +{ + this->MergedBuiltinStreams = true; + return this->SetBuiltinStream(Stream_OUTPUT).SetBuiltinStream(Stream_ERROR); +} + cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetWorkingDirectory( std::string dir) { @@ -181,27 +187,6 @@ bool cmUVProcessChain::InternalData::Prepare( { this->Builder = builder; - auto const& output = - this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT]; - auto& outputData = this->OutputStreamData; - switch (output.Type) { - case cmUVProcessChainBuilder::None: - outputData.Stdio.flags = UV_IGNORE; - break; - - case cmUVProcessChainBuilder::Builtin: - outputData.BuiltinStream.init(*this->Loop, 0); - outputData.Stdio.flags = - static_cast(UV_CREATE_PIPE | UV_WRITABLE_PIPE); - outputData.Stdio.data.stream = outputData.BuiltinStream; - break; - - case cmUVProcessChainBuilder::External: - outputData.Stdio.flags = UV_INHERIT_FD; - outputData.Stdio.data.fd = output.FileDescriptor; - break; - } - auto const& error = this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR]; auto& errorData = this->ErrorStreamData; @@ -231,6 +216,32 @@ bool cmUVProcessChain::InternalData::Prepare( break; } + auto const& output = + this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT]; + auto& outputData = this->OutputStreamData; + switch (output.Type) { + case cmUVProcessChainBuilder::None: + outputData.Stdio.flags = UV_IGNORE; + break; + + case cmUVProcessChainBuilder::Builtin: + if (this->Builder->MergedBuiltinStreams) { + outputData.Stdio.flags = UV_INHERIT_FD; + outputData.Stdio.data.fd = errorData.Stdio.data.fd; + } else { + outputData.BuiltinStream.init(*this->Loop, 0); + outputData.Stdio.flags = + static_cast(UV_CREATE_PIPE | UV_WRITABLE_PIPE); + outputData.Stdio.data.stream = outputData.BuiltinStream; + } + break; + + case cmUVProcessChainBuilder::External: + outputData.Stdio.flags = UV_INHERIT_FD; + outputData.Stdio.data.fd = output.FileDescriptor; + break; + } + return true; } @@ -299,7 +310,8 @@ bool cmUVProcessChain::InternalData::AddCommand( bool cmUVProcessChain::InternalData::Finish() { if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT].Type == - cmUVProcessChainBuilder::Builtin) { + cmUVProcessChainBuilder::Builtin && + !this->Builder->MergedBuiltinStreams) { this->OutputStreamData.Streambuf.open( this->OutputStreamData.BuiltinStream); } @@ -349,6 +361,9 @@ uv_loop_t& cmUVProcessChain::GetLoop() std::istream* cmUVProcessChain::OutputStream() { + if (this->Data->Builder->MergedBuiltinStreams) { + return this->Data->ErrorStreamData.GetBuiltinStream(); + } return this->Data->OutputStreamData.GetBuiltinStream(); } diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h index 44a4888..3ade3fd 100644 --- a/Source/cmUVProcessChain.h +++ b/Source/cmUVProcessChain.h @@ -30,6 +30,7 @@ public: const std::vector& arguments); cmUVProcessChainBuilder& SetNoStream(Stream stdio); cmUVProcessChainBuilder& SetBuiltinStream(Stream stdio); + cmUVProcessChainBuilder& SetMergedBuiltinStreams(); cmUVProcessChainBuilder& SetExternalStream(Stream stdio, int fd); cmUVProcessChainBuilder& SetWorkingDirectory(std::string dir); @@ -59,6 +60,7 @@ private: std::array Stdio; std::vector Processes; std::string WorkingDirectory; + bool MergedBuiltinStreams = false; }; class cmUVProcessChain diff --git a/Tests/CMakeLib/testUVProcessChain.cxx b/Tests/CMakeLib/testUVProcessChain.cxx index 05262bc..cbb4384 100644 --- a/Tests/CMakeLib/testUVProcessChain.cxx +++ b/Tests/CMakeLib/testUVProcessChain.cxx @@ -229,6 +229,61 @@ bool testUVProcessChainBuiltin(const char* helperCommand) return true; } +bool testUVProcessChainBuiltinMerged(const char* helperCommand) +{ + cmUVProcessChainBuilder builder; + std::unique_ptr chain; + builder.AddCommand({ helperCommand, "echo" }) + .AddCommand({ helperCommand, "capitalize" }) + .AddCommand({ helperCommand, "dedup" }) + .SetMergedBuiltinStreams(); + + if (!checkExecution(builder, chain)) { + return false; + } + + if (!chain->OutputStream()) { + std::cout << "OutputStream() was null, expecting not null" << std::endl; + return false; + } + if (!chain->ErrorStream()) { + std::cout << "ErrorStream() was null, expecting not null" << std::endl; + return false; + } + if (chain->OutputStream() != chain->ErrorStream()) { + std::cout << "OutputStream() and ErrorStream() expected to be the same" + << std::endl; + return false; + } + + std::string merged = getInput(*chain->OutputStream()); + auto qemuErrorPos = merged.find("qemu:"); + if (qemuErrorPos != std::string::npos) { + merged.resize(qemuErrorPos); + } + if (merged.length() != cmStrLen("HELO WRD!123") || + merged.find('1') == std::string::npos || + merged.find('2') == std::string::npos || + merged.find('3') == std::string::npos) { + std::cout << "Expected output to contain '1', '2', and '3', was \"" + << merged << "\"" << std::endl; + return false; + } + std::string output; + for (auto const& c : merged) { + if (c != '1' && c != '2' && c != '3') { + output += c; + } + } + if (output != "HELO WRD!") { + std::cout << "Output was \"" << output << "\", expected \"HELO WRD!\"" + << std::endl; + return false; + } + + return true; +} + bool testUVProcessChainExternal(const char* helperCommand) { cmUVProcessChainBuilder builder; @@ -378,6 +433,11 @@ int testUVProcessChain(int argc, char** const argv) return -1; } + if (!testUVProcessChainBuiltinMerged(argv[1])) { + std::cout << "While executing testUVProcessChainBuiltinMerged().\n"; + return -1; + } + if (!testUVProcessChainExternal(argv[1])) { std::cout << "While executing testUVProcessChainExternal().\n"; return -1; -- cgit v0.12