Merge topic 'cmake-server-basic-commands'

89043267 server-mode: Add command to compute the build system
0a8ad670 server-mode: Add a configure command
544f65f4 server-mode: Set global configuration of cmake via a command
82104cc7 server-mode: Query global configuration of cmake via a command
This commit is contained in:
Brad King 2016-09-27 08:22:50 -04:00 committed by CMake Topic Stage
commit e8ff565d94
8 changed files with 561 additions and 4 deletions

View File

@ -248,3 +248,129 @@ which will result in a response type "reply"::
]== CMake Server ==]
indicating that the server is ready for action.
Type "globalSettings"
^^^^^^^^^^^^^^^^^^^^^
This request can be sent after the initial handshake. It will return a
JSON structure with information on cmake state.
Example::
[== CMake Server ==[
{"type":"globalSettings"}
]== CMake Server ==]
which will result in a response type "reply"::
[== CMake Server ==[
{
"buildDirectory": "/tmp/test-build",
"capabilities": {
"generators": [
{
"extraGenerators": [],
"name": "Watcom WMake",
"platformSupport": false,
"toolsetSupport": false
},
<...>
],
"serverMode": false,
"version": {
"isDirty": false,
"major": 3,
"minor": 6,
"patch": 20160830,
"string": "3.6.20160830-gd6abad",
"suffix": "gd6abad"
}
},
"checkSystemVars": false,
"cookie": "",
"extraGenerator": "",
"generator": "Ninja",
"debugOutput": false,
"inReplyTo": "globalSettings",
"sourceDirectory": "/home/code/cmake",
"trace": false,
"traceExpand": false,
"type": "reply",
"warnUninitialized": false,
"warnUnused": false,
"warnUnusedCli": true
}
]== CMake Server ==]
Type "setGlobalSettings"
^^^^^^^^^^^^^^^^^^^^^^^^
This request can be sent to change the global settings attributes. Unknown
attributes are going to be ignored. Read-only attributes reported by
"globalSettings" are all capabilities, buildDirectory, generator,
extraGenerator and sourceDirectory. Any attempt to set these will be ignored,
too.
All other settings will be changed.
The server will respond with an empty reply message or an error.
Example::
[== CMake Server ==[
{"type":"setGlobalSettings","debugOutput":true}
]== CMake Server ==]
CMake will reply to this with::
[== CMake Server ==[
{"inReplyTo":"setGlobalSettings","type":"reply"}
]== CMake Server ==]
Type "configure"
^^^^^^^^^^^^^^^^
This request will configure a project for build.
To configure a build directory already containing cmake files, it is enough to
set "buildDirectory" via "setGlobalSettings". To create a fresh build directory
you also need to set "currentGenerator" and "sourceDirectory" via "setGlobalSettings"
in addition to "buildDirectory".
You may a list of strings to "configure" via the "cacheArguments" key. These
strings will be interpreted similar to command line arguments related to
cache handling that are passed to the cmake command line client.
Example::
[== CMake Server ==[
{"type":"configure", "cacheArguments":["-Dsomething=else"]}
]== CMake Server ==]
CMake will reply like this (after reporting progress for some time)::
[== CMake Server ==[
{"cookie":"","inReplyTo":"configure","type":"reply"}
]== CMake Server ==]
Type "compute"
^^^^^^^^^^^^^^
This requist will generate build system files in the build directory and
is only available after a project was successfully "configure"d.
Example::
[== CMake Server ==[
{"type":"compute"}
]== CMake Server ==]
CMake will reply (after reporting progress information)::
[== CMake Server ==[
{"cookie":"","inReplyTo":"compute","type":"reply"}
]== CMake Server ==]

View File

