summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2016-09-21 08:47:48 -0400
committerCMake Topic Stage <kwrobot@kitware.com>2016-09-21 08:47:48 -0400
commiteca2af6e66343c51389f6605df79f7e6ce60cf37 (patch)
treee29abb1e6ccc488eebcaaa6a3705e3d5e2e80620
parent1657fa0795fe6109780593a265a240d9ef73ef77 (diff)
parent4fb2b41a58fa3bd82649d8b19ecbe038e594e753 (diff)
downloadcmake-eca2af6e66343c51389f6605df79f7e6ce60cf37.tar.gz
Merge topic 'cmake-server-more-info'
4fb2b41a server-mode: Add debug support 537efe05 server-mode: Report Messages from cmake to clients ca779948 server-mode: Automate progress reporting 70b8ba9a cmake-server: Use consistent constant naming style
-rw-r--r--Help/manual/cmake-server.7.rst49
-rw-r--r--Source/cmServer.cxx171
-rw-r--r--Source/cmServer.h14
-rw-r--r--Source/cmServerProtocol.cxx21
-rw-r--r--Source/cmServerProtocol.h10
5 files changed, 219 insertions, 46 deletions
diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst
index fd0c9ee42c..75aa0ee17e 100644
--- a/Help/manual/cmake-server.7.rst
+++ b/Help/manual/cmake-server.7.rst
@@ -68,6 +68,40 @@ Messages sent to and from the process are wrapped in magic strings::
The server is now ready to accept further requests via stdin.
+Debugging
+=========
+
+CMake server mode can be asked to provide statistics on execution times, etc.
+or to dump a copy of the response into a file. This is done passing a "debug"
+JSON object as a child of the request.
+
+The debug object supports the "showStats" key, which takes a boolean and makes
+the server mode return a "zzzDebug" object with stats as part of its response.
+"dumpToFile" takes a string value and will cause the cmake server to copy
+the response into the given filename.
+
+This is a response from the cmake server with "showStats" set to true::
+
+ [== CMake Server ==[
+ {
+ "cookie":"",
+ "errorMessage":"Waiting for type \"handshake\".",
+ "inReplyTo":"unknown",
+ "type":"error",
+ "zzzDebug": {
+ "dumpFile":"/tmp/error.txt",
+ "jsonSerialization":0.011016,
+ "size":111,
+ "totalTime":0.025995
+ }
+ }
+ ]== CMake Server ==]
+
+The server has made a copy of this response into the file /tmp/error.txt and
+took 0.011 seconds to turn the JSON response into a string, and it took 0.025
+seconds to process the request in total. The reply has a size of 111 bytes.
+
+
Protocol API
============
@@ -132,6 +166,21 @@ a message of type "reply" or "error" that complete the request.
the request that triggered the responses was delivered.
+Type "message"
+^^^^^^^^^^^^^^
+
+A message is triggered when the server processes a request and produces some
+form of output that should be displayed to the user. A Message has a "message"
+with the actual text to display as well as a "title" with a suggested dialog
+box title.
+
+Example::
+
+ [== CMake Server ==[
+ {"cookie":"","message":"Something happened.","title":"Title Text","inReplyTo":"handshake","type":"message"}
+ ]== CMake Server ==]
+
+
Specific Message Types
----------------------
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index 208fac6ac9..be001a776a 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -14,6 +14,7 @@
#include "cmServer.h"
#include "cmServerProtocol.h"
+#include "cmSystemTools.h"
#include "cmVersionMacros.h"
#include "cmake.h"
@@ -22,17 +23,22 @@
#include "cm_jsoncpp_value.h"
#endif
-const char kTYPE_KEY[] = "type";
-const char kCOOKIE_KEY[] = "cookie";
-const char REPLY_TO_KEY[] = "inReplyTo";
-const char ERROR_MESSAGE_KEY[] = "errorMessage";
+#include <fstream>
+#include <iostream>
+#include <memory>
-const char ERROR_TYPE[] = "error";
-const char REPLY_TYPE[] = "reply";
-const char PROGRESS_TYPE[] = "progress";
+static const std::string kTYPE_KEY = "type";
+static const std::string kCOOKIE_KEY = "cookie";
+static const std::string kREPLY_TO_KEY = "inReplyTo";
+static const std::string kERROR_MESSAGE_KEY = "errorMessage";
-const char START_MAGIC[] = "[== CMake Server ==[";
-const char END_MAGIC[] = "]== CMake Server ==]";
+static const std::string kERROR_TYPE = "error";
+static const std::string kREPLY_TYPE = "reply";
+static const std::string kPROGRESS_TYPE = "progress";
+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
{
@@ -85,6 +91,20 @@ void read_stdin(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
free(buf->base);
}
+class cmServer::DebugInfo
+{
+public:
+ DebugInfo()
+ : StartTime(uv_hrtime())
+ {
+ }
+
+ bool PrintStatistics = false;
+
+ std::string OutputFile;
+ uint64_t StartTime;
+};
+
cmServer::cmServer(bool supportExperimental)
: SupportExperimental(supportExperimental)
{
@@ -124,18 +144,33 @@ void cmServer::PopOne()
return;
}
+ std::unique_ptr<DebugInfo> debug;
+ Json::Value debugValue = value["debug"];
+ if (!debugValue.isNull()) {
+ debug = std::make_unique<DebugInfo>();
+ debug->OutputFile = debugValue["dumpToFile"].asString();
+ debug->PrintStatistics = debugValue["showStats"].asBool();
+ }
+
const cmServerRequest request(this, 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);
+ this->WriteResponse(response, nullptr);
return;
}
- this->WriteResponse(this->Protocol ? this->Protocol->Process(request)
- : this->SetProtocolVersion(request));
+ cmSystemTools::SetMessageCallback(reportMessage,
+ const_cast<cmServerRequest*>(&request));
+ if (this->Protocol) {
+ this->Protocol->CMakeInstance()->SetProgressCallback(
+ reportProgress, const_cast<cmServerRequest*>(&request));
+ this->WriteResponse(this->Protocol->Process(request), debug.get());
+ } else {
+ this->WriteResponse(this->SetProtocolVersion(request), debug.get());
+ }
}
void cmServer::handleData(const std::string& data)
@@ -154,11 +189,11 @@ void cmServer::handleData(const std::string& data)
line.erase(ls - 1, 1);
this->DataBuffer.erase(this->DataBuffer.begin(),
this->DataBuffer.begin() + needle + 1);
- if (line == START_MAGIC) {
+ if (line == kSTART_MAGIC) {
this->JsonData.clear();
continue;
}
- if (line == END_MAGIC) {
+ if (line == kEND_MAGIC) {
this->Queue.push_back(this->JsonData);
this->JsonData.clear();
if (!this->Writing) {
@@ -207,7 +242,31 @@ void cmServer::PrintHello() const
protocolVersions.append(tmp);
}
- this->WriteJsonObject(hello);
+ this->WriteJsonObject(hello, nullptr);
+}
+
+void cmServer::reportProgress(const char* msg, float progress, void* data)
+{
+ const cmServerRequest* request = static_cast<const cmServerRequest*>(data);
+ assert(request);
+ if (progress < 0.0 || progress > 1.0) {
+ request->ReportMessage(msg, "");
+ } else {
+ request->ReportProgress(0, static_cast<int>(progress * 1000), 1000, msg);
+ }
+}
+
+void cmServer::reportMessage(const char* msg, const char* title,
+ bool& /* cancel */, void* data)
+{
+ const cmServerRequest* request = static_cast<const cmServerRequest*>(data);
+ assert(request);
+ assert(msg);
+ std::string titleString;
+ if (title) {
+ titleString = title;
+ }
+ request->ReportMessage(std::string(msg), titleString);
}
cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request)
@@ -292,16 +351,44 @@ bool cmServer::Serve()
return true;
}
-void cmServer::WriteJsonObject(const Json::Value& jsonValue) const
+void cmServer::WriteJsonObject(const Json::Value& jsonValue,
+ const DebugInfo* debug) const
{
Json::FastWriter writer;
- std::string result = std::string("\n") + std::string(START_MAGIC) +
- std::string("\n") + writer.write(jsonValue) + std::string(END_MAGIC) +
- std::string("\n");
+ auto beforeJson = uv_hrtime();
+ std::string result = writer.write(jsonValue);
+
+ if (debug) {
+ Json::Value copy = jsonValue;
+ if (debug->PrintStatistics) {
+ Json::Value stats = Json::objectValue;
+ auto endTime = uv_hrtime();
+
+ stats["jsonSerialization"] = double(endTime - beforeJson) / 1000000.0;
+ stats["totalTime"] = double(endTime - debug->StartTime) / 1000000.0;
+ stats["size"] = static_cast<int>(result.size());
+ if (!debug->OutputFile.empty()) {
+ stats["dumpFile"] = debug->OutputFile;
+ }
+
+ copy["zzzDebug"] = stats;
+
+ result = writer.write(copy); // Update result to include debug info
+ }
+
+ if (!debug->OutputFile.empty()) {
+ std::ofstream myfile;
+ myfile.open(debug->OutputFile);
+ myfile << result;
+ myfile.close();
+ }
+ }
this->Writing = true;
- write_data(this->OutputStream, result, on_stdout_write);
+ write_data(this->OutputStream, std::string("\n") + kSTART_MAGIC +
+ std::string("\n") + result + kEND_MAGIC + std::string("\n"),
+ on_stdout_write);
}
cmServerProtocol* cmServer::FindMatchingProtocol(
@@ -328,39 +415,59 @@ void cmServer::WriteProgress(const cmServerRequest& request, int min,
assert(message.length() != 0);
Json::Value obj = Json::objectValue;
- obj[kTYPE_KEY] = PROGRESS_TYPE;
- obj[REPLY_TO_KEY] = request.Type;
+ obj[kTYPE_KEY] = kPROGRESS_TYPE;
+ obj[kREPLY_TO_KEY] = request.Type;
obj[kCOOKIE_KEY] = request.Cookie;
obj["progressMessage"] = message;
obj["progressMinimum"] = min;
obj["progressMaximum"] = max;
obj["progressCurrent"] = current;
- this->WriteJsonObject(obj);
+ this->WriteJsonObject(obj, nullptr);
+}
+
+void cmServer::WriteMessage(const cmServerRequest& request,
+ const std::string& message,
+ const std::string& title) const
+{
+ if (message.empty())
+ return;
+
+ Json::Value obj = Json::objectValue;
+ obj[kTYPE_KEY] = kMESSAGE_TYPE;
+ obj[kREPLY_TO_KEY] = request.Type;
+ obj[kCOOKIE_KEY] = request.Cookie;
+ obj["message"] = message;
+ if (!title.empty()) {
+ obj["title"] = title;
+ }
+
+ WriteJsonObject(obj, nullptr);
}
void cmServer::WriteParseError(const std::string& message) const
{
Json::Value obj = Json::objectValue;
- obj[kTYPE_KEY] = ERROR_TYPE;
- obj[ERROR_MESSAGE_KEY] = message;
- obj[REPLY_TO_KEY] = "";
+ obj[kTYPE_KEY] = kERROR_TYPE;
+ obj[kERROR_MESSAGE_KEY] = message;
+ obj[kREPLY_TO_KEY] = "";
obj[kCOOKIE_KEY] = "";
- this->WriteJsonObject(obj);
+ this->WriteJsonObject(obj, nullptr);
}
-void cmServer::WriteResponse(const cmServerResponse& response) const
+void cmServer::WriteResponse(const cmServerResponse& response,
+ const DebugInfo* debug) const
{
assert(response.IsComplete());
Json::Value obj = response.Data();
obj[kCOOKIE_KEY] = response.Cookie;
- obj[kTYPE_KEY] = response.IsError() ? ERROR_TYPE : REPLY_TYPE;
- obj[REPLY_TO_KEY] = response.Type;
+ obj[kTYPE_KEY] = response.IsError() ? kERROR_TYPE : kREPLY_TYPE;
+ obj[kREPLY_TO_KEY] = response.Type;
if (response.IsError()) {
- obj[ERROR_MESSAGE_KEY] = response.ErrorMessage();
+ obj[kERROR_MESSAGE_KEY] = response.ErrorMessage();
}
- this->WriteJsonObject(obj);
+ this->WriteJsonObject(obj, debug);
}
diff --git a/Source/cmServer.h b/Source/cmServer.h
index 4a9c3f53c6..38a11bbcad 100644
--- a/Source/cmServer.h
+++ b/Source/cmServer.h
@@ -31,6 +31,8 @@ class cmServerResponse;
class cmServer
{
public:
+ class DebugInfo;
+
cmServer(bool supportExperimental);
~cmServer();
@@ -43,6 +45,10 @@ public:
private:
void RegisterProtocol(cmServerProtocol* protocol);
+ static void reportProgress(const char* msg, float progress, void* data);
+ static void reportMessage(const char* msg, const char* title, bool& cancel,
+ void* data);
+
// Handle requests:
cmServerResponse SetProtocolVersion(const cmServerRequest& request);
@@ -51,10 +57,14 @@ private:
// Write responses:
void WriteProgress(const cmServerRequest& request, int min, int current,
int max, const std::string& message) const;
- void WriteResponse(const cmServerResponse& response) const;
+ void WriteMessage(const cmServerRequest& request, const std::string& message,
+ const std::string& title) const;
+ void WriteResponse(const cmServerResponse& response,
+ const DebugInfo* debug) const;
void WriteParseError(const std::string& message) const;
- void WriteJsonObject(Json::Value const& jsonValue) const;
+ void WriteJsonObject(Json::Value const& jsonValue,
+ const DebugInfo* debug) const;
static cmServerProtocol* FindMatchingProtocol(
const std::vector<cmServerProtocol*>& protocols, int major, int minor);
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index d53ac28a1f..26942d3100 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -22,17 +22,14 @@
#include "cm_jsoncpp_value.h"
#endif
-namespace {
// Vocabulary:
-const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
-const std::string kCOOKIE_KEY = "cookie";
-const std::string kEXTRA_GENERATOR_KEY = "extraGenerator";
-const std::string kGENERATOR_KEY = "generator";
-const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory";
-const std::string kTYPE_KEY = "type";
-
-} // namespace
+static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
+static const std::string kCOOKIE_KEY = "cookie";
+static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator";
+static const std::string kGENERATOR_KEY = "generator";
+static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory";
+static const std::string kTYPE_KEY = "type";
cmServerRequest::cmServerRequest(cmServer* server, const std::string& t,
const std::string& c, const Json::Value& d)
@@ -49,6 +46,12 @@ void cmServerRequest::ReportProgress(int min, int current, int max,
this->m_Server->WriteProgress(*this, min, current, max, message);
}
+void cmServerRequest::ReportMessage(const std::string& message,
+ const std::string& title) const
+{
+ m_Server->WriteMessage(*this, message, title);
+}
+
cmServerResponse cmServerRequest::Reply(const Json::Value& data) const
{
cmServerResponse response(*this);
diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h
index e95c2f19c7..bab949b759 100644
--- a/Source/cmServerProtocol.h
+++ b/Source/cmServerProtocol.h
@@ -57,9 +57,6 @@ private:
class cmServerRequest
{
public:
- void ReportProgress(int min, int current, int max,
- const std::string& message) const;
-
cmServerResponse Reply(const Json::Value& data) const;
cmServerResponse ReportError(const std::string& message) const;
@@ -71,6 +68,11 @@ private:
cmServerRequest(cmServer* server, const std::string& t, const std::string& c,
const Json::Value& d);
+ void ReportProgress(int min, int current, int max,
+ const std::string& message) const;
+ void ReportMessage(const std::string& message,
+ const std::string& title) const;
+
cmServer* m_Server;
friend class cmServer;
@@ -95,6 +97,8 @@ protected:
private:
std::unique_ptr<cmake> m_CMakeInstance;
+
+ friend class cmServer;
};
class cmServerProtocol1_0 : public cmServerProtocol