| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file Copyright.txt or https://cmake.org/licensing for details. */ | |
| #include "cmProcessTools.h" | |
| #include <algorithm> | |
| #include <iterator> | |
| #include <ostream> | |
| #include <cm3p/uv.h> | |
| #include "cmProcessOutput.h" | |
| #include "cmUVHandlePtr.h" | |
| #include "cmUVStream.h" | |
| std::vector<cmUVProcessChain::Status> cmProcessTools::RunProcess( | |
| cmUVProcessChainBuilder& builder, OutputParser* out, OutputParser* err, | |
| Encoding encoding) | |
| { | |
| cmProcessOutput processOutput(encoding); | |
| builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT) | |
| .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR); | |
| auto chain = builder.Start(); | |
| std::string strdata; | |
| cm::uv_pipe_ptr outputPipe; | |
| outputPipe.init(chain.GetLoop(), 0); | |
| uv_pipe_open(outputPipe, chain.OutputStream()); | |
| auto outputHandle = cmUVStreamRead( | |
| outputPipe, | |
| [&out, &processOutput, &strdata](std::vector<char> data) { | |
| if (out) { | |
| processOutput.DecodeText(data.data(), data.size(), strdata, 1); | |
| if (!out->Process(strdata.c_str(), static_cast<int>(strdata.size()))) { | |
| out = nullptr; | |
| } | |
| } | |
| }, | |
| [&out]() { out = nullptr; }); | |
| cm::uv_pipe_ptr errorPipe; | |
| errorPipe.init(chain.GetLoop(), 0); | |
| uv_pipe_open(errorPipe, chain.ErrorStream()); | |
| auto errorHandle = cmUVStreamRead( | |
| errorPipe, | |
| [&err, &processOutput, &strdata](std::vector<char> data) { | |
| if (err) { | |
| processOutput.DecodeText(data.data(), data.size(), strdata, 2); | |
| if (!err->Process(strdata.c_str(), static_cast<int>(strdata.size()))) { | |
| err = nullptr; | |
| } | |
| } | |
| }, | |
| [&err]() { err = nullptr; }); | |
| while (out || err || !chain.Finished()) { | |
| uv_run(&chain.GetLoop(), UV_RUN_ONCE); | |
| } | |
| std::vector<cmUVProcessChain::Status> result; | |
| auto status = chain.GetStatus(); | |
| std::transform( | |
| status.begin(), status.end(), std::back_inserter(result), | |
| [](cmUVProcessChain::Status const* s) -> cmUVProcessChain::Status { | |
| return *s; | |
| }); | |
| return result; | |
| } | |
| cmProcessTools::LineParser::LineParser(char sep, bool ignoreCR) | |
| : Separator(sep) | |
| , IgnoreCR(ignoreCR) | |
| { | |
| } | |
| void cmProcessTools::LineParser::SetLog(std::ostream* log, char const* prefix) | |
| { | |
| this->Log = log; | |
| this->Prefix = prefix ? prefix : ""; | |
| } | |
| bool cmProcessTools::LineParser::ProcessChunk(char const* first, int length) | |
| { | |
| char const* last = first + length; | |
| for (char const* c = first; c != last; ++c) { | |
| if (*c == this->Separator || *c == '\0') { | |
| this->LineEnd = *c; | |
| // Log this line. | |
| if (this->Log && this->Prefix) { | |
| *this->Log << this->Prefix << this->Line << "\n"; | |
| } | |
| // Hand this line to the subclass implementation. | |
| if (!this->ProcessLine()) { | |
| this->Line.clear(); | |
| return false; | |
| } | |
| this->Line.clear(); | |
| } else if (*c != '\r' || !this->IgnoreCR) { | |
| // Append this character to the line under construction. | |
| this->Line.append(1, *c); | |
| } | |
| } | |
| return true; | |
| } |