@ -16,15 +16,23 @@
// Vocabulary:
static const std::string kCOMPUTE_TYPE = "compute";
static const std::string kCONFIGURE_TYPE = "configure";
static const std::string kERROR_TYPE = "error";
static const std::string kGLOBAL_SETTINGS_TYPE = "globalSettings";
static const std::string kHANDSHAKE_TYPE = "handshake";
static const std::string kMESSAGE_TYPE = "message";
static const std::string kPROGRESS_TYPE = "progress";
static const std::string kREPLY_TYPE = "reply";
static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings";
static const std::string kSIGNAL_TYPE = "signal";
static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments";
static const std::string kCAPABILITIES_KEY = "capabilities";
static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars";
static const std::string kCOOKIE_KEY = "cookie";
static const std::string kDEBUG_OUTPUT_KEY = "debugOutput";
static const std::string kERROR_MESSAGE_KEY = "errorMessage";
static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator";
static const std::string kGENERATOR_KEY = "generator";
@ -43,7 +51,12 @@ static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory";
static const std::string kSUPPORTED_PROTOCOL_VERSIONS =
"supportedProtocolVersions";
static const std::string kTITLE_KEY = "title";
static const std::string kTRACE_EXPAND_KEY = "traceExpand";
static const std::string kTRACE_KEY = "trace";
static const std::string kTYPE_KEY = "type";
static const std::string kWARN_UNINITIALIZED_KEY = "warnUninitialized";
static const std::string kWARN_UNUSED_CLI_KEY = "warnUnusedCli";
static const std::string kWARN_UNUSED_KEY = "warnUnused";
static const std::string kSTART_MAGIC = "[== CMake Server ==[";
static const std::string kEND_MAGIC = "]== CMake Server ==]";

View File

