cmServerProtocol.cxx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmServerProtocol.h"
  4. #include <algorithm>
  5. #include <cassert>
  6. #include <functional>
  7. #include <string>
  8. #include <utility>
  9. #include <vector>
  10. #include <cm/memory>
  11. #include "cm_uv.h"
  12. #include "cmAlgorithms.h"
  13. #include "cmExternalMakefileProjectGenerator.h"
  14. #include "cmFileMonitor.h"
  15. #include "cmGlobalGenerator.h"
  16. #include "cmJsonObjectDictionary.h"
  17. #include "cmJsonObjects.h"
  18. #include "cmMessageType.h"
  19. #include "cmServer.h"
  20. #include "cmServerDictionary.h"
  21. #include "cmState.h"
  22. #include "cmSystemTools.h"
  23. #include "cmake.h"
  24. // Get rid of some windows macros:
  25. #undef max
  26. namespace {
  27. std::vector<std::string> toStringList(const Json::Value& in)
  28. {
  29. std::vector<std::string> result;
  30. for (auto const& it : in) {
  31. result.push_back(it.asString());
  32. }
  33. return result;
  34. }
  35. } // namespace
  36. cmServerRequest::cmServerRequest(cmServer* server, cmConnection* connection,
  37. std::string t, std::string c, Json::Value d)
  38. : Type(std::move(t))
  39. , Cookie(std::move(c))
  40. , Data(std::move(d))
  41. , Connection(connection)
  42. , m_Server(server)
  43. {
  44. }
  45. void cmServerRequest::ReportProgress(int min, int current, int max,
  46. const std::string& message) const
  47. {
  48. this->m_Server->WriteProgress(*this, min, current, max, message);
  49. }
  50. void cmServerRequest::ReportMessage(const std::string& message,
  51. const std::string& title) const
  52. {
  53. m_Server->WriteMessage(*this, message, title);
  54. }
  55. cmServerResponse cmServerRequest::Reply(const Json::Value& data) const
  56. {
  57. cmServerResponse response(*this);
  58. response.SetData(data);
  59. return response;
  60. }
  61. cmServerResponse cmServerRequest::ReportError(const std::string& message) const
  62. {
  63. cmServerResponse response(*this);
  64. response.SetError(message);
  65. return response;
  66. }
  67. cmServerResponse::cmServerResponse(const cmServerRequest& request)
  68. : Type(request.Type)
  69. , Cookie(request.Cookie)
  70. {
  71. }
  72. void cmServerResponse::SetData(const Json::Value& data)
  73. {
  74. assert(this->m_Payload == PAYLOAD_UNKNOWN);
  75. if (!data[kCOOKIE_KEY].isNull() || !data[kTYPE_KEY].isNull()) {
  76. this->SetError("Response contains cookie or type field.");
  77. return;
  78. }
  79. this->m_Payload = PAYLOAD_DATA;
  80. this->m_Data = data;
  81. }
  82. void cmServerResponse::SetError(const std::string& message)
  83. {
  84. assert(this->m_Payload == PAYLOAD_UNKNOWN);
  85. this->m_Payload = PAYLOAD_ERROR;
  86. this->m_ErrorMessage = message;
  87. }
  88. bool cmServerResponse::IsComplete() const
  89. {
  90. return this->m_Payload != PAYLOAD_UNKNOWN;
  91. }
  92. bool cmServerResponse::IsError() const
  93. {
  94. assert(this->m_Payload != PAYLOAD_UNKNOWN);
  95. return this->m_Payload == PAYLOAD_ERROR;
  96. }
  97. std::string cmServerResponse::ErrorMessage() const
  98. {
  99. if (this->m_Payload == PAYLOAD_ERROR) {
  100. return this->m_ErrorMessage;
  101. }
  102. return std::string();
  103. }
  104. Json::Value cmServerResponse::Data() const
  105. {
  106. assert(this->m_Payload != PAYLOAD_UNKNOWN);
  107. return this->m_Data;
  108. }
  109. bool cmServerProtocol::Activate(cmServer* server,
  110. const cmServerRequest& request,
  111. std::string* errorMessage)
  112. {
  113. assert(server);
  114. this->m_Server = server;
  115. this->m_CMakeInstance =
  116. cm::make_unique<cmake>(cmake::RoleProject, cmState::Project);
  117. const bool result = this->DoActivate(request, errorMessage);
  118. if (!result) {
  119. this->m_CMakeInstance = nullptr;
  120. }
  121. return result;
  122. }
  123. cmFileMonitor* cmServerProtocol::FileMonitor() const
  124. {
  125. return this->m_Server ? this->m_Server->FileMonitor() : nullptr;
  126. }
  127. void cmServerProtocol::SendSignal(const std::string& name,
  128. const Json::Value& data) const
  129. {
  130. if (this->m_Server) {
  131. this->m_Server->WriteSignal(name, data);
  132. }
  133. }
  134. cmake* cmServerProtocol::CMakeInstance() const
  135. {
  136. return this->m_CMakeInstance.get();
  137. }
  138. bool cmServerProtocol::DoActivate(const cmServerRequest& /*request*/,
  139. std::string* /*errorMessage*/)
  140. {
  141. return true;
  142. }
  143. std::pair<int, int> cmServerProtocol1::ProtocolVersion() const
  144. {
  145. return { 1, 2 };
  146. }
  147. static void setErrorMessage(std::string* errorMessage, const std::string& text)
  148. {
  149. if (errorMessage) {
  150. *errorMessage = text;
  151. }
  152. }
  153. static bool getOrTestHomeDirectory(cmState* state, std::string& value,
  154. std::string* errorMessage)
  155. {
  156. const std::string cachedValue =
  157. *state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
  158. if (value.empty()) {
  159. value = cachedValue;
  160. return true;
  161. }
  162. const std::string suffix = "/CMakeLists.txt";
  163. const std::string cachedValueCML = cachedValue + suffix;
  164. const std::string valueCML = value + suffix;
  165. if (!cmSystemTools::SameFile(valueCML, cachedValueCML)) {
  166. setErrorMessage(errorMessage,
  167. std::string("\"CMAKE_HOME_DIRECTORY\" is set but "
  168. "incompatible with configured "
  169. "source directory value."));
  170. return false;
  171. }
  172. return true;
  173. }
  174. static bool getOrTestValue(cmState* state, const std::string& key,
  175. std::string& value,
  176. const std::string& keyDescription,
  177. std::string* errorMessage)
  178. {
  179. const std::string cachedValue = state->GetSafeCacheEntryValue(key);
  180. if (value.empty()) {
  181. value = cachedValue;
  182. }
  183. if (!cachedValue.empty() && cachedValue != value) {
  184. setErrorMessage(errorMessage,
  185. std::string("\"") + key +
  186. "\" is set but incompatible with configured " +
  187. keyDescription + " value.");
  188. return false;
  189. }
  190. return true;
  191. }
  192. bool cmServerProtocol1::DoActivate(const cmServerRequest& request,
  193. std::string* errorMessage)
  194. {
  195. std::string sourceDirectory = request.Data[kSOURCE_DIRECTORY_KEY].asString();
  196. std::string buildDirectory = request.Data[kBUILD_DIRECTORY_KEY].asString();
  197. std::string generator = request.Data[kGENERATOR_KEY].asString();
  198. std::string extraGenerator = request.Data[kEXTRA_GENERATOR_KEY].asString();
  199. std::string toolset = request.Data[kTOOLSET_KEY].asString();
  200. std::string platform = request.Data[kPLATFORM_KEY].asString();
  201. // normalize source and build directory
  202. if (!sourceDirectory.empty()) {
  203. sourceDirectory = cmSystemTools::CollapseFullPath(sourceDirectory);
  204. cmSystemTools::ConvertToUnixSlashes(sourceDirectory);
  205. }
  206. if (!buildDirectory.empty()) {
  207. buildDirectory = cmSystemTools::CollapseFullPath(buildDirectory);
  208. cmSystemTools::ConvertToUnixSlashes(buildDirectory);
  209. }
  210. if (buildDirectory.empty()) {
  211. setErrorMessage(errorMessage,
  212. std::string("\"") + kBUILD_DIRECTORY_KEY +
  213. "\" is missing.");
  214. return false;
  215. }
  216. cmake* cm = CMakeInstance();
  217. if (cmSystemTools::PathExists(buildDirectory)) {
  218. if (!cmSystemTools::FileIsDirectory(buildDirectory)) {
  219. setErrorMessage(errorMessage,
  220. std::string("\"") + kBUILD_DIRECTORY_KEY +
  221. "\" exists but is not a directory.");
  222. return false;
  223. }
  224. const std::string cachePath = cmake::FindCacheFile(buildDirectory);
  225. if (cm->LoadCache(cachePath)) {
  226. cmState* state = cm->GetState();
  227. // Check generator:
  228. if (!getOrTestValue(state, "CMAKE_GENERATOR", generator, "generator",
  229. errorMessage)) {
  230. return false;
  231. }
  232. // check extra generator:
  233. if (!getOrTestValue(state, "CMAKE_EXTRA_GENERATOR", extraGenerator,
  234. "extra generator", errorMessage)) {
  235. return false;
  236. }
  237. // check sourcedir:
  238. if (!getOrTestHomeDirectory(state, sourceDirectory, errorMessage)) {
  239. return false;
  240. }
  241. // check toolset:
  242. if (!getOrTestValue(state, "CMAKE_GENERATOR_TOOLSET", toolset, "toolset",
  243. errorMessage)) {
  244. return false;
  245. }
  246. // check platform:
  247. if (!getOrTestValue(state, "CMAKE_GENERATOR_PLATFORM", platform,
  248. "platform", errorMessage)) {
  249. return false;
  250. }
  251. }
  252. }
  253. if (sourceDirectory.empty()) {
  254. setErrorMessage(errorMessage,
  255. std::string("\"") + kSOURCE_DIRECTORY_KEY +
  256. "\" is unset but required.");
  257. return false;
  258. }
  259. if (!cmSystemTools::FileIsDirectory(sourceDirectory)) {
  260. setErrorMessage(errorMessage,
  261. std::string("\"") + kSOURCE_DIRECTORY_KEY +
  262. "\" is not a directory.");
  263. return false;
  264. }
  265. if (generator.empty()) {
  266. setErrorMessage(errorMessage,
  267. std::string("\"") + kGENERATOR_KEY +
  268. "\" is unset but required.");
  269. return false;
  270. }
  271. std::vector<cmake::GeneratorInfo> generators;
  272. cm->GetRegisteredGenerators(generators);
  273. auto baseIt = std::find_if(generators.begin(), generators.end(),
  274. [&generator](const cmake::GeneratorInfo& info) {
  275. return info.name == generator;
  276. });
  277. if (baseIt == generators.end()) {
  278. setErrorMessage(errorMessage,
  279. std::string("Generator \"") + generator +
  280. "\" not supported.");
  281. return false;
  282. }
  283. auto extraIt = std::find_if(
  284. generators.begin(), generators.end(),
  285. [&generator, &extraGenerator](const cmake::GeneratorInfo& info) {
  286. return info.baseName == generator && info.extraName == extraGenerator;
  287. });
  288. if (extraIt == generators.end()) {
  289. setErrorMessage(errorMessage,
  290. std::string("The combination of generator \"" + generator +
  291. "\" and extra generator \"" + extraGenerator +
  292. "\" is not supported."));
  293. return false;
  294. }
  295. if (!extraIt->supportsToolset && !toolset.empty()) {
  296. setErrorMessage(errorMessage,
  297. std::string("Toolset was provided but is not supported by "
  298. "the requested generator."));
  299. return false;
  300. }
  301. if (!extraIt->supportsPlatform && !platform.empty()) {
  302. setErrorMessage(errorMessage,
  303. std::string("Platform was provided but is not supported "
  304. "by the requested generator."));
  305. return false;
  306. }
  307. this->GeneratorInfo =
  308. GeneratorInformation(generator, extraGenerator, toolset, platform,
  309. sourceDirectory, buildDirectory);
  310. this->m_State = STATE_ACTIVE;
  311. return true;
  312. }
  313. void cmServerProtocol1::HandleCMakeFileChanges(const std::string& path,
  314. int event, int status)
  315. {
  316. assert(status == 0);
  317. static_cast<void>(status);
  318. if (!m_isDirty) {
  319. m_isDirty = true;
  320. SendSignal(kDIRTY_SIGNAL, Json::objectValue);
  321. }
  322. Json::Value obj = Json::objectValue;
  323. obj[kPATH_KEY] = path;
  324. Json::Value properties = Json::arrayValue;
  325. if (event & UV_RENAME) {
  326. properties.append(kRENAME_PROPERTY_VALUE);
  327. }
  328. if (event & UV_CHANGE) {
  329. properties.append(kCHANGE_PROPERTY_VALUE);
  330. }
  331. obj[kPROPERTIES_KEY] = properties;
  332. SendSignal(kFILE_CHANGE_SIGNAL, obj);
  333. }
  334. cmServerResponse cmServerProtocol1::Process(const cmServerRequest& request)
  335. {
  336. assert(this->m_State >= STATE_ACTIVE);
  337. if (request.Type == kCACHE_TYPE) {
  338. return this->ProcessCache(request);
  339. }
  340. if (request.Type == kCMAKE_INPUTS_TYPE) {
  341. return this->ProcessCMakeInputs(request);
  342. }
  343. if (request.Type == kCODE_MODEL_TYPE) {
  344. return this->ProcessCodeModel(request);
  345. }
  346. if (request.Type == kCOMPUTE_TYPE) {
  347. return this->ProcessCompute(request);
  348. }
  349. if (request.Type == kCONFIGURE_TYPE) {
  350. return this->ProcessConfigure(request);
  351. }
  352. if (request.Type == kFILESYSTEM_WATCHERS_TYPE) {
  353. return this->ProcessFileSystemWatchers(request);
  354. }
  355. if (request.Type == kGLOBAL_SETTINGS_TYPE) {
  356. return this->ProcessGlobalSettings(request);
  357. }
  358. if (request.Type == kSET_GLOBAL_SETTINGS_TYPE) {
  359. return this->ProcessSetGlobalSettings(request);
  360. }
  361. if (request.Type == kCTEST_INFO_TYPE) {
  362. return this->ProcessCTests(request);
  363. }
  364. return request.ReportError("Unknown command!");
  365. }
  366. bool cmServerProtocol1::IsExperimental() const
  367. {
  368. return true;
  369. }
  370. cmServerResponse cmServerProtocol1::ProcessCache(
  371. const cmServerRequest& request)
  372. {
  373. cmState* state = this->CMakeInstance()->GetState();
  374. Json::Value result = Json::objectValue;
  375. std::vector<std::string> allKeys = state->GetCacheEntryKeys();
  376. Json::Value list = Json::arrayValue;
  377. std::vector<std::string> keys = toStringList(request.Data[kKEYS_KEY]);
  378. if (keys.empty()) {
  379. keys = allKeys;
  380. } else {
  381. for (auto const& i : keys) {
  382. if (!cmContains(allKeys, i)) {
  383. return request.ReportError("Key \"" + i + "\" not found in cache.");
  384. }
  385. }
  386. }
  387. std::sort(keys.begin(), keys.end());
  388. for (auto const& key : keys) {
  389. Json::Value entry = Json::objectValue;
  390. entry[kKEY_KEY] = key;
  391. entry[kTYPE_KEY] =
  392. cmState::CacheEntryTypeToString(state->GetCacheEntryType(key));
  393. entry[kVALUE_KEY] = state->GetCacheEntryValue(key);
  394. Json::Value props = Json::objectValue;
  395. bool haveProperties = false;
  396. for (auto const& prop : state->GetCacheEntryPropertyList(key)) {
  397. haveProperties = true;
  398. props[prop] = *state->GetCacheEntryProperty(key, prop);
  399. }
  400. if (haveProperties) {
  401. entry[kPROPERTIES_KEY] = props;
  402. }
  403. list.append(entry);
  404. }
  405. result[kCACHE_KEY] = list;
  406. return request.Reply(result);
  407. }
  408. cmServerResponse cmServerProtocol1::ProcessCMakeInputs(
  409. const cmServerRequest& request)
  410. {
  411. if (this->m_State < STATE_CONFIGURED) {
  412. return request.ReportError("This instance was not yet configured.");
  413. }
  414. const cmake* cm = this->CMakeInstance();
  415. const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot();
  416. const std::string& sourceDir = cm->GetHomeDirectory();
  417. Json::Value result = Json::objectValue;
  418. result[kSOURCE_DIRECTORY_KEY] = sourceDir;
  419. result[kCMAKE_ROOT_DIRECTORY_KEY] = cmakeRootDir;
  420. result[kBUILD_FILES_KEY] = cmDumpCMakeInputs(cm);
  421. return request.Reply(result);
  422. }
  423. cmServerResponse cmServerProtocol1::ProcessCodeModel(
  424. const cmServerRequest& request)
  425. {
  426. if (this->m_State != STATE_COMPUTED) {
  427. return request.ReportError("No build system was generated yet.");
  428. }
  429. return request.Reply(cmDumpCodeModel(this->CMakeInstance()));
  430. }
  431. cmServerResponse cmServerProtocol1::ProcessCompute(
  432. const cmServerRequest& request)
  433. {
  434. if (this->m_State > STATE_CONFIGURED) {
  435. return request.ReportError("This build system was already generated.");
  436. }
  437. if (this->m_State < STATE_CONFIGURED) {
  438. return request.ReportError("This project was not configured yet.");
  439. }
  440. cmake* cm = this->CMakeInstance();
  441. int ret = cm->Generate();
  442. if (ret < 0) {
  443. return request.ReportError("Failed to compute build system.");
  444. }
  445. m_State = STATE_COMPUTED;
  446. return request.Reply(Json::Value());
  447. }
  448. cmServerResponse cmServerProtocol1::ProcessConfigure(
  449. const cmServerRequest& request)
  450. {
  451. if (this->m_State == STATE_INACTIVE) {
  452. return request.ReportError("This instance is inactive.");
  453. }
  454. FileMonitor()->StopMonitoring();
  455. std::string errorMessage;
  456. cmake* cm = this->CMakeInstance();
  457. this->GeneratorInfo.SetupGenerator(cm, &errorMessage);
  458. if (!errorMessage.empty()) {
  459. return request.ReportError(errorMessage);
  460. }
  461. // Make sure the types of cacheArguments matches (if given):
  462. std::vector<std::string> cacheArgs = { "unused" };
  463. bool cacheArgumentsError = false;
  464. const Json::Value passedArgs = request.Data[kCACHE_ARGUMENTS_KEY];
  465. if (!passedArgs.isNull()) {
  466. if (passedArgs.isString()) {
  467. cacheArgs.push_back(passedArgs.asString());
  468. } else if (passedArgs.isArray()) {
  469. for (auto const& arg : passedArgs) {
  470. if (!arg.isString()) {
  471. cacheArgumentsError = true;
  472. break;
  473. }
  474. cacheArgs.push_back(arg.asString());
  475. }
  476. } else {
  477. cacheArgumentsError = true;
  478. }
  479. }
  480. if (cacheArgumentsError) {
  481. request.ReportError(
  482. "cacheArguments must be unset, a string or an array of strings.");
  483. }
  484. std::string sourceDir = cm->GetHomeDirectory();
  485. const std::string buildDir = cm->GetHomeOutputDirectory();
  486. cmGlobalGenerator* gg = cm->GetGlobalGenerator();
  487. if (buildDir.empty()) {
  488. return request.ReportError("No build directory set via Handshake.");
  489. }
  490. if (cm->LoadCache(buildDir)) {
  491. // build directory has been set up before
  492. const std::string* cachedSourceDir =
  493. cm->GetState()->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY");
  494. if (!cachedSourceDir) {
  495. return request.ReportError("No CMAKE_HOME_DIRECTORY found in cache.");
  496. }
  497. if (sourceDir.empty()) {
  498. sourceDir = *cachedSourceDir;
  499. cm->SetHomeDirectory(sourceDir);
  500. }
  501. const std::string* cachedGenerator =
  502. cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR");
  503. if (cachedGenerator) {
  504. if (gg && gg->GetName() != *cachedGenerator) {
  505. return request.ReportError("Configured generator does not match with "
  506. "CMAKE_GENERATOR found in cache.");
  507. }
  508. }
  509. } else {
  510. // build directory has not been set up before
  511. if (sourceDir.empty()) {
  512. return request.ReportError("No sourceDirectory set via "
  513. "setGlobalSettings and no cache found in "
  514. "buildDirectory.");
  515. }
  516. }
  517. cmSystemTools::ResetErrorOccuredFlag(); // Reset error state
  518. if (cm->AddCMakePaths() != 1) {
  519. return request.ReportError("Failed to set CMake paths.");
  520. }
  521. if (!cm->SetCacheArgs(cacheArgs)) {
  522. return request.ReportError("cacheArguments could not be set.");
  523. }
  524. int ret = cm->Configure();
  525. cm->IssueMessage(
  526. MessageType::DEPRECATION_WARNING,
  527. "The 'cmake-server(7)' is deprecated. "
  528. "Please port clients to use the 'cmake-file-api(7)' instead.");
  529. if (ret < 0) {
  530. return request.ReportError("Configuration failed.");
  531. }
  532. std::vector<std::string> toWatchList;
  533. cmGetCMakeInputs(gg, std::string(), buildDir, nullptr, &toWatchList,
  534. nullptr);
  535. FileMonitor()->MonitorPaths(toWatchList,
  536. [this](const std::string& p, int e, int s) {
  537. this->HandleCMakeFileChanges(p, e, s);
  538. });
  539. m_State = STATE_CONFIGURED;
  540. m_isDirty = false;
  541. return request.Reply(Json::Value());
  542. }
  543. cmServerResponse cmServerProtocol1::ProcessGlobalSettings(
  544. const cmServerRequest& request)
  545. {
  546. cmake* cm = this->CMakeInstance();
  547. Json::Value obj = Json::objectValue;
  548. // Capabilities information:
  549. obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson();
  550. obj[kDEBUG_OUTPUT_KEY] = cm->GetDebugOutput();
  551. obj[kTRACE_KEY] = cm->GetTrace();
  552. obj[kTRACE_EXPAND_KEY] = cm->GetTraceExpand();
  553. obj[kWARN_UNINITIALIZED_KEY] = cm->GetWarnUninitialized();
  554. obj[kWARN_UNUSED_KEY] = cm->GetWarnUnused();
  555. obj[kWARN_UNUSED_CLI_KEY] = cm->GetWarnUnusedCli();
  556. obj[kCHECK_SYSTEM_VARS_KEY] = cm->GetCheckSystemVars();
  557. obj[kSOURCE_DIRECTORY_KEY] = this->GeneratorInfo.SourceDirectory;
  558. obj[kBUILD_DIRECTORY_KEY] = this->GeneratorInfo.BuildDirectory;
  559. // Currently used generator:
  560. obj[kGENERATOR_KEY] = this->GeneratorInfo.GeneratorName;
  561. obj[kEXTRA_GENERATOR_KEY] = this->GeneratorInfo.ExtraGeneratorName;
  562. return request.Reply(obj);
  563. }
  564. static void setBool(const cmServerRequest& request, const std::string& key,
  565. std::function<void(bool)> const& setter)
  566. {
  567. if (request.Data[key].isNull()) {
  568. return;
  569. }
  570. setter(request.Data[key].asBool());
  571. }
  572. cmServerResponse cmServerProtocol1::ProcessSetGlobalSettings(
  573. const cmServerRequest& request)
  574. {
  575. const std::vector<std::string> boolValues = {
  576. kDEBUG_OUTPUT_KEY, kTRACE_KEY, kTRACE_EXPAND_KEY,
  577. kWARN_UNINITIALIZED_KEY, kWARN_UNUSED_KEY, kWARN_UNUSED_CLI_KEY,
  578. kCHECK_SYSTEM_VARS_KEY
  579. };
  580. for (std::string const& i : boolValues) {
  581. if (!request.Data[i].isNull() && !request.Data[i].isBool()) {
  582. return request.ReportError("\"" + i +
  583. "\" must be unset or a bool value.");
  584. }
  585. }
  586. cmake* cm = this->CMakeInstance();
  587. setBool(request, kDEBUG_OUTPUT_KEY,
  588. [cm](bool e) { cm->SetDebugOutputOn(e); });
  589. setBool(request, kTRACE_KEY, [cm](bool e) { cm->SetTrace(e); });
  590. setBool(request, kTRACE_EXPAND_KEY, [cm](bool e) { cm->SetTraceExpand(e); });
  591. setBool(request, kWARN_UNINITIALIZED_KEY,
  592. [cm](bool e) { cm->SetWarnUninitialized(e); });
  593. setBool(request, kWARN_UNUSED_KEY, [cm](bool e) { cm->SetWarnUnused(e); });
  594. setBool(request, kWARN_UNUSED_CLI_KEY,
  595. [cm](bool e) { cm->SetWarnUnusedCli(e); });
  596. setBool(request, kCHECK_SYSTEM_VARS_KEY,
  597. [cm](bool e) { cm->SetCheckSystemVars(e); });
  598. return request.Reply(Json::Value());
  599. }
  600. cmServerResponse cmServerProtocol1::ProcessFileSystemWatchers(
  601. const cmServerRequest& request)
  602. {
  603. const cmFileMonitor* const fm = FileMonitor();
  604. Json::Value result = Json::objectValue;
  605. Json::Value files = Json::arrayValue;
  606. for (auto const& f : fm->WatchedFiles()) {
  607. files.append(f);
  608. }
  609. Json::Value directories = Json::arrayValue;
  610. for (auto const& d : fm->WatchedDirectories()) {
  611. directories.append(d);
  612. }
  613. result[kWATCHED_FILES_KEY] = files;
  614. result[kWATCHED_DIRECTORIES_KEY] = directories;
  615. return request.Reply(result);
  616. }
  617. cmServerResponse cmServerProtocol1::ProcessCTests(
  618. const cmServerRequest& request)
  619. {
  620. if (this->m_State < STATE_COMPUTED) {
  621. return request.ReportError("This instance was not yet computed.");
  622. }
  623. return request.Reply(cmDumpCTestInfo(this->CMakeInstance()));
  624. }
  625. cmServerProtocol1::GeneratorInformation::GeneratorInformation(
  626. std::string generatorName, std::string extraGeneratorName,
  627. std::string toolset, std::string platform, std::string sourceDirectory,
  628. std::string buildDirectory)
  629. : GeneratorName(std::move(generatorName))
  630. , ExtraGeneratorName(std::move(extraGeneratorName))
  631. , Toolset(std::move(toolset))
  632. , Platform(std::move(platform))
  633. , SourceDirectory(std::move(sourceDirectory))
  634. , BuildDirectory(std::move(buildDirectory))
  635. {
  636. }
  637. void cmServerProtocol1::GeneratorInformation::SetupGenerator(
  638. cmake* cm, std::string* errorMessage)
  639. {
  640. const std::string fullGeneratorName =
  641. cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
  642. GeneratorName, ExtraGeneratorName);
  643. cm->SetHomeDirectory(SourceDirectory);
  644. cm->SetHomeOutputDirectory(BuildDirectory);
  645. auto gg = cm->CreateGlobalGenerator(fullGeneratorName);
  646. if (!gg) {
  647. setErrorMessage(
  648. errorMessage,
  649. std::string("Could not set up the requested combination of \"") +
  650. kGENERATOR_KEY + "\" and \"" + kEXTRA_GENERATOR_KEY + "\"");
  651. return;
  652. }
  653. cm->SetGlobalGenerator(std::move(gg));
  654. cm->SetGeneratorToolset(Toolset);
  655. cm->SetGeneratorPlatform(Platform);
  656. }