diff options
74 files changed, 1052 insertions, 493 deletions
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index ba925e8..8aece23 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -262,6 +262,36 @@ Available commands are: 351abe79cd3800b38cdfb25d45015a15 file1.txt 052f86c15bbde68af55c7f7b340ab639 file2.txt +``sha1sum <file>...`` + Create SHA1 checksum of files in ``sha1sum`` compatible format:: + + 4bb7932a29e6f73c97bb9272f2bdc393122f86e0 file1.txt + 1df4c8f318665f9a5f2ed38f55adadb7ef9f559c file2.txt + +``sha224sum <file>...`` + Create SHA224 checksum of files in ``sha224sum`` compatible format:: + + b9b9346bc8437bbda630b0b7ddfc5ea9ca157546dbbf4c613192f930 file1.txt + 6dfbe55f4d2edc5fe5c9197bca51ceaaf824e48eba0cc453088aee24 file2.txt + +``sha256sum <file>...`` + Create SHA256 checksum of files in ``sha256sum`` compatible format:: + + 76713b23615d31680afeb0e9efe94d47d3d4229191198bb46d7485f9cb191acc file1.txt + 15b682ead6c12dedb1baf91231e1e89cfc7974b3787c1e2e01b986bffadae0ea file2.txt + +``sha384sum <file>...`` + Create SHA384 checksum of files in ``sha384sum`` compatible format:: + + acc049fedc091a22f5f2ce39a43b9057fd93c910e9afd76a6411a28a8f2b8a12c73d7129e292f94fc0329c309df49434 file1.txt + 668ddeb108710d271ee21c0f3acbd6a7517e2b78f9181c6a2ff3b8943af92b0195dcb7cce48aa3e17893173c0a39e23d file2.txt + +``sha512sum <file>...`` + Create SHA512 checksum of files in ``sha512sum`` compatible format:: + + 2a78d7a6c5328cfb1467c63beac8ff21794213901eaadafd48e7800289afbc08e5fb3e86aa31116c945ee3d7bf2a6194489ec6101051083d1108defc8e1dba89 file1.txt + 7a0b54896fe5e70cca6dd643ad6f672614b189bf26f8153061c4d219474b05dad08c4e729af9f4b009f1a1a280cb625454bf587c690f4617c27e3aebdf3b7a2d file2.txt + ``remove [-f] <file>...`` Remove the file(s). If any of the listed files already do not exist, the command returns a non-zero exit code, but no message diff --git a/Help/release/3.9.rst b/Help/release/3.9.rst index c31f533..14e8699 100644 --- a/Help/release/3.9.rst +++ b/Help/release/3.9.rst @@ -34,6 +34,8 @@ Generators This is an experimental feature and can be activated by setting the :variable:`CMAKE_XCODE_GENERATE_SCHEME` variable to a ``TRUE`` value. +* The :generator:`Xcode` generator now supports Xcode 9. + Commands -------- @@ -319,3 +321,8 @@ Other Changes * On macOS, ``RPATH`` settings such as :prop_tgt:`BUILD_WITH_INSTALL_RPATH` no longer affect the ``install_name`` field. See policy :policy:`CMP0068`. + +* The :generator:`Visual Studio 14 2015` generator has been taught about + a change to the ``v140`` toolset made by a VS 2015 update. VS changed + the set of values it understands for the ``GenerateDebugInformation`` + linker setting that produces the ``-DEBUG`` linker flag variants. diff --git a/Help/release/dev/cmake-command-mode-shasum.rst b/Help/release/dev/cmake-command-mode-shasum.rst new file mode 100644 index 0000000..681e0c0 --- /dev/null +++ b/Help/release/dev/cmake-command-mode-shasum.rst @@ -0,0 +1,5 @@ +cmake-command-mode-shasum +------------------------- + +* Added sha1sum, sha224sum, sha256sum, sha384sum and sha512sum + as an equivalent to existing md5sum to cmake command mode. diff --git a/Modules/FindLibXml2.cmake b/Modules/FindLibXml2.cmake index 613f927..f68628d 100644 --- a/Modules/FindLibXml2.cmake +++ b/Modules/FindLibXml2.cmake @@ -5,18 +5,37 @@ # FindLibXml2 # ----------- # -# Try to find the LibXml2 xml processing library +# Find the XML processing library (libxml2). # -# Once done this will define +# Result variables +# ^^^^^^^^^^^^^^^^ # -# :: +# This module will set the following variables in your project: # -# LIBXML2_FOUND - System has LibXml2 -# LIBXML2_INCLUDE_DIR - The LibXml2 include directory -# LIBXML2_LIBRARIES - The libraries needed to use LibXml2 -# LIBXML2_DEFINITIONS - Compiler switches required for using LibXml2 -# LIBXML2_XMLLINT_EXECUTABLE - The XML checking tool xmllint coming with LibXml2 -# LIBXML2_VERSION_STRING - the version of LibXml2 found (since CMake 2.8.8) +# ``LIBXML2_FOUND`` +# true if libxml2 headers and libraries were found +# ``LIBXML2_INCLUDE_DIR`` +# the directory containing LibXml2 headers +# ``LIBXML2_INCLUDE_DIRS`` +# list of the include directories needed to use LibXml2 +# ``LIBXML2_LIBRARIES`` +# LibXml2 libraries to be linked +# ``LIBXML2_DEFINITIONS`` +# the compiler switches required for using LibXml2 +# ``LIBXML2_XMLLINT_EXECUTABLE`` +# path to the XML checking tool xmllint coming with LibXml2 +# ``LIBXML2_VERSION_STRING`` +# the version of LibXml2 found (since CMake 2.8.8) +# +# Cache variables +# ^^^^^^^^^^^^^^^ +# +# The following cache variables may also be set: +# +# ``LIBXML2_INCLUDE_DIR`` +# the directory containing LibXml2 headers +# ``LIBXML2_LIBRARY`` +# path to the LibXml2 library # use pkg-config to get the directories and then use these values # in the find_path() and find_library() calls @@ -31,7 +50,7 @@ find_path(LIBXML2_INCLUDE_DIR NAMES libxml/xpath.h PATH_SUFFIXES libxml2 ) -find_library(LIBXML2_LIBRARIES NAMES xml2 libxml2 +find_library(LIBXML2_LIBRARY NAMES xml2 libxml2 HINTS ${PC_LIBXML_LIBDIR} ${PC_LIBXML_LIBRARY_DIRS} @@ -52,9 +71,12 @@ elseif(LIBXML2_INCLUDE_DIR AND EXISTS "${LIBXML2_INCLUDE_DIR}/libxml/xmlversion. unset(libxml2_version_str) endif() +set(LIBXML2_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIR} ${PC_LIBXML_INCLUDE_DIRS}) +set(LIBXML2_LIBRARIES ${LIBXML2_LIBRARY}) + include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 - REQUIRED_VARS LIBXML2_LIBRARIES LIBXML2_INCLUDE_DIR + REQUIRED_VARS LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR VERSION_VAR LIBXML2_VERSION_STRING) -mark_as_advanced(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARIES LIBXML2_XMLLINT_EXECUTABLE) +mark_as_advanced(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARY LIBXML2_XMLLINT_EXECUTABLE) diff --git a/Modules/Platform/GHS-MULTI-Initialize.cmake b/Modules/Platform/GHS-MULTI-Initialize.cmake index fcda6f6..bf61d7b 100644 --- a/Modules/Platform/GHS-MULTI-Initialize.cmake +++ b/Modules/Platform/GHS-MULTI-Initialize.cmake @@ -10,7 +10,7 @@ if (NOT GHS_INT_DIRECTORY) if (EXISTS ${GHS_EXPECTED_ROOT}) FILE(GLOB GHS_CANDIDATE_INT_DIRS RELATIVE ${GHS_EXPECTED_ROOT} ${GHS_EXPECTED_ROOT}/*) - string(REGEX MATCHALL "int[0-9][0-9][0-9][0-9]" GHS_CANDIDATE_INT_DIRS + string(REGEX MATCHALL "int[0-9][0-9][0-9][0-9a-z]" GHS_CANDIDATE_INT_DIRS ${GHS_CANDIDATE_INT_DIRS}) if (GHS_CANDIDATE_INT_DIRS) list(SORT GHS_CANDIDATE_INT_DIRS) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e556ca6..d35b7fb 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -1012,7 +1012,9 @@ target_link_libraries(cmake CMakeLib) if(CMake_ENABLE_SERVER_MODE) add_library(CMakeServerLib + cmConnection.h cmConnection.cxx cmFileMonitor.cxx cmFileMonitor.h + cmPipeConnection.cxx cmPipeConnection.h cmServer.cxx cmServer.h cmServerConnection.cxx cmServerConnection.h cmServerProtocol.cxx cmServerProtocol.h diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 1772ae5..1f0d469 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 9) -set(CMake_VERSION_PATCH 20170714) +set(CMake_VERSION_PATCH 20170720) #set(CMake_VERSION_RC 1) diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index 00d017e..0705460 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -6,6 +6,7 @@ #include "cmCPackComponentGroup.h" #include "cmCPackGenerator.h" #include "cmCPackLog.h" +#include "cmCryptoHash.h" #include "cmGeneratedFileStream.h" #include "cmSystemTools.h" #include "cm_sys_stat.h" @@ -527,15 +528,13 @@ int cmCPackDebGenerator::createDeb() continue; } - char md5sum[33]; - if (!cmSystemTools::ComputeFileMD5(*fileIt, md5sum)) { + std::string output = + cmSystemTools::ComputeFileHash(*fileIt, cmCryptoHash::AlgoMD5); + if (output.empty()) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem computing the md5 of " << *fileIt << std::endl); } - md5sum[32] = 0; - - std::string output(md5sum); output += " " + *fileIt + "\n"; // debian md5sums entries are like this: // 014f3604694729f3bf19263bac599765 usr/bin/ccmake diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 8d62fa1..689668d 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -13,6 +13,7 @@ #include "cmCTest.h" #include "cmCTestCurl.h" #include "cmCTestScriptHandler.h" +#include "cmCryptoHash.h" #include "cmCurl.h" #include "cmGeneratedFileStream.h" #include "cmProcessOutput.h" @@ -428,10 +429,8 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix, if (cmSystemTools::IsOn(this->GetOption("InternalTest"))) { upload_as += "bad_md5sum"; } else { - char md5[33]; - cmSystemTools::ComputeFileMD5(local_file, md5); - md5[32] = 0; - upload_as += md5; + upload_as += + cmSystemTools::ComputeFileHash(local_file, cmCryptoHash::AlgoMD5); } if (!cmSystemTools::FileExists(local_file.c_str())) { @@ -1058,9 +1057,8 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, } } - char md5sum[33]; - md5sum[32] = 0; - cmSystemTools::ComputeFileMD5(file, md5sum); + std::string md5sum = + cmSystemTools::ComputeFileHash(file, cmCryptoHash::AlgoMD5); // 1. request the buildid and check to see if the file // has already been uploaded // TODO I added support for subproject. You would need to add diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx new file mode 100644 index 0000000..00cf283 --- /dev/null +++ b/Source/cmConnection.cxx @@ -0,0 +1,158 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmConnection.h" + +#include "cmServer.h" +#include "cm_uv.h" + +#include <cassert> +#include <cstring> + +struct write_req_t +{ + uv_write_t req; + uv_buf_t buf; +}; + +void cmEventBasedConnection::on_alloc_buffer(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) +{ + (void)(handle); + char* rawBuffer = new char[suggested_size]; + *buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size)); +} + +void cmEventBasedConnection::on_read(uv_stream_t* stream, ssize_t nread, + const uv_buf_t* buf) +{ + auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data); + if (conn) { + if (nread >= 0) { + conn->ReadData(std::string(buf->base, buf->base + nread)); + } else { + conn->OnDisconnect((int)nread); + } + } + + delete[](buf->base); +} + +void cmEventBasedConnection::on_close_delete(uv_handle_t* handle) +{ + delete handle; +} + +void cmEventBasedConnection::on_close(uv_handle_t* /*handle*/) +{ +} + +void cmEventBasedConnection::on_write(uv_write_t* req, int status) +{ + (void)(status); + + // Free req and buffer + write_req_t* wr = reinterpret_cast<write_req_t*>(req); + delete[](wr->buf.base); + delete wr; +} + +void cmEventBasedConnection::on_new_connection(uv_stream_t* stream, int status) +{ + (void)(status); + auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data); + + if (conn) { + conn->Connect(stream); + } +} + +bool cmEventBasedConnection::IsOpen() const +{ + return this->WriteStream != CM_NULLPTR; +} + +void cmEventBasedConnection::WriteData(const std::string& data) +{ + assert(this->WriteStream); + + auto ds = data.size(); + + write_req_t* req = new write_req_t; + req->req.data = this; + req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds)); + memcpy(req->buf.base, data.c_str(), ds); + uv_write(reinterpret_cast<uv_write_t*>(req), + static_cast<uv_stream_t*>(this->WriteStream), &req->buf, 1, + on_write); +} + +void cmEventBasedConnection::ReadData(const std::string& data) +{ + this->RawReadBuffer += data; + if (BufferStrategy) { + std::string packet = BufferStrategy->BufferMessage(this->RawReadBuffer); + do { + ProcessRequest(packet); + packet = BufferStrategy->BufferMessage(this->RawReadBuffer); + } while (!packet.empty()); + + } else { + ProcessRequest(this->RawReadBuffer); + this->RawReadBuffer.clear(); + } +} + +cmEventBasedConnection::cmEventBasedConnection( + cmConnectionBufferStrategy* bufferStrategy) + : BufferStrategy(bufferStrategy) +{ +} + +void cmEventBasedConnection::Connect(uv_stream_t* server) +{ + (void)server; + Server->OnConnected(nullptr); +} + +void cmEventBasedConnection::OnDisconnect(int onerror) +{ + (void)onerror; + this->OnConnectionShuttingDown(); + this->Server->OnDisconnect(this); +} + +cmConnection::~cmConnection() +{ +} + +bool cmConnection::OnConnectionShuttingDown() +{ + return true; +} + +void cmConnection::SetServer(cmServerBase* s) +{ + Server = s; +} + +void cmConnection::ProcessRequest(const std::string& request) +{ + Server->ProcessRequest(this, request); +} + +bool cmConnection::OnServeStart(std::string* errString) +{ + (void)errString; + return true; +} + +bool cmEventBasedConnection::OnConnectionShuttingDown() +{ + this->WriteStream->data = nullptr; + this->ReadStream->data = nullptr; + + this->ReadStream = nullptr; + this->WriteStream = nullptr; + return true; +} diff --git a/Source/cmConnection.h b/Source/cmConnection.h new file mode 100644 index 0000000..4b8fcb3 --- /dev/null +++ b/Source/cmConnection.h @@ -0,0 +1,118 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#pragma once + +#include "cmConfigure.h" + +#include "cm_uv.h" + +#include <cstddef> +#include <memory> +#include <string> + +class cmServerBase; + +/*** + * Given a sequence of bytes with any kind of buffering, instances of this + * class arrange logical chunks according to whatever the use case is for + * the connection. + */ +class cmConnectionBufferStrategy +{ +public: + virtual ~cmConnectionBufferStrategy(); + + /*** + * Called whenever with an active raw buffer. If a logical chunk + * becomes available, that chunk is returned and that portion is + * removed from the rawBuffer + * + * @param rawBuffer in/out parameter. Receive buffer; the buffer strategy is + * free to manipulate this buffer anyway it needs to. + * + * @return Next chunk from the stream. Returns the empty string if a chunk + * isn't ready yet. Users of this interface should repeatedly call this + * function until an empty string is returned since its entirely possible + * multiple chunks come in a single raw buffer. + */ + virtual std::string BufferMessage(std::string& rawBuffer) = 0; + + /*** + * Resets the internal state of the buffering + */ + virtual void clear(); + + // TODO: There should be a callback / flag set for errors +}; + +class cmConnection +{ + CM_DISABLE_COPY(cmConnection) + +public: + cmConnection() {} + + virtual void WriteData(const std::string& data) = 0; + + virtual ~cmConnection(); + + virtual bool OnConnectionShuttingDown(); + + virtual bool IsOpen() const = 0; + + virtual void SetServer(cmServerBase* s); + + virtual void ProcessRequest(const std::string& request); + + virtual bool OnServeStart(std::string* pString); + +protected: + cmServerBase* Server = nullptr; +}; + +/*** + * Abstraction of a connection; ties in event callbacks from libuv and notifies + * the server when appropriate + */ +class cmEventBasedConnection : public cmConnection +{ + +public: + /*** + * @param bufferStrategy If no strategy is given, it will process the raw + * chunks as they come in. The connection + * owns the pointer given. + */ + cmEventBasedConnection(cmConnectionBufferStrategy* bufferStrategy = nullptr); + + virtual void Connect(uv_stream_t* server); + + virtual void ReadData(const std::string& data); + + bool IsOpen() const override; + + void WriteData(const std::string& data) override; + bool OnConnectionShuttingDown() override; + + virtual void OnDisconnect(int errorCode); + uv_stream_t* ReadStream = nullptr; + uv_stream_t* WriteStream = nullptr; + + static void on_close(uv_handle_t* handle); + static void on_close_delete(uv_handle_t* handle); + +protected: + std::string RawReadBuffer; + + std::unique_ptr<cmConnectionBufferStrategy> BufferStrategy; + + static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); + + static void on_write(uv_write_t* req, int status); + + static void on_new_connection(uv_stream_t* stream, int status); + + static void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, + uv_buf_t* buf); +}; diff --git a/Source/cmFileMonitor.cxx b/Source/cmFileMonitor.cxx index 8027535..c0401d7 100644 --- a/Source/cmFileMonitor.cxx +++ b/Source/cmFileMonitor.cxx @@ -171,7 +171,9 @@ public: { if (this->Handle) { uv_fs_event_stop(this->Handle); - uv_close(reinterpret_cast<uv_handle_t*>(this->Handle), &on_fs_close); + if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(this->Handle))) { + uv_close(reinterpret_cast<uv_handle_t*>(this->Handle), &on_fs_close); + } this->Handle = nullptr; } cmVirtualDirectoryWatcher::StopWatching(); diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 1802da4..329c7a9 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1025,12 +1025,23 @@ cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources( std::string const key = cmSystemTools::UpperCase(config); KindedSourcesMapType::iterator it = this->KindedSourcesMap.find(key); if (it != this->KindedSourcesMap.end()) { + if (!it->second.Initialized) { + std::ostringstream e; + e << "The SOURCES of \"" << this->GetName() + << "\" use a generator expression that depends on the " + "SOURCES themselves."; + this->GlobalGenerator->GetCMakeInstance()->IssueMessage( + cmake::FATAL_ERROR, e.str(), this->GetBacktrace()); + static KindedSources empty; + return empty; + } return it->second; } // Add an entry to the map for this configuration. KindedSources& files = this->KindedSourcesMap[key]; this->ComputeKindedSources(files, config); + files.Initialized = true; return files; } diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index c04d62b..52147e3 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -107,6 +107,11 @@ public: std::set<std::string> ExpectedResxHeaders; std::set<std::string> ExpectedXamlHeaders; std::set<std::string> ExpectedXamlSources; + bool Initialized; + KindedSources() + : Initialized(false) + { + } }; /** Get all sources needed for a configuration with kinds assigned. */ diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 4be3c80..071d49c 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1517,6 +1517,17 @@ void cmGlobalXCodeGenerator::AddCommandsToBuildPhase( makecmd += " all"; buildphase->AddAttribute("shellScript", this->CreateString(makecmd)); buildphase->AddAttribute("showEnvVarsInLog", this->CreateString("0")); + + cmXCodeObject* outputFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); + for (std::vector<cmCustomCommand>::const_iterator i = commands.begin(); + i != commands.end(); ++i) { + std::vector<std::string> const& outputs = i->GetOutputs(); + for (std::vector<std::string>::const_iterator j = outputs.begin(); + j != outputs.end(); ++j) { + outputFiles->AddObject(this->CreateString(*j)); + } + } + buildphase->AddAttribute("outputPaths", outputFiles); } void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( diff --git a/Source/cmPipeConnection.cxx b/Source/cmPipeConnection.cxx new file mode 100644 index 0000000..cc82438 --- /dev/null +++ b/Source/cmPipeConnection.cxx @@ -0,0 +1,80 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmPipeConnection.h" + +#include "cmConfigure.h" +#include "cmServer.h" + +cmPipeConnection::cmPipeConnection(const std::string& name, + cmConnectionBufferStrategy* bufferStrategy) + : cmEventBasedConnection(bufferStrategy) + , PipeName(name) +{ +} + +void cmPipeConnection::Connect(uv_stream_t* server) +{ + if (this->ClientPipe) { + // Accept and close all pipes but the first: + uv_pipe_t* rejectPipe = new uv_pipe_t(); + + uv_pipe_init(this->Server->GetLoop(), rejectPipe, 0); + uv_accept(server, reinterpret_cast<uv_stream_t*>(rejectPipe)); + uv_close(reinterpret_cast<uv_handle_t*>(rejectPipe), &on_close_delete); + return; + } + + this->ClientPipe = new uv_pipe_t(); + uv_pipe_init(this->Server->GetLoop(), this->ClientPipe, 0); + this->ClientPipe->data = static_cast<cmEventBasedConnection*>(this); + auto client = reinterpret_cast<uv_stream_t*>(this->ClientPipe); + if (uv_accept(server, client) != 0) { + uv_close(reinterpret_cast<uv_handle_t*>(client), &on_close_delete); + this->ClientPipe = CM_NULLPTR; + return; + } + this->ReadStream = client; + this->WriteStream = client; + + uv_read_start(this->ReadStream, on_alloc_buffer, on_read); + Server->OnConnected(this); +} + +bool cmPipeConnection::OnServeStart(std::string* errorMessage) +{ + this->ServerPipe = new uv_pipe_t(); + uv_pipe_init(this->Server->GetLoop(), this->ServerPipe, 0); + this->ServerPipe->data = static_cast<cmEventBasedConnection*>(this); + + int r; + if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) { + *errorMessage = std::string("Internal Error with ") + this->PipeName + + ": " + uv_err_name(r); + return false; + } + auto serverStream = reinterpret_cast<uv_stream_t*>(this->ServerPipe); + if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) { + *errorMessage = std::string("Internal Error listening on ") + + this->PipeName + ": " + uv_err_name(r); + return false; + } + + return cmConnection::OnServeStart(errorMessage); +} + +bool cmPipeConnection::OnConnectionShuttingDown() +{ + if (this->ClientPipe) { + uv_close(reinterpret_cast<uv_handle_t*>(this->ClientPipe), + &on_close_delete); + this->WriteStream->data = nullptr; + } + uv_close(reinterpret_cast<uv_handle_t*>(this->ServerPipe), &on_close_delete); + + this->ClientPipe = nullptr; + this->ServerPipe = nullptr; + this->WriteStream = nullptr; + this->ReadStream = nullptr; + + return cmConnection::OnConnectionShuttingDown(); +} diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h new file mode 100644 index 0000000..fea85b5 --- /dev/null +++ b/Source/cmPipeConnection.h @@ -0,0 +1,28 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#pragma once + +#include "cmConnection.h" + +#include "cm_uv.h" + +#include <string> + +class cmPipeConnection : public cmEventBasedConnection +{ +public: + cmPipeConnection(const std::string& name, + cmConnectionBufferStrategy* bufferStrategy = nullptr); + + bool OnServeStart(std::string* pString) override; + + bool OnConnectionShuttingDown() override; + + void Connect(uv_stream_t* server) override; + +private: + const std::string PipeName; + uv_pipe_t* ServerPipe = nullptr; + uv_pipe_t* ClientPipe = nullptr; +}; diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx index 5283dfc..ccb9af6 100644 --- a/Source/cmServer.cxx +++ b/Source/cmServer.cxx @@ -2,7 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmServer.h" -#include "cmServerConnection.h" +#include "cmConnection.h" +#include "cmFileMonitor.h" #include "cmServerDictionary.h" #include "cmServerProtocol.h" #include "cmSystemTools.h" @@ -14,8 +15,23 @@ #include <algorithm> #include <cassert> #include <cstdint> +#include <memory> #include <utility> +void on_signal(uv_signal_t* signal, int signum) +{ + auto conn = reinterpret_cast<cmServerBase*>(signal->data); + conn->OnSignal(signum); +} + +static void on_walk_to_shutdown(uv_handle_t* handle, void* arg) +{ + (void)arg; + if (!uv_is_closing(handle)) { + uv_close(handle, &cmEventBasedConnection::on_close); + } +} + class cmServer::DebugInfo { public: @@ -30,11 +46,10 @@ public: uint64_t StartTime; }; -cmServer::cmServer(cmServerConnection* conn, bool supportExperimental) - : Connection(conn) +cmServer::cmServer(cmConnection* conn, bool supportExperimental) + : cmServerBase(conn) , SupportExperimental(supportExperimental) { - this->Connection->SetServer(this); // Register supported protocols: this->RegisterProtocol(new cmServerProtocol1); } @@ -48,23 +63,15 @@ cmServer::~cmServer() for (cmServerProtocol* p : this->SupportedProtocols) { delete p; } - - delete this->Connection; } -void cmServer::PopOne() +void cmServer::ProcessRequest(cmConnection* connection, + const std::string& input) { - if (this->Queue.empty()) { - return; - } - Json::Reader reader; Json::Value value; - const std::string input = this->Queue.front(); - this->Queue.erase(this->Queue.begin()); - if (!reader.parse(input, value)) { - this->WriteParseError("Failed to parse JSON input."); + this->WriteParseError(connection, "Failed to parse JSON input."); return; } @@ -76,13 +83,13 @@ void cmServer::PopOne() debug->PrintStatistics = debugValue["showStats"].asBool(); } - const cmServerRequest request(this, value[kTYPE_KEY].asString(), + const cmServerRequest request(this, connection, value[kTYPE_KEY].asString(), value[kCOOKIE_KEY].asString(), value); if (request.Type == "") { cmServerResponse response(request); response.SetError("No type given in request."); - this->WriteResponse(response, nullptr); + this->WriteResponse(connection, response, nullptr); return; } @@ -91,9 +98,11 @@ void cmServer::PopOne() if (this->Protocol) { this->Protocol->CMakeInstance()->SetProgressCallback( reportProgress, const_cast<cmServerRequest*>(&request)); - this->WriteResponse(this->Protocol->Process(request), debug.get()); + this->WriteResponse(connection, this->Protocol->Process(request), + debug.get()); } else { - this->WriteResponse(this->SetProtocolVersion(request), debug.get()); + this->WriteResponse(connection, this->SetProtocolVersion(request), + debug.get()); } } @@ -115,7 +124,7 @@ void cmServer::RegisterProtocol(cmServerProtocol* protocol) } } -void cmServer::PrintHello() const +void cmServer::PrintHello(cmConnection* connection) const { Json::Value hello = Json::objectValue; hello[kTYPE_KEY] = "hello"; @@ -134,13 +143,7 @@ void cmServer::PrintHello() const protocolVersions.append(tmp); } - this->WriteJsonObject(hello, nullptr); -} - -void cmServer::QueueRequest(const std::string& request) -{ - this->Queue.push_back(request); - this->PopOne(); + this->WriteJsonObject(connection, hello, nullptr); } void cmServer::reportProgress(const char* msg, float progress, void* data) @@ -232,17 +235,26 @@ bool cmServer::Serve(std::string* errorMessage) } assert(!this->Protocol); - return Connection->ProcessEvents(errorMessage); + return cmServerBase::Serve(errorMessage); } cmFileMonitor* cmServer::FileMonitor() const { - return Connection->FileMonitor(); + return fileMonitor.get(); } void cmServer::WriteJsonObject(const Json::Value& jsonValue, const DebugInfo* debug) const { + for (auto& connection : this->Connections) { + WriteJsonObject(connection.get(), jsonValue, debug); + } +} + +void cmServer::WriteJsonObject(cmConnection* connection, + const Json::Value& jsonValue, + const DebugInfo* debug) const +{ Json::FastWriter writer; auto beforeJson = uv_hrtime(); @@ -272,7 +284,7 @@ void cmServer::WriteJsonObject(const Json::Value& jsonValue, } } - Connection->WriteData(std::string("\n") + kSTART_MAGIC + std::string("\n") + + connection->WriteData(std::string("\n") + kSTART_MAGIC + std::string("\n") + result + kEND_MAGIC + std::string("\n")); } @@ -311,7 +323,7 @@ void cmServer::WriteProgress(const cmServerRequest& request, int min, obj[kPROGRESS_MAXIMUM_KEY] = max; obj[kPROGRESS_CURRENT_KEY] = current; - this->WriteJsonObject(obj, nullptr); + this->WriteJsonObject(request.Connection, obj, nullptr); } void cmServer::WriteMessage(const cmServerRequest& request, @@ -331,10 +343,11 @@ void cmServer::WriteMessage(const cmServerRequest& request, obj[kTITLE_KEY] = title; } - WriteJsonObject(obj, nullptr); + WriteJsonObject(request.Connection, obj, nullptr); } -void cmServer::WriteParseError(const std::string& message) const +void cmServer::WriteParseError(cmConnection* connection, + const std::string& message) const { Json::Value obj = Json::objectValue; obj[kTYPE_KEY] = kERROR_TYPE; @@ -342,7 +355,7 @@ void cmServer::WriteParseError(const std::string& message) const obj[kREPLY_TO_KEY] = ""; obj[kCOOKIE_KEY] = ""; - this->WriteJsonObject(obj, nullptr); + this->WriteJsonObject(connection, obj, nullptr); } void cmServer::WriteSignal(const std::string& name, @@ -358,7 +371,8 @@ void cmServer::WriteSignal(const std::string& name, WriteJsonObject(obj, nullptr); } -void cmServer::WriteResponse(const cmServerResponse& response, +void cmServer::WriteResponse(cmConnection* connection, + const cmServerResponse& response, const DebugInfo* debug) const { assert(response.IsComplete()); @@ -371,5 +385,161 @@ void cmServer::WriteResponse(const cmServerResponse& response, obj[kERROR_MESSAGE_KEY] = response.ErrorMessage(); } - this->WriteJsonObject(obj, debug); + this->WriteJsonObject(connection, obj, debug); +} + +void cmServer::OnConnected(cmConnection* connection) +{ + PrintHello(connection); +} + +void cmServer::OnServeStart() +{ + cmServerBase::OnServeStart(); + fileMonitor = std::make_shared<cmFileMonitor>(GetLoop()); +} + +void cmServer::StartShutDown() +{ + if (fileMonitor) { + fileMonitor->StopMonitoring(); + fileMonitor.reset(); + } + cmServerBase::StartShutDown(); +} + +static void __start_thread(void* arg) +{ + auto server = reinterpret_cast<cmServerBase*>(arg); + std::string error; + server->Serve(&error); +} + +bool cmServerBase::StartServeThread() +{ + ServeThreadRunning = true; + uv_thread_create(&ServeThread, __start_thread, this); + return true; +} + +bool cmServerBase::Serve(std::string* errorMessage) +{ + errorMessage->clear(); + + uv_signal_init(&Loop, &this->SIGINTHandler); + uv_signal_init(&Loop, &this->SIGHUPHandler); + + this->SIGINTHandler.data = this; + this->SIGHUPHandler.data = this; + + uv_signal_start(&this->SIGINTHandler, &on_signal, SIGINT); + uv_signal_start(&this->SIGHUPHandler, &on_signal, SIGHUP); + + OnServeStart(); + + for (auto& connection : Connections) { + if (!connection->OnServeStart(errorMessage)) { + return false; + } + } + + if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) { + *errorMessage = "Internal Error: Event loop stopped in unclean state."; + StartShutDown(); + return false; + } + + ServeThreadRunning = false; + return true; +} + +void cmServerBase::OnConnected(cmConnection*) +{ +} + +void cmServerBase::OnDisconnect() +{ +} + +void cmServerBase::OnServeStart() +{ + uv_signal_start(&this->SIGINTHandler, &on_signal, SIGINT); + uv_signal_start(&this->SIGHUPHandler, &on_signal, SIGHUP); +} + +void cmServerBase::StartShutDown() +{ + if (!uv_is_closing((const uv_handle_t*)&this->SIGINTHandler)) { + uv_signal_stop(&this->SIGINTHandler); + } + + if (!uv_is_closing((const uv_handle_t*)&this->SIGHUPHandler)) { + uv_signal_stop(&this->SIGHUPHandler); + } + + for (auto& connection : Connections) { + connection->OnConnectionShuttingDown(); + } + Connections.clear(); + + uv_stop(&Loop); + + uv_walk(&Loop, on_walk_to_shutdown, CM_NULLPTR); + + uv_run(&Loop, UV_RUN_DEFAULT); +} + +bool cmServerBase::OnSignal(int signum) +{ + (void)signum; + StartShutDown(); + return true; +} + +cmServerBase::cmServerBase(cmConnection* connection) +{ + uv_loop_init(&Loop); + + uv_signal_init(&Loop, &this->SIGINTHandler); + uv_signal_init(&Loop, &this->SIGHUPHandler); + + this->SIGINTHandler.data = this; + this->SIGHUPHandler.data = this; + + AddNewConnection(connection); +} + +cmServerBase::~cmServerBase() +{ + + if (ServeThreadRunning) { + StartShutDown(); + uv_thread_join(&ServeThread); + } + + uv_loop_close(&Loop); +} + +void cmServerBase::AddNewConnection(cmConnection* ownedConnection) +{ + Connections.emplace_back(ownedConnection); + ownedConnection->SetServer(this); +} + +uv_loop_t* cmServerBase::GetLoop() +{ + return &Loop; +} + +void cmServerBase::OnDisconnect(cmConnection* pConnection) +{ + auto pred = [pConnection](const std::unique_ptr<cmConnection>& m) { + return m.get() == pConnection; + }; + Connections.erase( + std::remove_if(Connections.begin(), Connections.end(), pred), + Connections.end()); + if (Connections.empty()) { + StartShutDown(); + } } diff --git a/Source/cmServer.h b/Source/cmServer.h index b814050..0000704 100644 --- a/Source/cmServer.h +++ b/Source/cmServer.h @@ -7,26 +7,83 @@ #include "cm_jsoncpp_value.h" #include "cm_uv.h" +#include <memory> // IWYU pragma: keep #include <string> #include <vector> +class cmConnection; class cmFileMonitor; -class cmServerConnection; class cmServerProtocol; class cmServerRequest; class cmServerResponse; -class cmServer +/*** + * This essentially hold and manages a libuv event queue and responds to + * messages + * on any of its connections. + */ +class cmServerBase +{ +public: + cmServerBase(cmConnection* connection); + virtual ~cmServerBase(); + + virtual void AddNewConnection(cmConnection* ownedConnection); + + /*** + * The main override responsible for tailoring behavior towards + * whatever the given server is supposed to do + * + * This should almost always be called by the given connections + * directly. + * + * @param connection The connectiont the request was received on + * @param request The actual request + */ + virtual void ProcessRequest(cmConnection* connection, + const std::string& request) = 0; + virtual void OnConnected(cmConnection* connection); + virtual void OnDisconnect(); + + /*** + * Start a dedicated thread. If this is used to start the server, it will + * join on the + * servers dtor. + */ + virtual bool StartServeThread(); + virtual bool Serve(std::string* errorMessage); + + virtual void OnServeStart(); + virtual void StartShutDown(); + + virtual bool OnSignal(int signum); + uv_loop_t* GetLoop(); + + void OnDisconnect(cmConnection* pConnection); + +protected: + std::vector<std::unique_ptr<cmConnection> > Connections; + + bool ServeThreadRunning = false; + uv_thread_t ServeThread; + + uv_loop_t Loop; + + uv_signal_t SIGINTHandler; + uv_signal_t SIGHUPHandler; +}; + +class cmServer : public cmServerBase { CM_DISABLE_COPY(cmServer) public: class DebugInfo; - cmServer(cmServerConnection* conn, bool supportExperimental); - ~cmServer(); + cmServer(cmConnection* conn, bool supportExperimental); + ~cmServer() override; - bool Serve(std::string* errorMessage); + bool Serve(std::string* errorMessage) override; cmFileMonitor* FileMonitor() const; @@ -34,9 +91,20 @@ private: void RegisterProtocol(cmServerProtocol* protocol); // Callbacks from cmServerConnection: - void PopOne(); - void QueueRequest(const std::string& request); + void ProcessRequest(cmConnection* connection, + const std::string& request) override; + std::shared_ptr<cmFileMonitor> fileMonitor; + +public: + void OnServeStart() override; + + void StartShutDown() override; + +public: + void OnConnected(cmConnection* connection) override; + +private: static void reportProgress(const char* msg, float progress, void* data); static void reportMessage(const char* msg, const char* title, bool& cancel, void* data); @@ -44,36 +112,37 @@ private: // Handle requests: cmServerResponse SetProtocolVersion(const cmServerRequest& request); - void PrintHello() const; + void PrintHello(cmConnection* connection) const; // Write responses: void WriteProgress(const cmServerRequest& request, int min, int current, int max, const std::string& message) const; void WriteMessage(const cmServerRequest& request, const std::string& message, const std::string& title) const; - void WriteResponse(const cmServerResponse& response, + void WriteResponse(cmConnection* connection, + const cmServerResponse& response, const DebugInfo* debug) const; - void WriteParseError(const std::string& message) const; + void WriteParseError(cmConnection* connection, + const std::string& message) const; void WriteSignal(const std::string& name, const Json::Value& obj) const; void WriteJsonObject(Json::Value const& jsonValue, const DebugInfo* debug) const; + void WriteJsonObject(cmConnection* connection, Json::Value const& jsonValue, + const DebugInfo* debug) const; + static cmServerProtocol* FindMatchingProtocol( const std::vector<cmServerProtocol*>& protocols, int major, int minor); - cmServerConnection* Connection = nullptr; const bool SupportExperimental; cmServerProtocol* Protocol = nullptr; std::vector<cmServerProtocol*> SupportedProtocols; - std::vector<std::string> Queue; std::string DataBuffer; std::string JsonData; - uv_loop_t* Loop = nullptr; - typedef union { uv_tty_t tty; @@ -87,7 +156,6 @@ private: mutable bool Writing = false; - friend class cmServerConnection; friend class cmServerProtocol; friend class cmServerRequest; }; diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx index 36312ed..4891131 100644 --- a/Source/cmServerConnection.cxx +++ b/Source/cmServerConnection.cxx @@ -2,376 +2,123 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmServerConnection.h" -#include "cmFileMonitor.h" #include "cmServer.h" #include "cmServerDictionary.h" -#include <assert.h> -#include <string.h> - -namespace { - -struct write_req_t +cmStdIoConnection::cmStdIoConnection( + cmConnectionBufferStrategy* bufferStrategy) + : cmEventBasedConnection(bufferStrategy) + , Input() + , Output() { - uv_write_t req; - uv_buf_t buf; -}; - -void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) -{ - (void)(handle); - char* rawBuffer = new char[suggested_size]; - *buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size)); -} - -void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) -{ - auto conn = reinterpret_cast<cmServerConnection*>(stream->data); - if (nread >= 0) { - conn->ReadData(std::string(buf->base, buf->base + nread)); - } else { - conn->TriggerShutdown(); - } - - delete[](buf->base); } -void on_write(uv_write_t* req, int status) +void cmStdIoConnection::SetServer(cmServerBase* s) { - (void)(status); - auto conn = reinterpret_cast<cmServerConnection*>(req->data); - - // Free req and buffer - write_req_t* wr = reinterpret_cast<write_req_t*>(req); - delete[](wr->buf.base); - delete wr; + cmConnection::SetServer(s); - conn->ProcessNextRequest(); -} + if (uv_guess_handle(1) == UV_TTY) { + usesTty = true; -void on_new_connection(uv_stream_t* stream, int status) -{ - (void)(status); - auto conn = reinterpret_cast<cmServerConnection*>(stream->data); - conn->Connect(stream); -} + this->Input.tty = new uv_tty_t(); + uv_tty_init(this->Server->GetLoop(), this->Input.tty, 0, 1); + uv_tty_set_mode(this->Input.tty, UV_TTY_MODE_NORMAL); + this->Input.tty->data = static_cast<cmEventBasedConnection*>(this); + this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.tty); -void on_signal(uv_signal_t* signal, int signum) -{ - auto conn = reinterpret_cast<cmServerConnection*>(signal->data); - (void)(signum); - conn->TriggerShutdown(); -} + this->Output.tty = new uv_tty_t(); + uv_tty_init(this->Server->GetLoop(), this->Output.tty, 1, 0); + uv_tty_set_mode(this->Output.tty, UV_TTY_MODE_NORMAL); + this->Output.tty->data = static_cast<cmEventBasedConnection*>(this); + this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.tty); + } else { + usesTty = false; -void on_signal_close(uv_handle_t* handle) -{ - delete reinterpret_cast<uv_signal_t*>(handle); -} + this->Input.pipe = new uv_pipe_t(); + uv_pipe_init(this->Server->GetLoop(), this->Input.pipe, 0); + uv_pipe_open(this->Input.pipe, 0); + this->Input.pipe->data = static_cast<cmEventBasedConnection*>(this); + this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.pipe); -void on_pipe_close(uv_handle_t* handle) -{ - delete reinterpret_cast<uv_pipe_t*>(handle); + this->Output.pipe = new uv_pipe_t(); + uv_pipe_init(this->Server->GetLoop(), this->Output.pipe, 0); + uv_pipe_open(this->Output.pipe, 1); + this->Output.pipe->data = static_cast<cmEventBasedConnection*>(this); + this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.pipe); + } } -void on_tty_close(uv_handle_t* handle) +bool cmStdIoConnection::OnServeStart(std::string* pString) { - delete reinterpret_cast<uv_tty_t*>(handle); + uv_read_start(this->ReadStream, on_alloc_buffer, on_read); + Server->OnConnected(this); + return cmConnection::OnServeStart(pString); } -} // namespace - -class LoopGuard +bool cmStdIoConnection::OnConnectionShuttingDown() { -public: - LoopGuard(cmServerConnection* connection) - : Connection(connection) - { - this->Connection->mLoop = uv_default_loop(); - if (!this->Connection->mLoop) { - return; - } - this->Connection->mFileMonitor = - new cmFileMonitor(this->Connection->mLoop); - } - - ~LoopGuard() - { - if (!this->Connection->mLoop) { - return; - } + cmEventBasedConnection::OnConnectionShuttingDown(); - if (this->Connection->mFileMonitor) { - delete this->Connection->mFileMonitor; - } - uv_loop_close(this->Connection->mLoop); - this->Connection->mLoop = nullptr; + if (usesTty) { + uv_read_stop(reinterpret_cast<uv_stream_t*>(this->Input.tty)); + uv_close(reinterpret_cast<uv_handle_t*>(this->Input.tty), + &on_close_delete); + uv_close(reinterpret_cast<uv_handle_t*>(this->Output.tty), + &on_close_delete); + } else { + uv_close(reinterpret_cast<uv_handle_t*>(this->Input.pipe), + &on_close_delete); + uv_close(reinterpret_cast<uv_handle_t*>(this->Output.pipe), + &on_close_delete); } -private: - cmServerConnection* Connection; -}; + return true; +} -cmServerConnection::cmServerConnection() +cmServerPipeConnection::cmServerPipeConnection(const std::string& name) + : cmPipeConnection(name, new cmServerBufferStrategy) { } -cmServerConnection::~cmServerConnection() +cmServerStdIoConnection::cmServerStdIoConnection() + : cmStdIoConnection(new cmServerBufferStrategy) { } -void cmServerConnection::SetServer(cmServer* s) +cmConnectionBufferStrategy::~cmConnectionBufferStrategy() { - this->Server = s; } -bool cmServerConnection::ProcessEvents(std::string* errorMessage) +void cmConnectionBufferStrategy::clear() { - assert(this->Server); - errorMessage->clear(); - - this->RawReadBuffer.clear(); - this->RequestBuffer.clear(); - - LoopGuard guard(this); - (void)(guard); - if (!this->mLoop) { - *errorMessage = "Internal Error: Failed to create event loop."; - return false; - } - - this->SIGINTHandler = new uv_signal_t; - uv_signal_init(this->mLoop, this->SIGINTHandler); - this->SIGINTHandler->data = static_cast<void*>(this); - uv_signal_start(this->SIGINTHandler, &on_signal, SIGINT); - - this->SIGHUPHandler = new uv_signal_t; - uv_signal_init(this->mLoop, this->SIGHUPHandler); - this->SIGHUPHandler->data = static_cast<void*>(this); - uv_signal_start(this->SIGHUPHandler, &on_signal, SIGHUP); - - if (!DoSetup(errorMessage)) { - return false; - } - - if (uv_run(this->mLoop, UV_RUN_DEFAULT) != 0) { - *errorMessage = "Internal Error: Event loop stopped in unclean state."; - return false; - } - - // These need to be cleaned up by now: - assert(!this->ReadStream); - assert(!this->WriteStream); - - this->RawReadBuffer.clear(); - this->RequestBuffer.clear(); - - return true; } -void cmServerConnection::ReadData(const std::string& data) +std::string cmServerBufferStrategy::BufferMessage(std::string& RawReadBuffer) { - this->RawReadBuffer += data; - for (;;) { - auto needle = this->RawReadBuffer.find('\n'); + auto needle = RawReadBuffer.find('\n'); if (needle == std::string::npos) { - return; + return ""; } - std::string line = this->RawReadBuffer.substr(0, needle); + std::string line = RawReadBuffer.substr(0, needle); const auto ls = line.size(); if (ls > 1 && line.at(ls - 1) == '\r') { line.erase(ls - 1, 1); } - this->RawReadBuffer.erase(this->RawReadBuffer.begin(), - this->RawReadBuffer.begin() + - static_cast<long>(needle) + 1); + RawReadBuffer.erase(RawReadBuffer.begin(), + RawReadBuffer.begin() + static_cast<long>(needle) + 1); if (line == kSTART_MAGIC) { - this->RequestBuffer.clear(); + RequestBuffer.clear(); continue; } if (line == kEND_MAGIC) { - this->Server->QueueRequest(this->RequestBuffer); - this->RequestBuffer.clear(); - } else { - this->RequestBuffer += line; - this->RequestBuffer += "\n"; + std::string rtn; + rtn.swap(this->RequestBuffer); + return rtn; } - } -} -void cmServerConnection::TriggerShutdown() -{ - this->FileMonitor()->StopMonitoring(); - - uv_signal_stop(this->SIGINTHandler); - uv_signal_stop(this->SIGHUPHandler); - - uv_close(reinterpret_cast<uv_handle_t*>(this->SIGINTHandler), - &on_signal_close); // delete handle - uv_close(reinterpret_cast<uv_handle_t*>(this->SIGHUPHandler), - &on_signal_close); // delete handle - - this->SIGINTHandler = nullptr; - this->SIGHUPHandler = nullptr; - - this->TearDown(); -} - -void cmServerConnection::WriteData(const std::string& data) -{ - assert(this->WriteStream); - - auto ds = data.size(); - - write_req_t* req = new write_req_t; - req->req.data = this; - req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds)); - memcpy(req->buf.base, data.c_str(), ds); - - uv_write(reinterpret_cast<uv_write_t*>(req), - static_cast<uv_stream_t*>(this->WriteStream), &req->buf, 1, - on_write); -} - -void cmServerConnection::ProcessNextRequest() -{ - Server->PopOne(); -} - -void cmServerConnection::SendGreetings() -{ - Server->PrintHello(); -} - -cmServerStdIoConnection::cmServerStdIoConnection() -{ - this->Input.tty = nullptr; - this->Output.tty = nullptr; -} - -bool cmServerStdIoConnection::DoSetup(std::string* errorMessage) -{ - (void)(errorMessage); - - if (uv_guess_handle(1) == UV_TTY) { - usesTty = true; - this->Input.tty = new uv_tty_t; - uv_tty_init(this->Loop(), this->Input.tty, 0, 1); - uv_tty_set_mode(this->Input.tty, UV_TTY_MODE_NORMAL); - Input.tty->data = this; - this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.tty); - - this->Output.tty = new uv_tty_t; - uv_tty_init(this->Loop(), this->Output.tty, 1, 0); - uv_tty_set_mode(this->Output.tty, UV_TTY_MODE_NORMAL); - Output.tty->data = this; - this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.tty); - } else { - usesTty = false; - this->Input.pipe = new uv_pipe_t; - uv_pipe_init(this->Loop(), this->Input.pipe, 0); - uv_pipe_open(this->Input.pipe, 0); - Input.pipe->data = this; - this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.pipe); - - this->Output.pipe = new uv_pipe_t; - uv_pipe_init(this->Loop(), this->Output.pipe, 0); - uv_pipe_open(this->Output.pipe, 1); - Output.pipe->data = this; - this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.pipe); + this->RequestBuffer += line; + this->RequestBuffer += "\n"; } - - SendGreetings(); - uv_read_start(this->ReadStream, on_alloc_buffer, on_read); - - return true; -} - -void cmServerStdIoConnection::TearDown() -{ - if (usesTty) { - uv_close(reinterpret_cast<uv_handle_t*>(this->Input.tty), &on_tty_close); - uv_close(reinterpret_cast<uv_handle_t*>(this->Output.tty), &on_tty_close); - this->Input.tty = nullptr; - this->Output.tty = nullptr; - } else { - uv_close(reinterpret_cast<uv_handle_t*>(this->Input.pipe), &on_pipe_close); - uv_close(reinterpret_cast<uv_handle_t*>(this->Output.pipe), - &on_pipe_close); - this->Input.pipe = nullptr; - this->Input.pipe = nullptr; - } - this->ReadStream = nullptr; - this->WriteStream = nullptr; -} - -cmServerPipeConnection::cmServerPipeConnection(const std::string& name) - : PipeName(name) -{ -} - -bool cmServerPipeConnection::DoSetup(std::string* errorMessage) -{ - this->ServerPipe = new uv_pipe_t; - uv_pipe_init(this->Loop(), this->ServerPipe, 0); - this->ServerPipe->data = this; - - int r; - if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) { - *errorMessage = std::string("Internal Error with ") + this->PipeName + - ": " + uv_err_name(r); - return false; - } - auto serverStream = reinterpret_cast<uv_stream_t*>(this->ServerPipe); - if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) { - *errorMessage = std::string("Internal Error listening on ") + - this->PipeName + ": " + uv_err_name(r); - return false; - } - - return true; -} - -void cmServerPipeConnection::TearDown() -{ - if (this->ClientPipe) { - uv_close(reinterpret_cast<uv_handle_t*>(this->ClientPipe), &on_pipe_close); - this->WriteStream->data = nullptr; - } - uv_close(reinterpret_cast<uv_handle_t*>(this->ServerPipe), &on_pipe_close); - - this->ClientPipe = nullptr; - this->ServerPipe = nullptr; - this->WriteStream = nullptr; - this->ReadStream = nullptr; -} - -void cmServerPipeConnection::Connect(uv_stream_t* server) -{ - if (this->ClientPipe) { - // Accept and close all pipes but the first: - uv_pipe_t* rejectPipe = new uv_pipe_t; - - uv_pipe_init(this->Loop(), rejectPipe, 0); - auto rejecter = reinterpret_cast<uv_stream_t*>(rejectPipe); - uv_accept(server, rejecter); - uv_close(reinterpret_cast<uv_handle_t*>(rejecter), &on_pipe_close); - return; - } - - this->ClientPipe = new uv_pipe_t; - uv_pipe_init(this->Loop(), this->ClientPipe, 0); - this->ClientPipe->data = this; - auto client = reinterpret_cast<uv_stream_t*>(this->ClientPipe); - if (uv_accept(server, client) != 0) { - uv_close(reinterpret_cast<uv_handle_t*>(client), nullptr); - return; - } - this->ReadStream = client; - this->WriteStream = client; - - uv_read_start(this->ReadStream, on_alloc_buffer, on_read); - - this->SendGreetings(); } diff --git a/Source/cmServerConnection.h b/Source/cmServerConnection.h index b96bf3c..0804f0e 100644 --- a/Source/cmServerConnection.h +++ b/Source/cmServerConnection.h @@ -2,68 +2,46 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once -#include "cmConfigure.h" +#include "cmConnection.h" +#include "cmPipeConnection.h" #include "cm_uv.h" #include <string> -class cmFileMonitor; -class cmServer; +class cmServerBase; -class cmServerConnection +/*** + * This connection buffer strategy accepts messages in the form of + * [== "CMake Server" ==[ +{ + ... some JSON message ... +} +]== "CMake Server" ==] + * and only passes on the core json; it discards the envelope. + */ +class cmServerBufferStrategy : public cmConnectionBufferStrategy { - CM_DISABLE_COPY(cmServerConnection) - public: - cmServerConnection(); - virtual ~cmServerConnection(); - - void SetServer(cmServer* s); - - bool ProcessEvents(std::string* errorMessage); - - void ReadData(const std::string& data); - void TriggerShutdown(); - void WriteData(const std::string& data); - void ProcessNextRequest(); - - virtual void Connect(uv_stream_t* server) { (void)(server); } - - cmFileMonitor* FileMonitor() const { return this->mFileMonitor; } - -protected: - virtual bool DoSetup(std::string* errorMessage) = 0; - virtual void TearDown() = 0; - - void SendGreetings(); - - uv_loop_t* Loop() const { return mLoop; } - -protected: - std::string RawReadBuffer; - std::string RequestBuffer; - - uv_stream_t* ReadStream = nullptr; - uv_stream_t* WriteStream = nullptr; + std::string BufferMessage(std::string& rawBuffer) override; private: - uv_loop_t* mLoop = nullptr; - cmFileMonitor* mFileMonitor = nullptr; - cmServer* Server = nullptr; - uv_signal_t* SIGINTHandler = nullptr; - uv_signal_t* SIGHUPHandler = nullptr; - - friend class LoopGuard; + std::string RequestBuffer; }; -class cmServerStdIoConnection : public cmServerConnection +/*** + * Generic connection over std io interfaces -- tty + */ +class cmStdIoConnection : public cmEventBasedConnection { public: - cmServerStdIoConnection(); - bool DoSetup(std::string* errorMessage) override; + cmStdIoConnection(cmConnectionBufferStrategy* bufferStrategy); + + void SetServer(cmServerBase* s) override; + + bool OnConnectionShuttingDown() override; - void TearDown() override; + bool OnServeStart(std::string* pString) override; private: typedef union @@ -78,18 +56,18 @@ private: InOutUnion Output; }; -class cmServerPipeConnection : public cmServerConnection +/*** + * These specific connections use the cmake server + * buffering strategy. + */ +class cmServerStdIoConnection : public cmStdIoConnection { public: - cmServerPipeConnection(const std::string& name); - bool DoSetup(std::string* errorMessage) override; - - void TearDown() override; - - void Connect(uv_stream_t* server) override; + cmServerStdIoConnection(); +}; -private: - const std::string PipeName; - uv_pipe_t* ServerPipe = nullptr; - uv_pipe_t* ClientPipe = nullptr; +class cmServerPipeConnection : public cmPipeConnection +{ +public: + cmServerPipeConnection(const std::string& name); }; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index 21b69cf..8ad4916 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -128,11 +128,13 @@ void getCMakeInputs(const cmGlobalGenerator* gg, const std::string& sourceDir, } // namespace -cmServerRequest::cmServerRequest(cmServer* server, const std::string& t, - const std::string& c, const Json::Value& d) +cmServerRequest::cmServerRequest(cmServer* server, cmConnection* connection, + const std::string& t, const std::string& c, + const Json::Value& d) : Type(t) , Cookie(c) , Data(d) + , Connection(connection) , m_Server(server) { } diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h index 4e57bb6..145708c 100644 --- a/Source/cmServerProtocol.h +++ b/Source/cmServerProtocol.h @@ -11,6 +11,7 @@ #include <string> #include <utility> +class cmConnection; class cmFileMonitor; class cmServer; class cmServerRequest; @@ -52,9 +53,11 @@ public: const std::string Type; const std::string Cookie; const Json::Value Data; + cmConnection* Connection; private: - cmServerRequest(cmServer* server, const std::string& t, const std::string& c, + cmServerRequest(cmServer* server, cmConnection* connection, + const std::string& t, const std::string& c, const Json::Value& d); void ReportProgress(int min, int current, int max, diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index f7192e0..9f214c3 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -934,19 +934,17 @@ bool cmSystemTools::RenameFile(const char* oldname, const char* newname) #endif } -bool cmSystemTools::ComputeFileMD5(const std::string& source, char* md5out) +std::string cmSystemTools::ComputeFileHash(const std::string& source, + cmCryptoHash::Algo algo) { #if defined(CMAKE_BUILD_WITH_CMAKE) - cmCryptoHash md5(cmCryptoHash::AlgoMD5); - std::string const str = md5.HashFile(source); - strncpy(md5out, str.c_str(), 32); - return !str.empty(); + cmCryptoHash hash(algo); + return hash.HashFile(source); #else (void)source; - (void)md5out; - cmSystemTools::Message("md5sum not supported in bootstrapping mode", + cmSystemTools::Message("hashsum not supported in bootstrapping mode", "Error"); - return false; + return std::string(); #endif } diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 9de7967..e163c91 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" +#include "cmCryptoHash.h" #include "cmProcessOutput.h" #include "cmsys/Process.h" #include "cmsys/SystemTools.hxx" // IWYU pragma: export @@ -179,8 +180,9 @@ public: if possible). */ static bool RenameFile(const char* oldname, const char* newname); - ///! Compute the md5sum of a file - static bool ComputeFileMD5(const std::string& source, char* md5out); + ///! Compute the hash of a file + static std::string ComputeFileHash(const std::string& source, + cmCryptoHash::Algo algo); /** Compute the md5sum of a string. */ static std::string ComputeStringMD5(const std::string& input); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index d5b0861..c546c7e 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -44,6 +44,8 @@ #include <stdlib.h> #include <time.h> +class cmConnection; + int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, std::vector<std::string>::const_iterator argEnd); int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, @@ -88,6 +90,11 @@ void CMakeCommandUsage(const char* program) << " environment - display the current environment\n" << " make_directory <dir>... - create parent and <dir> directories\n" << " md5sum <file>... - create MD5 checksum of files\n" + << " sha1sum <file>... - create SHA1 checksum of files\n" + << " sha224sum <file>... - create SHA224 checksum of files\n" + << " sha256sum <file>... - create SHA256 checksum of files\n" + << " sha384sum <file>... - create SHA384 checksum of files\n" + << " sha512sum <file>... - create SHA512 checksum of files\n" << " remove [-f] <file>... - remove the file(s), use -f to force " "it\n" << " remove_directory dir - remove a directory and its contents\n" @@ -641,24 +648,28 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) // Command to calculate the md5sum of a file if (args[1] == "md5sum" && args.size() >= 3) { - char md5out[32]; - int retval = 0; - for (std::string::size_type cc = 2; cc < args.size(); cc++) { - const char* filename = args[cc].c_str(); - // Cannot compute md5sum of a directory - if (cmSystemTools::FileIsDirectory(filename)) { - std::cerr << "Error: " << filename << " is a directory" << std::endl; - retval++; - } else if (!cmSystemTools::ComputeFileMD5(filename, md5out)) { - // To mimic md5sum behavior in a shell: - std::cerr << filename << ": No such file or directory" << std::endl; - retval++; - } else { - std::cout << std::string(md5out, 32) << " " << filename - << std::endl; - } - } - return retval; + return HashSumFile(args, cmCryptoHash::AlgoMD5); + } + + // Command to calculate the sha1sum of a file + if (args[1] == "sha1sum" && args.size() >= 3) { + return HashSumFile(args, cmCryptoHash::AlgoSHA1); + } + + if (args[1] == "sha224sum" && args.size() >= 3) { + return HashSumFile(args, cmCryptoHash::AlgoSHA224); + } + + if (args[1] == "sha256sum" && args.size() >= 3) { + return HashSumFile(args, cmCryptoHash::AlgoSHA256); + } + + if (args[1] == "sha384sum" && args.size() >= 3) { + return HashSumFile(args, cmCryptoHash::AlgoSHA384); + } + + if (args[1] == "sha512sum" && args.size() >= 3) { + return HashSumFile(args, cmCryptoHash::AlgoSHA512); } // Command to change directory and run a program. @@ -1013,7 +1024,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) } } #if defined(HAVE_SERVER_MODE) && HAVE_SERVER_MODE - cmServerConnection* conn; + cmConnection* conn; if (isDebug) { conn = new cmServerStdIoConnection; } else { @@ -1074,6 +1085,33 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) return 1; } +int cmcmd::HashSumFile(std::vector<std::string>& args, cmCryptoHash::Algo algo) +{ + if (args.size() < 3) { + return -1; + } + int retval = 0; + + for (std::string::size_type cc = 2; cc < args.size(); cc++) { + const char* filename = args[cc].c_str(); + // Cannot compute sum of a directory + if (cmSystemTools::FileIsDirectory(filename)) { + std::cerr << "Error: " << filename << " is a directory" << std::endl; + retval++; + } else { + std::string value = cmSystemTools::ComputeFileHash(filename, algo); + if (value.empty()) { + // To mimic "md5sum/shasum" behavior in a shell: + std::cerr << filename << ": No such file or directory" << std::endl; + retval++; + } else { + std::cout << value << " " << filename << std::endl; + } + } + } + return retval; +} + int cmcmd::SymlinkLibrary(std::vector<std::string>& args) { int result = 0; diff --git a/Source/cmcmd.h b/Source/cmcmd.h index 929f1ae..faac1d2 100644 --- a/Source/cmcmd.h +++ b/Source/cmcmd.h @@ -4,6 +4,7 @@ #define cmcmd_h #include "cmConfigure.h" // IWYU pragma: keep +#include "cmCryptoHash.h" #include <string> #include <vector> @@ -18,6 +19,8 @@ public: static int ExecuteCMakeCommand(std::vector<std::string>&); protected: + static int HashSumFile(std::vector<std::string>& args, + cmCryptoHash::Algo algo); static int SymlinkLibrary(std::vector<std::string>& args); static int SymlinkExecutable(std::vector<std::string>& args); static bool SymlinkInternal(std::string const& file, diff --git a/Templates/TestDriver.cxx.in b/Templates/TestDriver.cxx.in index 0d3f44f..bf61be4 100644 --- a/Templates/TestDriver.cxx.in +++ b/Templates/TestDriver.cxx.in @@ -32,8 +32,8 @@ static functionMapEntry cmakeGeneratedFunctionMapEntries[] = { { NULL, NULL } /* NOLINT */ }; -static const int NumTests = - (sizeof(cmakeGeneratedFunctionMapEntries) / sizeof(functionMapEntry)) - 1; +static const int NumTests = CM_CAST(int, + sizeof(cmakeGeneratedFunctionMapEntries) / sizeof(functionMapEntry)) - 1; /* Allocate and create a lowercased copy of string (note that it has to be free'd manually) */ diff --git a/Tests/RunCMake/CommandLine/E_md5sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_md5sum-dir-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_md5sum-dir-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_md5sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_md5sum-dir-stderr.txt new file mode 100644 index 0000000..061fd64 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_md5sum-dir-stderr.txt @@ -0,0 +1 @@ +Error: . is a directory diff --git a/Tests/RunCMake/CommandLine/E_md5sum-mixed-result.txt b/Tests/RunCMake/CommandLine/E_md5sum-mixed-result.txt new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_md5sum-mixed-result.txt @@ -0,0 +1 @@ +2 diff --git a/Tests/RunCMake/CommandLine/E_md5sum-mixed-stderr.txt b/Tests/RunCMake/CommandLine/E_md5sum-mixed-stderr.txt new file mode 100644 index 0000000..b6b84c3 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_md5sum-mixed-stderr.txt @@ -0,0 +1,2 @@ +Error: . is a directory +nonexisting: No such file or directory diff --git a/Tests/RunCMake/CommandLine/E_md5sum-mixed-stdout.txt b/Tests/RunCMake/CommandLine/E_md5sum-mixed-stdout.txt new file mode 100644 index 0000000..18e49be --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_md5sum-mixed-stdout.txt @@ -0,0 +1 @@ +275876e34cf609db118f3d84b799a790 ../dummy diff --git a/Tests/RunCMake/CommandLine/E_md5sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_md5sum-no-file-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_md5sum-no-file-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_md5sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_md5sum-no-file-stderr.txt new file mode 100644 index 0000000..732e8c4 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_md5sum-no-file-stderr.txt @@ -0,0 +1 @@ +nonexisting: No such file or directory diff --git a/Tests/RunCMake/CommandLine/E_md5sum-result.txt b/Tests/RunCMake/CommandLine/E_md5sum-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_md5sum-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CommandLine/E_md5sum-stdout.txt b/Tests/RunCMake/CommandLine/E_md5sum-stdout.txt new file mode 100644 index 0000000..18e49be --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_md5sum-stdout.txt @@ -0,0 +1 @@ +275876e34cf609db118f3d84b799a790 ../dummy diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_sha1sum-dir-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha1sum-dir-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_sha1sum-dir-stderr.txt new file mode 100644 index 0000000..061fd64 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha1sum-dir-stderr.txt @@ -0,0 +1 @@ +Error: . is a directory diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_sha1sum-no-file-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha1sum-no-file-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_sha1sum-no-file-stderr.txt new file mode 100644 index 0000000..732e8c4 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha1sum-no-file-stderr.txt @@ -0,0 +1 @@ +nonexisting: No such file or directory diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-result.txt b/Tests/RunCMake/CommandLine/E_sha1sum-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha1sum-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-stdout.txt b/Tests/RunCMake/CommandLine/E_sha1sum-stdout.txt new file mode 100644 index 0000000..689b85b --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha1sum-stdout.txt @@ -0,0 +1 @@ +829c3804401b0727f70f73d4415e162400cbe57b ../dummy diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_sha224sum-dir-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha224sum-dir-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_sha224sum-dir-stderr.txt new file mode 100644 index 0000000..061fd64 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha224sum-dir-stderr.txt @@ -0,0 +1 @@ +Error: . is a directory diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_sha224sum-no-file-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha224sum-no-file-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_sha224sum-no-file-stderr.txt new file mode 100644 index 0000000..732e8c4 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha224sum-no-file-stderr.txt @@ -0,0 +1 @@ +nonexisting: No such file or directory diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-result.txt b/Tests/RunCMake/CommandLine/E_sha224sum-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha224sum-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-stdout.txt b/Tests/RunCMake/CommandLine/E_sha224sum-stdout.txt new file mode 100644 index 0000000..5b3e217 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha224sum-stdout.txt @@ -0,0 +1 @@ +37d32c6dbabed711cb1d4620b64090fef0ef63ab16a4a51d668259e6 ../dummy diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_sha256sum-dir-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha256sum-dir-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_sha256sum-dir-stderr.txt new file mode 100644 index 0000000..061fd64 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha256sum-dir-stderr.txt @@ -0,0 +1 @@ +Error: . is a directory diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_sha256sum-no-file-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha256sum-no-file-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_sha256sum-no-file-stderr.txt new file mode 100644 index 0000000..732e8c4 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha256sum-no-file-stderr.txt @@ -0,0 +1 @@ +nonexisting: No such file or directory diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-result.txt b/Tests/RunCMake/CommandLine/E_sha256sum-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha256sum-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-stdout.txt b/Tests/RunCMake/CommandLine/E_sha256sum-stdout.txt new file mode 100644 index 0000000..9a18770 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha256sum-stdout.txt @@ -0,0 +1 @@ +b5a2c96250612366ea272ffac6d9744aaf4b45aacd96aa7cfcb931ee3b558259 ../dummy diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_sha384sum-dir-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha384sum-dir-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_sha384sum-dir-stderr.txt new file mode 100644 index 0000000..061fd64 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha384sum-dir-stderr.txt @@ -0,0 +1 @@ +Error: . is a directory diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_sha384sum-no-file-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha384sum-no-file-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_sha384sum-no-file-stderr.txt new file mode 100644 index 0000000..732e8c4 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha384sum-no-file-stderr.txt @@ -0,0 +1 @@ +nonexisting: No such file or directory diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-result.txt b/Tests/RunCMake/CommandLine/E_sha384sum-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha384sum-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-stdout.txt b/Tests/RunCMake/CommandLine/E_sha384sum-stdout.txt new file mode 100644 index 0000000..b706ac5 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha384sum-stdout.txt @@ -0,0 +1 @@ +43c1835ceba2e29596f05e3859d4fe2b6d124a181ed670f68e914bd3ed251b02b4be609608a13f23ec3d98da6c4eb8cd ../dummy diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_sha512sum-dir-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha512sum-dir-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_sha512sum-dir-stderr.txt new file mode 100644 index 0000000..061fd64 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha512sum-dir-stderr.txt @@ -0,0 +1 @@ +Error: . is a directory diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_sha512sum-no-file-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha512sum-no-file-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_sha512sum-no-file-stderr.txt new file mode 100644 index 0000000..732e8c4 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha512sum-no-file-stderr.txt @@ -0,0 +1 @@ +nonexisting: No such file or directory diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-result.txt b/Tests/RunCMake/CommandLine/E_sha512sum-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha512sum-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-stdout.txt b/Tests/RunCMake/CommandLine/E_sha512sum-stdout.txt new file mode 100644 index 0000000..4305383 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_sha512sum-stdout.txt @@ -0,0 +1 @@ +1692526aab84461a8aebcefddcba2b33fb5897ab180c53e8b345ae125484d0aaa35baf60487050be21ed8909a48eace93851bf139087ce1f7a87d97b6120a651 ../dummy diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index f94b10a..6efcc12 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -172,6 +172,30 @@ run_cmake_command(E_env-bad-arg1 ${CMAKE_COMMAND} -E env -bad-arg1) run_cmake_command(E_env-set ${CMAKE_COMMAND} -E env TEST_ENV=1 ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-set.cmake) run_cmake_command(E_env-unset ${CMAKE_COMMAND} -E env TEST_ENV=1 ${CMAKE_COMMAND} -E env --unset=TEST_ENV ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-unset.cmake) +run_cmake_command(E_md5sum-dir ${CMAKE_COMMAND} -E md5sum .) +run_cmake_command(E_sha1sum-dir ${CMAKE_COMMAND} -E sha1sum .) +run_cmake_command(E_sha224sum-dir ${CMAKE_COMMAND} -E sha224sum .) +run_cmake_command(E_sha256sum-dir ${CMAKE_COMMAND} -E sha256sum .) +run_cmake_command(E_sha384sum-dir ${CMAKE_COMMAND} -E sha384sum .) +run_cmake_command(E_sha512sum-dir ${CMAKE_COMMAND} -E sha512sum .) + +run_cmake_command(E_md5sum-no-file ${CMAKE_COMMAND} -E md5sum nonexisting) +run_cmake_command(E_sha1sum-no-file ${CMAKE_COMMAND} -E sha1sum nonexisting) +run_cmake_command(E_sha224sum-no-file ${CMAKE_COMMAND} -E sha224sum nonexisting) +run_cmake_command(E_sha256sum-no-file ${CMAKE_COMMAND} -E sha256sum nonexisting) +run_cmake_command(E_sha384sum-no-file ${CMAKE_COMMAND} -E sha384sum nonexisting) +run_cmake_command(E_sha512sum-no-file ${CMAKE_COMMAND} -E sha512sum nonexisting) + +file(WRITE "${RunCMake_BINARY_DIR}/dummy" "dummy") +run_cmake_command(E_md5sum ${CMAKE_COMMAND} -E md5sum ../dummy) +run_cmake_command(E_md5sum-mixed ${CMAKE_COMMAND} -E md5sum . ../dummy nonexisting) +run_cmake_command(E_sha1sum ${CMAKE_COMMAND} -E sha1sum ../dummy) +run_cmake_command(E_sha224sum ${CMAKE_COMMAND} -E sha224sum ../dummy) +run_cmake_command(E_sha256sum ${CMAKE_COMMAND} -E sha256sum ../dummy) +run_cmake_command(E_sha384sum ${CMAKE_COMMAND} -E sha384sum ../dummy) +run_cmake_command(E_sha512sum ${CMAKE_COMMAND} -E sha512sum ../dummy) +file(REMOVE "${RunCMake_BINARY_DIR}/dummy") + set(RunCMake_DEFAULT_stderr ".") run_cmake_command(E_sleep-no-args ${CMAKE_COMMAND} -E sleep) unset(RunCMake_DEFAULT_stderr) diff --git a/Tests/RunCMake/ObjectLibrary/OwnSources-result.txt b/Tests/RunCMake/ObjectLibrary/OwnSources-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/OwnSources-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt b/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt new file mode 100644 index 0000000..40d650e --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error at OwnSources.cmake:[0-9]+ \(add_library\): + The SOURCES of "A" use a generator expression that depends on the SOURCES + themselves. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/ObjectLibrary/OwnSources.cmake b/Tests/RunCMake/ObjectLibrary/OwnSources.cmake new file mode 100644 index 0000000..e7bdf8d --- /dev/null +++ b/Tests/RunCMake/ObjectLibrary/OwnSources.cmake @@ -0,0 +1,2 @@ +add_library(A OBJECT a.c) +target_sources(A PRIVATE $<TARGET_OBJECTS:A>) diff --git a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake index fe708ce..b8eed73 100644 --- a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake +++ b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake @@ -19,6 +19,7 @@ run_cmake(LinkObjRHS1) run_cmake(LinkObjRHS2) run_cmake(MissingSource) run_cmake(ObjWithObj) +run_cmake(OwnSources) run_cmake(PostBuild) run_cmake(PreBuild) run_cmake(PreLink) diff --git a/Tests/Server/server-test.py b/Tests/Server/server-test.py index 62d9008..5621111 100644 --- a/Tests/Server/server-test.py +++ b/Tests/Server/server-test.py @@ -117,4 +117,4 @@ except: proc.terminate() raise -sys.exit(0) +sys.exit(proc.returncode) diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp index fe0f7df..23ca091 100644 --- a/Utilities/IWYU/mapping.imp +++ b/Utilities/IWYU/mapping.imp @@ -21,6 +21,7 @@ { include: [ "<wctype.h>", public, "<cwctype>", public ] }, # HACK: check whether this can be removed with next iwyu release. + { include: [ "<bits/shared_ptr.h>", private, "<memory>", public ] }, { include: [ "<bits/std_function.h>", private, "<functional>", public ] }, { include: [ "<bits/time.h>", private, "<time.h>", public ] }, { include: [ "<bits/types/clock_t.h>", private, "<time.h>", public ] }, |