@ -13,6 +13,7 @@
#include "cmServerProtocol.h"
#include "cmExternalMakefileProjectGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmServer.h"
#include "cmServerDictionary.h"
#include "cmSystemTools.h"
@ -279,6 +280,19 @@ const cmServerResponse cmServerProtocol1_0::Process(
{
assert(this->m_State >= STATE_ACTIVE);
if (request.Type == kCOMPUTE_TYPE) {
return this->ProcessCompute(request);
}
if (request.Type == kCONFIGURE_TYPE) {
return this->ProcessConfigure(request);
}
if (request.Type == kGLOBAL_SETTINGS_TYPE) {
return this->ProcessGlobalSettings(request);
}
if (request.Type == kSET_GLOBAL_SETTINGS_TYPE) {
return this->ProcessSetGlobalSettings(request);
}
return request.ReportError("Unknown command!");
}
@ -286,3 +300,179 @@ bool cmServerProtocol1_0::IsExperimental() const
{
return true;
}
cmServerResponse cmServerProtocol1_0::ProcessCompute(
const cmServerRequest& request)
{
if (this->m_State > STATE_CONFIGURED) {
return request.ReportError("This build system was already generated.");
}
if (this->m_State < STATE_CONFIGURED) {
return request.ReportError("This project was not configured yet.");
}
cmake* cm = this->CMakeInstance();
int ret = cm->Generate();
if (ret < 0) {
return request.ReportError("Failed to compute build system.");
}
m_State = STATE_COMPUTED;
return request.Reply(Json::Value());
}
cmServerResponse cmServerProtocol1_0::ProcessConfigure(
const cmServerRequest& request)
{
if (this->m_State == STATE_INACTIVE) {
return request.ReportError("This instance is inactive.");
}
// Make sure the types of cacheArguments matches (if given):
std::vector<std::string> cacheArgs;
bool cacheArgumentsError = false;
const Json::Value passedArgs = request.Data[kCACHE_ARGUMENTS_KEY];
if (!passedArgs.isNull()) {
if (passedArgs.isString()) {
cacheArgs.push_back(passedArgs.asString());
} else if (passedArgs.isArray()) {
for (auto i = passedArgs.begin(); i != passedArgs.end(); ++i) {
if (!i->isString()) {
cacheArgumentsError = true;
break;
}
cacheArgs.push_back(i->asString());
}
} else {
cacheArgumentsError = true;
}
}
if (cacheArgumentsError) {
request.ReportError(
"cacheArguments must be unset, a string or an array of strings.");
}
cmake* cm = this->CMakeInstance();
std::string sourceDir = cm->GetHomeDirectory();
const std::string buildDir = cm->GetHomeOutputDirectory();
if (buildDir.empty()) {
return request.ReportError(
"No build directory set via setGlobalSettings.");
}
if (cm->LoadCache(buildDir)) {
// build directory has been set up before
const char* cachedSourceDir =
cm->GetState()->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY");
if (!cachedSourceDir) {
return request.ReportError("No CMAKE_HOME_DIRECTORY found in cache.");
}
if (sourceDir.empty()) {
sourceDir = std::string(cachedSourceDir);
cm->SetHomeDirectory(sourceDir);
}
const char* cachedGenerator =
cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR");
if (cachedGenerator) {
cmGlobalGenerator* gen = cm->GetGlobalGenerator();
if (gen && gen->GetName() != cachedGenerator) {
return request.ReportError("Configured generator does not match with "
"CMAKE_GENERATOR found in cache.");
}
}
} else {
// build directory has not been set up before
if (sourceDir.empty()) {
return request.ReportError("No sourceDirectory set via "
"setGlobalSettings and no cache found in "
"buildDirectory.");
}
}
if (cm->AddCMakePaths() != 1) {
return request.ReportError("Failed to set CMake paths.");
}
if (!cm->SetCacheArgs(cacheArgs)) {
return request.ReportError("cacheArguments could not be set.");
}
int ret = cm->Configure();
if (ret < 0) {
return request.ReportError("Configuration failed.");
}
m_State = STATE_CONFIGURED;
return request.Reply(Json::Value());
}
cmServerResponse cmServerProtocol1_0::ProcessGlobalSettings(
const cmServerRequest& request)
{
cmake* cm = this->CMakeInstance();
Json::Value obj = Json::objectValue;
// Capabilities information:
obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson(true);
obj[kDEBUG_OUTPUT_KEY] = cm->GetDebugOutput();
obj[kTRACE_KEY] = cm->GetTrace();
obj[kTRACE_EXPAND_KEY] = cm->GetTraceExpand();
obj[kWARN_UNINITIALIZED_KEY] = cm->GetWarnUninitialized();
obj[kWARN_UNUSED_KEY] = cm->GetWarnUnused();
obj[kWARN_UNUSED_CLI_KEY] = cm->GetWarnUnusedCli();
obj[kCHECK_SYSTEM_VARS_KEY] = cm->GetCheckSystemVars();
obj[kSOURCE_DIRECTORY_KEY] = cm->GetHomeDirectory();
obj[kBUILD_DIRECTORY_KEY] = cm->GetHomeOutputDirectory();
// Currently used generator:
cmGlobalGenerator* gen = cm->GetGlobalGenerator();
obj[kGENERATOR_KEY] = gen ? gen->GetName() : std::string();
obj[kEXTRA_GENERATOR_KEY] =
gen ? gen->GetExtraGeneratorName() : std::string();
return request.Reply(obj);
}
static void setBool(const cmServerRequest& request, const std::string& key,
std::function<void(bool)> setter)
{
if (request.Data[key].isNull()) {
return;
}
setter(request.Data[key].asBool());
}
cmServerResponse cmServerProtocol1_0::ProcessSetGlobalSettings(
const cmServerRequest& request)
{
const std::vector<std::string> boolValues = {
kDEBUG_OUTPUT_KEY, kTRACE_KEY, kTRACE_EXPAND_KEY,
kWARN_UNINITIALIZED_KEY, kWARN_UNUSED_KEY, kWARN_UNUSED_CLI_KEY,
kCHECK_SYSTEM_VARS_KEY
};
for (auto i : boolValues) {
if (!request.Data[i].isNull() && !request.Data[i].isBool()) {
return request.ReportError("\"" + i +
"\" must be unset or a bool value.");
}
}
cmake* cm = this->CMakeInstance();
setBool(request, kDEBUG_OUTPUT_KEY,
[cm](bool e) { cm->SetDebugOutputOn(e); });
setBool(request, kTRACE_KEY, [cm](bool e) { cm->SetTrace(e); });
setBool(request, kTRACE_EXPAND_KEY, [cm](bool e) { cm->SetTraceExpand(e); });
setBool(request, kWARN_UNINITIALIZED_KEY,
[cm](bool e) { cm->SetWarnUninitialized(e); });
setBool(request, kWARN_UNUSED_KEY, [cm](bool e) { cm->SetWarnUnused(e); });
setBool(request, kWARN_UNUSED_CLI_KEY,
[cm](bool e) { cm->SetWarnUnusedCli(e); });
setBool(request, kCHECK_SYSTEM_VARS_KEY,
[cm](bool e) { cm->SetCheckSystemVars(e); });
return request.Reply(Json::Value());
}

View File

@ -13,6 +13,7 @@
#pragma once
#include "cmListFileCache.h"
#include "cmake.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
#include "cm_jsoncpp_writer.h"
@ -116,10 +117,18 @@ private:
bool DoActivate(const cmServerRequest& request,
std::string* errorMessage) override;
// Handle requests:
cmServerResponse ProcessCompute(const cmServerRequest& request);
cmServerResponse ProcessConfigure(const cmServerRequest& request);
cmServerResponse ProcessGlobalSettings(const cmServerRequest& request);
cmServerResponse ProcessSetGlobalSettings(const cmServerRequest& request);
enum State
{
STATE_INACTIVE,
STATE_ACTIVE
STATE_ACTIVE,
STATE_CONFIGURED,
STATE_COMPUTED
};
State m_State = STATE_INACTIVE;
};

