This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, next has been updated
       via  132255bfb6e1e00ed121e544f902323f44cb8cfe (commit)
       via  431d1dcc4b658141a045cdc44348a3525af1fe24 (commit)
      from  aa70241e58025d750ddca67f37426d5f0ddf4331 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=132255bfb6e1e00ed121e544f902323f44cb8cfe
commit 132255bfb6e1e00ed121e544f902323f44cb8cfe
Merge: aa70241 431d1dc
Author:     Brad King <brad.k...@kitware.com>
AuthorDate: Wed Sep 21 13:02:02 2016 -0400
Commit:     CMake Topic Stage <kwro...@kitware.com>
CommitDate: Wed Sep 21 13:02:02 2016 -0400

    Merge topic 'cmake-server-pipes' into next
    
    431d1dcc server-mode: Introduce cmServerConnection


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=431d1dcc4b658141a045cdc44348a3525af1fe24
commit 431d1dcc4b658141a045cdc44348a3525af1fe24
Author:     Tobias Hunger <tobias.hun...@qt.io>
AuthorDate: Fri Sep 9 10:01:44 2016 +0200
Commit:     Tobias Hunger <tobias.hun...@qt.io>
CommitDate: Wed Sep 21 17:53:15 2016 +0200

    server-mode: Introduce cmServerConnection
    
    Use it to split pipe and stdin/out handling out of cmServer itself.
    
    The server will shut down when it looses its connection to the client.
    This has the nice property that a crashing client will cause the server
    to terminate as the OS will close the connection on behave of the client.

diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst
index 75aa0ee..00ffcd1 100644
--- a/Help/manual/cmake-server.7.rst
+++ b/Help/manual/cmake-server.7.rst
@@ -49,12 +49,16 @@ Operation
 Start :manual:`cmake(1)` in the server command mode, supplying the path to
 the build directory to process::
 
-  cmake -E server
+  cmake -E server (--debug|--pipe <NAMED_PIPE>)
 
-The server will start up and reply with an hello message on stdout::
+The server will communicate using stdin/stdout (with the ``--debug`` parameter)
+or using a named pipe (with the ``--pipe <NAMED_PIPE>`` parameter).
+
+When connecting to the server (via named pipe or by starting it in ``--debug``
+mode), the server will reply with a hello message::
 
   [== CMake Server ==[
-  {"supportedProtocolVersions":[{"major":0,"minor":1}],"type":"hello"}
+  {"supportedProtocolVersions":[{"major":1,"minor":0}],"type":"hello"}
   ]== CMake Server ==]
 
 Messages sent to and from the process are wrapped in magic strings::
@@ -65,7 +69,8 @@ Messages sent to and from the process are wrapped in magic 
strings::
   }
   ]== CMake Server ==]
 
-The server is now ready to accept further requests via stdin.
+The server is now ready to accept further requests via the named pipe
+or stdin.
 
 
 Debugging
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index a2dead6..5e136e4 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -789,6 +789,7 @@ target_link_libraries(cmake CMakeLib)
 if(CMake_HAVE_SERVER_MODE)
   add_library(CMakeServerLib
     cmServer.cxx cmServer.h
+    cmServerConnection.cxx cmServerConnection.h
     cmServerProtocol.cxx cmServerProtocol.h
     )
   target_link_libraries(CMakeServerLib CMakeLib)
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index be001a7..56cd7ba 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -13,6 +13,7 @@
 
 #include "cmServer.h"
 
+#include "cmServerConnection.h"
 #include "cmServerProtocol.h"
 #include "cmSystemTools.h"
 #include "cmVersionMacros.h"
@@ -40,57 +41,6 @@ static const std::string kMESSAGE_TYPE = "message";
 static const std::string kSTART_MAGIC = "[== CMake Server ==[";
 static const std::string kEND_MAGIC = "]== CMake Server ==]";
 
