/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #ifndef cmQtAutoGenerator_h #define cmQtAutoGenerator_h #include "cmConfigure.h" // IWYU pragma: keep #include "cmQtAutoGen.h" #include "cmUVHandlePtr.h" #include "cmUVSignalHackRAII.h" // IWYU pragma: keep #include "cm_uv.h" #include #include #include #include #include #include #include class cmMakefile; /// @brief Base class for QtAutoGen gernerators class cmQtAutoGenerator : public cmQtAutoGen { CM_DISABLE_COPY(cmQtAutoGenerator) public: // -- Types /// @brief Thread safe logging class Logger { public: // -- Verbosity bool Verbose() const { return this->Verbose_; } void SetVerbose(bool value); bool ColorOutput() const { return this->ColorOutput_; } void SetColorOutput(bool value); // -- Log info void Info(GeneratorT genType, std::string const& message); // -- Log warning void Warning(GeneratorT genType, std::string const& message); void WarningFile(GeneratorT genType, std::string const& filename, std::string const& message); // -- Log error void Error(GeneratorT genType, std::string const& message); void ErrorFile(GeneratorT genType, std::string const& filename, std::string const& message); void ErrorCommand(GeneratorT genType, std::string const& message, std::vector const& command, std::string const& output); private: static std::string HeadLine(std::string const& title); private: std::mutex Mutex_; bool volatile Verbose_ = false; bool volatile ColorOutput_ = false; }; /// @brief Thread safe file system interface class FileSystem { public: FileSystem(Logger* log) : Log_(log) { } Logger* Log() const { return Log_; } std::string RealPath(std::string const& filename); bool FileExists(std::string const& filename); bool FileIsOlderThan(std::string const& buildFile, std::string const& sourceFile, std::string* error = nullptr); bool FileRead(std::string& content, std::string const& filename, std::string* error = nullptr); /// @brief Error logging version bool FileRead(GeneratorT genType, std::string& content, std::string const& filename); bool FileWrite(std::string const& filename, std::string const& content, std::string* error = nullptr); /// @brief Error logging version bool FileWrite(GeneratorT genType, std::string const& filename, std::string const& content); bool FileDiffers(std::string const& filename, std::string const& content); bool FileRemove(std::string const& filename); bool Touch(std::string const& filename); bool MakeDirectory(std::string const& dirname); /// @brief Error logging version bool MakeDirectory(GeneratorT genType, std::string const& dirname); bool MakeParentDirectory(std::string const& filename); /// @brief Error logging version bool MakeParentDirectory(GeneratorT genType, std::string const& filename); private: std::mutex Mutex_; Logger* Log_; }; /// @brief Return value and output of an external process struct ProcessResultT { void reset(); bool error() const { return (ExitStatus != 0) || (TermSignal != 0) || !ErrorMessage.empty(); } std::int64_t ExitStatus = 0; int TermSignal = 0; std::string StdOut; std::string StdErr; std::string ErrorMessage; }; /// @brief External process management class struct ReadOnlyProcessT { // -- Types /// @brief libuv pipe buffer class class PipeT { public: int init(uv_loop_t* uv_loop, ReadOnlyProcessT* process); int startRead(std::string* target); void reset(); // -- Libuv casts uv_pipe_t* uv_pipe() { return UVPipe_.get(); } uv_stream_t* uv_stream() { return reinterpret_cast(uv_pipe()); } uv_handle_t* uv_handle() { return reinterpret_cast(uv_pipe()); } // -- Libuv callbacks static void UVAlloc(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf); static void UVData(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); private: ReadOnlyProcessT* Process_ = nullptr; std::string* Target_ = nullptr; std::vector Buffer_; cm::uv_pipe_ptr UVPipe_; }; /// @brief Process settings struct SetupT { std::string WorkingDirectory; std::vector Command; ProcessResultT* Result = nullptr; bool MergedOutput = false; }; // -- Constructor ReadOnlyProcessT() = default; // -- Const accessors const SetupT& Setup() const { return Setup_; } ProcessResultT* Result() const { return Setup_.Result; } bool IsStarted() const { return IsStarted_; } bool IsFinished() const { return IsFinished_; } // -- Runtime void setup(ProcessResultT* result, bool mergedOutput, std::vector const& command, std::string const& workingDirectory = std::string()); bool start(uv_loop_t* uv_loop, std::function&& finishedCallback); private: // -- Friends friend class PipeT; // -- Libuv callbacks static void UVExit(uv_process_t* handle, int64_t exitStatus, int termSignal); void UVTryFinish(); // -- Setup SetupT Setup_; // -- Runtime bool IsStarted_ = false; bool IsFinished_ = false; std::function FinishedCallback_; std::vector CommandPtr_; std::array UVOptionsStdIO_; uv_process_options_t UVOptions_; cm::uv_process_ptr UVProcess_; PipeT UVPipeOut_; PipeT UVPipeErr_; }; public: // -- Constructors cmQtAutoGenerator(); virtual ~cmQtAutoGenerator(); // -- Run bool Run(std::string const& infoFile, std::string const& config); // -- Accessors // Logging Logger& Log() { return Logger_; } // File System FileSystem& FileSys() { return FileSys_; } // InfoFile std::string const& InfoFile() const { return InfoFile_; } std::string const& InfoDir() const { return InfoDir_; } std::string const& InfoConfig() const { return InfoConfig_; } // libuv loop uv_loop_t* UVLoop() { return UVLoop_.get(); } cm::uv_async_ptr& UVRequest() { return UVRequest_; } // -- Utility static std::string SettingsFind(std::string const& content, const char* key); protected: // -- Abstract processing interface virtual bool Init(cmMakefile* makefile) = 0; virtual bool Process() = 0; private: // -- Logging Logger Logger_; FileSystem FileSys_; // -- Info settings std::string InfoFile_; std::string InfoDir_; std::string InfoConfig_; // -- libuv loop #ifdef CMAKE_UV_SIGNAL_HACK std::unique_ptr UVHackRAII_; #endif std::unique_ptr UVLoop_; cm::uv_async_ptr UVRequest_; }; #endif