View File

@ -19,5 +19,6 @@ macro(do_test bsname file)
endmacro()
do_test("test_handshake" "tc_handshake.json")
do_test("test_globalSettings" "tc_globalSettings.json")
add_executable(Server empty.cpp)

View File

@ -106,6 +106,7 @@ def waitForReply(cmakeCommand, originalType, cookie):
packet = waitForRawMessage(cmakeCommand)
if packet['cookie'] != cookie or packet['type'] != 'reply' or packet['inReplyTo'] != originalType:
sys.exit(1)
return packet
def waitForError(cmakeCommand, originalType, cookie, message):
packet = waitForRawMessage(cmakeCommand)
@ -117,10 +118,71 @@ def waitForProgress(cmakeCommand, originalType, cookie, current, message):
if packet['cookie'] != cookie or packet['type'] != 'progress' or packet['inReplyTo'] != originalType or packet['progressCurrent'] != current or packet['progressMessage'] != message:
sys.exit(1)
def handshake(cmakeCommand, major, minor):
def handshake(cmakeCommand, major, minor, source, build, generator, extraGenerator):
version = { 'major': major }
if minor >= 0:
version['minor'] = minor
writePayload(cmakeCommand, { 'type': 'handshake', 'protocolVersion': version, 'cookie': 'TEST_HANDSHAKE' })
writePayload(cmakeCommand, { 'type': 'handshake', 'protocolVersion': version,
'cookie': 'TEST_HANDSHAKE', 'sourceDirectory': source, 'buildDirectory': build,
'generator': generator, 'extraGenerator': extraGenerator })
waitForReply(cmakeCommand, 'handshake', 'TEST_HANDSHAKE')
def validateGlobalSettings(cmakeCommand, cmakeCommandPath, data):
packet = waitForReply(cmakeCommand, 'globalSettings', '')
capabilities = packet['capabilities']
# validate version:
cmakeoutput = subprocess.check_output([ cmakeCommandPath, "--version" ], universal_newlines=True)
cmakeVersion = cmakeoutput.splitlines()[0][14:]
version = capabilities['version']
versionString = version['string']
vs = str(version['major']) + '.' + str(version['minor']) + '.' + str(version['patch'])
if (versionString != vs and not versionString.startswith(vs + '-')):
sys.exit(1)
if (versionString != cmakeVersion):
sys.exit(1)
# validate generators:
generatorObjects = capabilities['generators']
cmakeoutput = subprocess.check_output([ cmakeCommandPath, "--help" ], universal_newlines=True)
index = cmakeoutput.index('\nGenerators\n\n')
cmakeGenerators = []
for line in cmakeoutput[index + 12:].splitlines():
if not line.startswith(' '):
continue
if line.startswith(' '):
continue
equalPos = line.find('=')
tmp = ''
if (equalPos > 0):
tmp = line[2:equalPos].strip()
else:
tmp = line.strip()
if tmp.endswith(" [arch]"):
tmp = tmp[0:len(tmp) - 7]
if (len(tmp) > 0) and (" - " not in tmp) and (tmp != 'KDevelop3'):
cmakeGenerators.append(tmp)
generators = []
for genObj in generatorObjects:
generators.append(genObj['name'])
generators.sort()
cmakeGenerators.sort()
for gen in cmakeGenerators:
if (not gen in generators):
sys.exit(1)
gen = packet['generator']
if (gen != '' and not (gen in generators)):
sys.exit(1)
for i in data:
print("Validating", i)
if (packet[i] != data[i]):
sys.exit(1)