-typedef struct
-{
-  uv_write_t req;
-  uv_buf_t buf;
-} write_req_t;
-
-void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
-{
-  (void)handle;
-  *buf = uv_buf_init(static_cast<char*>(malloc(suggested_size)),
-                     static_cast<unsigned int>(suggested_size));
-}
-
-void free_write_req(uv_write_t* req)
-{
-  write_req_t* wr = reinterpret_cast<write_req_t*>(req);
-  free(wr->buf.base);
-  free(wr);
-}
-
-void on_stdout_write(uv_write_t* req, int status)
-{
-  (void)status;
-  auto server = reinterpret_cast<cmServer*>(req->data);
-  free_write_req(req);
-  server->PopOne();
-}
-
-void write_data(uv_stream_t* dest, std::string content, uv_write_cb cb)
-{
-  write_req_t* req = static_cast<write_req_t*>(malloc(sizeof(write_req_t)));
-  req->req.data = dest->data;
-  req->buf = uv_buf_init(static_cast<char*>(malloc(content.size())),
-                         static_cast<unsigned int>(content.size()));
-  memcpy(req->buf.base, content.c_str(), content.size());
-  uv_write(reinterpret_cast<uv_write_t*>(req), static_cast<uv_stream_t*>(dest),
-           &req->buf, 1, cb);
-}
-
-void read_stdin(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
-{
-  if (nread > 0) {
-    auto server = reinterpret_cast<cmServer*>(stream->data);
-    std::string result = std::string(buf->base, buf->base + nread);
-    server->handleData(result);
-  }
-
-  if (buf->base)
-    free(buf->base);
-}
-
 class cmServer::DebugInfo
 {
 public:
@@ -105,9 +55,11 @@ public:
   uint64_t StartTime;
 };
 
-cmServer::cmServer(bool supportExperimental)
-  : SupportExperimental(supportExperimental)
+cmServer::cmServer(cmServerConnection* conn, bool supportExperimental)
+  : Connection(conn)
+  , SupportExperimental(supportExperimental)
 {
+  this->Connection->SetServer(this);
   // Register supported protocols:
   this->RegisterProtocol(new cmServerProtocol1_0);
 }
@@ -118,18 +70,15 @@ cmServer::~cmServer()
     return;
   }
 
-  uv_close(reinterpret_cast<uv_handle_t*>(this->InputStream), NULL);
-  uv_close(reinterpret_cast<uv_handle_t*>(this->OutputStream), NULL);
-  uv_loop_close(this->Loop);
-
   for (cmServerProtocol* p : this->SupportedProtocols) {
     delete p;
   }
+
+  delete this->Connection;
 }
 
 void cmServer::PopOne()
 {
-  this->Writing = false;
   if (this->Queue.empty()) {
     return;
   }
@@ -173,39 +122,6 @@ void cmServer::PopOne()
   }
 }
 
