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  ea85b4e1c149a9b3b5fa446833d61ce16b13fa62 (commit)
       via  1d601c6cb978a3b6b6143fdf64e284fb3a098d1e (commit)
      from  b0e23de782c19caefdfbbb96a1582eed5817d8cc (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=ea85b4e1c149a9b3b5fa446833d61ce16b13fa62
commit ea85b4e1c149a9b3b5fa446833d61ce16b13fa62
Merge: b0e23de 1d601c6
Author:     Brad King <brad.k...@kitware.com>
AuthorDate: Thu Sep 22 08:07:12 2016 -0400
Commit:     CMake Topic Stage <kwro...@kitware.com>
CommitDate: Thu Sep 22 08:07:12 2016 -0400

    Merge topic 'cmake-server-pipes' into next
    
    1d601c6c server-mode: Introduce cmServerConnection


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1d601c6cb978a3b6b6143fdf64e284fb3a098d1e
commit 1d601c6cb978a3b6b6143fdf64e284fb3a098d1e
Author:     Tobias Hunger <tobias.hun...@qt.io>
AuthorDate: Fri Sep 9 10:01:44 2016 +0200
Commit:     Brad King <brad.k...@kitware.com>
CommitDate: Thu Sep 22 08:06:38 2016 -0400

    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..9daed4b 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,32 +914,49 @@ 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
       static_cast<void>(supportExperimental);
+      static_cast<void>(isDebug);
       cmSystemTools::Error("CMake was not built with server mode enabled");
       return 1;
 #endif
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:


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

Reply via email to