View File

@ -68,9 +68,25 @@ for obj in testData:
if debug: print("Doing handshake:", json.dumps(data))
major = -1
minor = -1
generator = 'Ninja'
extraGenerator = 'CodeBlocks'
sourceDirectory = sourceDir
buildDirectory = buildDir
if 'major' in data: major = data['major']
if 'minor' in data: minor = data['minor']
cmakelib.handshake(proc, major, minor)
if 'buildDirectory' in data: buildDirectory = data['buildDirectory']
if 'sourceDirectory' in data: sourceDirectory = data['sourceDirectory']
if 'generator' in data: generator = data['generator']
if 'extraGenerator' in data: extraGenerator = data['extraGenerator']
cmakelib.handshake(proc, major, minor, sourceDirectory, buildDirectory,
generator, extraGenerator)
elif 'validateGlobalSettings' in obj:
data = obj['validateGlobalSettings']
if not 'buildDirectory' in data: data['buildDirectory'] = buildDir
if not 'sourceDirectory' in data: data['sourceDirectory'] = sourceDir
if not 'generator' in data: data['generator'] = 'Ninja'
if not 'extraGenerator' in data: data['extraGenerator'] = 'CodeBlocks'
cmakelib.validateGlobalSettings(proc, cmakeCommand, data)
elif 'message' in obj:
print("MESSAGE:", obj["message"])
else:

View File

@ -0,0 +1,140 @@
[
{ "message": "Testing globalSettings" },
{ "handshake": {"major": 1} },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "message": "Change settings:" },
{ "send": { "type": "setGlobalSettings", "warnUnused": true } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "warnUnused": false } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "debugOutput": true } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": true, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "debugOutput": false } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "warnUninitialized": true } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": true, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "warnUninitialized": false } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "traceExpand": true } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": true, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "traceExpand": false } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "trace": true } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": true, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "trace": false } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "warnUnusedCli": false } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": false, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "warnUnusedCli": true } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "checkSystemVars": true } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": true } },
{ "send": { "type": "setGlobalSettings", "checkSystemVars": false } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } },
{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } },
{ "message": "Ignore unknown/readonly" },
{ "send": { "type": "setGlobalSettings", "unknownKey": "unknownValue", "extraGenerator": "XXX", "generator": "YYY", "sourceDirectory": "/tmp/source", "buildDirectory": "/tmp/build" } },
{ "reply": { "type": "setGlobalSettings" } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } },
{ "message": "Error paths:" },
{ "send": { "type": "setGlobalSettings", "debugOutput": true, "warnUnused": 1 } },
{ "error": { "type": "setGlobalSettings", "message": "\"warnUnused\" must be unset or a bool value." } },
{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": 1 } },
{ "error": { "type": "setGlobalSettings", "message": "\"debugOutput\" must be unset or a bool value." } },
{ "send": { "type": "setGlobalSettings", "warnUninitialized": 1, "warnUnused": true, "debugOutput": true } },
{ "error": { "type": "setGlobalSettings", "message": "\"warnUninitialized\" must be unset or a bool value." } },
{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "traceExpand": 1 } },
{ "error": { "type": "setGlobalSettings", "message": "\"traceExpand\" must be unset or a bool value." } },
{ "send": { "type": "setGlobalSettings", "debugOutput": true, "trace": 1, "warnUnused": true } },
{ "error": { "type": "setGlobalSettings", "message": "\"trace\" must be unset or a bool value." } },
{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "warnUnusedCli": 1.0 } },
{ "error": { "type": "setGlobalSettings", "message": "\"warnUnusedCli\" must be unset or a bool value." } },
{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "checkSystemVars": "some string" } },
{ "error": { "type": "setGlobalSettings", "message": "\"checkSystemVars\" must be unset or a bool value." } },
{ "send": { "type": "globalSettings"} },
{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } },
{ "message": "Everything ok." }
]