-void cmServer::handleData(const std::string& data)
-{
-  this->DataBuffer += data;
-
-  for (;;) {
-    auto needle = this->DataBuffer.find('\n');
-
-    if (needle == std::string::npos) {
-      return;
-    }
-    std::string line = this->DataBuffer.substr(0, needle);
-    const auto ls = line.size();
-    if (ls > 1 && line.at(ls - 1) == '\r')
-      line.erase(ls - 1, 1);
-    this->DataBuffer.erase(this->DataBuffer.begin(),
-                           this->DataBuffer.begin() + needle + 1);
-    if (line == kSTART_MAGIC) {
-      this->JsonData.clear();
-      continue;
-    }
-    if (line == kEND_MAGIC) {
-      this->Queue.push_back(this->JsonData);
-      this->JsonData.clear();
-      if (!this->Writing) {
-        this->PopOne();
-      }
-    } else {
-      this->JsonData += line;
-      this->JsonData += "\n";
-    }
-  }
-}
-
 void cmServer::RegisterProtocol(cmServerProtocol* protocol)
 {
   if (protocol->IsExperimental() && !this->SupportExperimental) {
@@ -245,6 +161,12 @@ void cmServer::PrintHello() const
   this->WriteJsonObject(hello, nullptr);
 }
 
+void cmServer::QueueRequest(const std::string& request)
+{
+  this->Queue.push_back(request);
+  this->PopOne();
+}
+
 void cmServer::reportProgress(const char* msg, float progress, void* data)
 {
   const cmServerRequest* request = static_cast<const cmServerRequest*>(data);
@@ -312,43 +234,16 @@ cmServerResponse cmServer::SetProtocolVersion(const 
cmServerRequest& request)
   return request.Reply(Json::objectValue);
 }
 
-bool cmServer::Serve()
+bool cmServer::Serve(std::string* errorMessage)
 {
   if (this->SupportedProtocols.empty()) {
+    *errorMessage =
+      "No protocol versions defined. Maybe you need --experimental?";
     return false;
   }
   assert(!this->Protocol);
 
-  this->Loop = uv_default_loop();
-
-  if (uv_guess_handle(1) == UV_TTY) {
-    uv_tty_init(this->Loop, &this->Input.tty, 0, 1);
-    uv_tty_set_mode(&this->Input.tty, UV_TTY_MODE_NORMAL);
-    this->Input.tty.data = this;
-    InputStream = reinterpret_cast<uv_stream_t*>(&this->Input.tty);
-
-    uv_tty_init(this->Loop, &this->Output.tty, 1, 0);
-    uv_tty_set_mode(&this->Output.tty, UV_TTY_MODE_NORMAL);
-    this->Output.tty.data = this;
-    OutputStream = reinterpret_cast<uv_stream_t*>(&this->Output.tty);
-  } else {
-    uv_pipe_init(this->Loop, &this->Input.pipe, 0);
-    uv_pipe_open(&this->Input.pipe, 0);
-    this->Input.pipe.data = this;
-    InputStream = reinterpret_cast<uv_stream_t*>(&this->Input.pipe);
-
-    uv_pipe_init(this->Loop, &this->Output.pipe, 0);
-    uv_pipe_open(&this->Output.pipe, 1);
-    this->Output.pipe.data = this;
-    OutputStream = reinterpret_cast<uv_stream_t*>(&this->Output.pipe);
-  }
-
-  this->PrintHello();
-
-  uv_read_start(this->InputStream, alloc_buffer, read_stdin);
-
-  uv_run(this->Loop, UV_RUN_DEFAULT);
-  return true;
+  return Connection->ProcessEvents(errorMessage);
 }
 
 void cmServer::WriteJsonObject(const Json::Value& jsonValue,
@@ -385,10 +280,8 @@ void cmServer::WriteJsonObject(const Json::Value& 
jsonValue,
     }
   }
 
-  this->Writing = true;
-  write_data(this->OutputStream, std::string("\n") + kSTART_MAGIC +
-               std::string("\n") + result + kEND_MAGIC + std::string("\n"),
-             on_stdout_write);
+  Connection->WriteData(std::string("\n") + kSTART_MAGIC + std::string("\n") +
+                        result + kEND_MAGIC + std::string("\n"));
 }
 
 cmServerProtocol* cmServer::FindMatchingProtocol(
diff --git a/Source/cmServer.h b/Source/cmServer.h
index 38a11bb..dde5333 100644
--- a/Source/cmServer.h
+++ b/Source/cmServer.h
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 
+class cmServerConnection;
 class cmServerProtocol;
 class cmServerRequest;
 class cmServerResponse;
@@ -33,18 +34,18 @@ class cmServer
 public:
   class DebugInfo;
 
-  cmServer(bool supportExperimental);
+  cmServer(cmServerConnection* conn, bool supportExperimental);
   ~cmServer();
 
-  bool Serve();
-
-  // for callbacks:
-  void PopOne();
-  void handleData(std::string const& data);
+  bool Serve(std::string* errorMessage);
 
 private:
   void RegisterProtocol(cmServerProtocol* protocol);
 
+  // Callbacks from cmServerConnection:
+  void PopOne();
+  void QueueRequest(const std::string& request);
+
   static void reportProgress(const char* msg, float progress, void* data);
   static void reportMessage(const char* msg, const char* title, bool& cancel,
                             void* data);
@@ -69,6 +70,7 @@ private:
   static cmServerProtocol* FindMatchingProtocol(
     const std::vector<cmServerProtocol*>& protocols, int major, int minor);
 
+  cmServerConnection* Connection = nullptr;
   const bool SupportExperimental;
 
   cmServerProtocol* Protocol = nullptr;
@@ -94,4 +96,5 @@ private:
   mutable bool Writing = false;
 
   friend class cmServerRequest;
+  friend class cmServerConnection;
 };
diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx
new file mode 100644
index 0000000..398e250
--- /dev/null
+++ b/Source/cmServerConnection.cxx
@@ -0,0 +1,307 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2015 Stephen Kelly <steve...@gmail.com>
+  Copyright 2016 Tobias Hunger <tobias.hun...@qt.io>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+
+#include "cmServerConnection.h"
+
+#include <cmServer.h>
+
+#include <assert.h>
+
+namespace {
+
+static const std::string kSTART_MAGIC = "[== CMake Server ==[";
+static const std::string kEND_MAGIC = "]== CMake Server ==]";
+
+struct write_req_t
+{
+  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->HandleEof();
+  }
+
+  delete[](buf->base);
+}
+
+void on_write(uv_write_t* req, int status)
+{
+  (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;
+
+  conn->ProcessNextRequest();
+}
+
+void on_new_connection(uv_stream_t* stream, int status)
+{
+  (void)(status);
+  auto conn = reinterpret_cast<cmServerConnection*>(stream->data);
+  conn->Connect(stream);
+}
+
+} // namespace
+
+class LoopGuard
+{
+public:
+  LoopGuard(cmServerConnection* connection)
+    : Connection(connection)
+  {
+    Connection->mLoop = uv_default_loop();
+  }
+
+  ~LoopGuard()
+  {
+    uv_loop_close(Connection->mLoop);
+    Connection->mLoop = nullptr;
+  }
+
+private:
+  cmServerConnection* Connection;
+};
+
+cmServerConnection::cmServerConnection()
+{
+}
+
+cmServerConnection::~cmServerConnection()
+{
+}
+
+void cmServerConnection::SetServer(cmServer* s)
+{
+  this->Server = s;
+}
+
+bool cmServerConnection::ProcessEvents(std::string* errorMessage)
+{
+  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;
+  }
+
+  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)
+{
+  this->RawReadBuffer += data;
+
+  for (;;) {
+    auto needle = this->RawReadBuffer.find('\n');
+
+    if (needle == std::string::npos) {
+      return;
+    }
+    std::string line = this->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);
+    if (line == kSTART_MAGIC) {
+      this->RequestBuffer.clear();
+      continue;
+    }
+    if (line == kEND_MAGIC) {
+      this->Server->QueueRequest(this->RequestBuffer);
+      this->RequestBuffer.clear();
+    } else {
+      this->RequestBuffer += line;
+      this->RequestBuffer += "\n";
+    }
+  }
+}
+
+void cmServerConnection::HandleEof()
+{
+  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();
+}
+
+bool cmServerStdIoConnection::DoSetup(std::string* errorMessage)
+{
+  (void)(errorMessage);
+
+  if (uv_guess_handle(1) == UV_TTY) {
+    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);
+
+    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 {
+    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);
+
+    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);
+  }
+
+  SendGreetings();
+  uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
+
+  return true;
+}
+
+void cmServerStdIoConnection::TearDown()
+{
+  uv_close(reinterpret_cast<uv_handle_t*>(this->ReadStream), nullptr);
+  this->ReadStream = nullptr;
+  uv_close(reinterpret_cast<uv_handle_t*>(this->WriteStream), nullptr);
+  this->WriteStream = nullptr;
+}
+
+cmServerPipeConnection::cmServerPipeConnection(const std::string& name)
+  : PipeName(name)
+{
+  this->ServerPipe.data = nullptr;
+  this->ClientPipe.data = nullptr;
+}
+
+bool cmServerPipeConnection::DoSetup(std::string* errorMessage)
+{
+  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);
+  serverStream->data = this;
+  if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) {
+    *errorMessage = std::string("Internal Error with ") + this->PipeName +
+      ": " + uv_err_name(r);
+    return false;
+  }
+
+  return true;
+}
+
+void cmServerPipeConnection::TearDown()
+{
+  if (this->WriteStream->data) {
+    uv_close(reinterpret_cast<uv_handle_t*>(this->WriteStream), nullptr);
+    this->WriteStream->data = nullptr;
+  }
+  uv_close(reinterpret_cast<uv_handle_t*>(&this->ServerPipe), nullptr);
+
+  this->WriteStream = nullptr;
+  this->ReadStream = nullptr;
+}
+
+void cmServerPipeConnection::Connect(uv_stream_t* server)
+{
+  if (this->ClientPipe.data == this) {
+    // Accept and close all pipes but the first:
+    uv_pipe_t rejectPipe;
+
+    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), nullptr);
+    return;
+  }
+
+  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
new file mode 100644
index 0000000..fa86e71
--- /dev/null
+++ b/Source/cmServerConnection.h
@@ -0,0 +1,97 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2015 Stephen Kelly <steve...@gmail.com>
+  Copyright 2016 Tobias Hunger <tobias.hun...@qt.io>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include "cm_uv.h"
+#endif
+
+class cmServer;
+class LoopGuard;
+
+class cmServerConnection
+{
+public:
+  cmServerConnection();
+  virtual ~cmServerConnection();
+
+  void SetServer(cmServer* s);
+
+  bool ProcessEvents(std::string* errorMessage);
+
+  void ReadData(const std::string& data);
+  void HandleEof();
+  void WriteData(const std::string& data);
+  void ProcessNextRequest();
+
+  virtual void Connect(uv_stream_t* server) { (void)(server); }
+
+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;
+
+private:
+  uv_loop_t* mLoop = nullptr;
+  cmServer* Server = nullptr;
+
+  friend class LoopGuard;
+};
+
+class cmServerStdIoConnection : public cmServerConnection
+{
+public:
+  bool DoSetup(std::string* errorMessage) override;
+
+  void TearDown() override;
+
+private:
+  typedef union
+  {
+    uv_tty_t tty;
+    uv_pipe_t pipe;
+  } InOutUnion;
+
+  InOutUnion Input;
+  InOutUnion Output;
+};
+
+class cmServerPipeConnection : public cmServerConnection
+{
+public:
+  cmServerPipeConnection(const std::string& name);
+  bool DoSetup(std::string* errorMessage) override;
+
+  void TearDown() override;
+
+  void Connect(uv_stream_t* server) override;
+
+private:
+  const std::string PipeName;
+  uv_pipe_t ServerPipe;
+  uv_pipe_t ClientPipe;
+};
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 38f00e6..c14faa7 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -25,6 +25,7 @@
 
 #if defined(HAVE_SERVER_MODE) && HAVE_SERVER_MODE
 #include "cmServer.h"
+#include "cmServerConnection.h"
 #endif
 
 #if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -913,28 +914,44 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& 
args)
       }
       return 0;
     } else if (args[1] == "server") {
-      if (args.size() > 3) {
-        cmSystemTools::Error("Too many arguments to start server mode");
-        return 1;
-      }
+      const std::string pipePrefix = "--pipe=";
       bool supportExperimental = false;
-      if (args.size() == 3) {
-        if (args[2] == "--experimental") {
+      bool isDebug = false;
+      std::string pipe;
+
+      for (size_t i = 2; i < args.size(); ++i) {
+        const std::string& a = args[i];
+
+        if (a == "--experimental") {
           supportExperimental = true;
+        } else if (a == "--debug") {
+          pipe.clear();
+          isDebug = true;
+        } else if (a.substr(0, pipePrefix.size()) == pipePrefix) {
+          isDebug = false;
+          pipe = a.substr(pipePrefix.size());
+          if (pipe.empty()) {
+            cmSystemTools::Error("No pipe given after --pipe=");
+            return 2;
+          }
         } else {
           cmSystemTools::Error("Unknown argument for server mode");
           return 1;
         }
       }
 #if defined(HAVE_SERVER_MODE) && HAVE_SERVER_MODE
-      cmServer server(supportExperimental);
-      if (server.Serve()) {
+      cmServerConnection* conn;
+      if (isDebug) {
+        conn = new cmServerStdIoConnection;
+      } else {
+        conn = new cmServerPipeConnection(pipe);
+      }
+      cmServer server(conn, supportExperimental);
+      std::string errorMessage;
+      if (server.Serve(&errorMessage)) {
         return 0;
       } else {
-        cmSystemTools::Error(
-          "CMake server could not find any supported protocol. "
-          "Try with \"--experimental\" to enable "
-          "experimental support.");
+        cmSystemTools::Error(errorMessage.c_str());
         return 1;
       }
 #else
diff --git a/Tests/RunCMake/CommandLine/E_server-pipe-result.txt 
b/Tests/RunCMake/CommandLine/E_server-pipe-result.txt
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_server-pipe-result.txt
@@ -0,0 +1 @@
+2
diff --git a/Tests/RunCMake/CommandLine/E_server-pipe-stderr.txt 
b/Tests/RunCMake/CommandLine/E_server-pipe-stderr.txt
new file mode 100644
index 0000000..7193ba6
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_server-pipe-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: No pipe given after --pipe=$
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake 
b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 9f76ad9..0c4f71c 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -13,6 +13,7 @@ run_cmake_command(E_capabilities-arg ${CMAKE_COMMAND} -E 
capabilities --extra-ar
 run_cmake_command(E_echo_append ${CMAKE_COMMAND} -E echo_append)
 run_cmake_command(E_rename-no-arg ${CMAKE_COMMAND} -E rename)
 run_cmake_command(E_server-arg ${CMAKE_COMMAND} -E server --extra-arg)
+run_cmake_command(E_server-pipe ${CMAKE_COMMAND} -E server --pipe=)
 run_cmake_command(E_touch_nocreate-no-arg ${CMAKE_COMMAND} -E touch_nocreate)
 
 run_cmake_command(E_time ${CMAKE_COMMAND} -E time ${CMAKE_COMMAND} -E echo 
"hello  world")
diff --git a/Tests/Server/cmakelib.py b/Tests/Server/cmakelib.py
index e89b1f0..0f98078 100644
--- a/Tests/Server/cmakelib.py
+++ b/Tests/Server/cmakelib.py
@@ -79,7 +79,7 @@ def writePayload(cmakeCommand, obj):
   writeRawData(cmakeCommand, json.dumps(obj))
 
 def initProc(cmakeCommand):
-  cmakeCommand = subprocess.Popen([cmakeCommand, "-E", "server", 
"--experimental"],
+  cmakeCommand = subprocess.Popen([cmakeCommand, "-E", "server", 
"--experimental", "--debug"],
                                   stdin=subprocess.PIPE,
                                   stdout=subprocess.PIPE)
 

-----------------------------------------------------------------------

Summary of changes:
 Help/manual/cmake-server.7.rst                     |   13 +-
 Source/CMakeLists.txt                              |    1 +
 Source/cmServer.cxx                                |  145 ++-------
 Source/cmServer.h                                  |   15 +-
 Source/cmServerConnection.cxx                      |  307 ++++++++++++++++++++
 Source/cmServerConnection.h                        |   97 +++++++
 Source/cmcmd.cxx                                   |   41 ++-
 .../RunCMake/CommandLine/E_server-pipe-result.txt  |    1 +
 .../RunCMake/CommandLine/E_server-pipe-stderr.txt  |    1 +
 Tests/RunCMake/CommandLine/RunCMakeTest.cmake      |    1 +
 Tests/Server/cmakelib.py                           |    2 +-
 11 files changed, 475 insertions(+), 149 deletions(-)
 create mode 100644 Source/cmServerConnection.cxx
 create mode 100644 Source/cmServerConnection.h
 create mode 100644 Tests/RunCMake/CommandLine/E_server-pipe-result.txt
 create mode 100644 Tests/RunCMake/CommandLine/E_server-pipe-stderr.txt


hooks/post-receive
-- 
CMake
_______________________________________________
Cmake-commits mailing list
Cmake-commits@cmake.org
http://public.kitware.com/mailman/listinfo/cmake-commits

Reply via email to