cmCMakePresetsGraphReadJSON.cxx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  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 <algorithm>
  4. #include <functional>
  5. #include <map>
  6. #include <string>
  7. #include <unordered_set>
  8. #include <utility>
  9. #include <vector>
  10. #include <cm/memory>
  11. #include <cm/optional>
  12. #include <cmext/string_view>
  13. #include <cm3p/json/reader.h>
  14. #include <cm3p/json/value.h>
  15. #include "cmsys/FStream.hxx"
  16. #include "cmCMakePresetsGraph.h"
  17. #include "cmCMakePresetsGraphInternal.h"
  18. #include "cmJSONHelpers.h"
  19. #include "cmStringAlgorithms.h"
  20. #include "cmSystemTools.h"
  21. #include "cmVersion.h"
  22. namespace {
  23. using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
  24. using CacheVariable = cmCMakePresetsGraph::CacheVariable;
  25. using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
  26. using BuildPreset = cmCMakePresetsGraph::BuildPreset;
  27. using TestPreset = cmCMakePresetsGraph::TestPreset;
  28. using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy;
  29. using JSONHelperBuilder = cmJSONHelperBuilder<ReadFileResult>;
  30. constexpr int MIN_VERSION = 1;
  31. constexpr int MAX_VERSION = 5;
  32. struct CMakeVersion
  33. {
  34. unsigned int Major = 0;
  35. unsigned int Minor = 0;
  36. unsigned int Patch = 0;
  37. };
  38. struct RootPresets
  39. {
  40. CMakeVersion CMakeMinimumRequired;
  41. std::vector<cmCMakePresetsGraph::ConfigurePreset> ConfigurePresets;
  42. std::vector<cmCMakePresetsGraph::BuildPreset> BuildPresets;
  43. std::vector<cmCMakePresetsGraph::TestPreset> TestPresets;
  44. std::vector<std::string> Include;
  45. };
  46. std::unique_ptr<cmCMakePresetsGraphInternal::NotCondition> InvertCondition(
  47. std::unique_ptr<cmCMakePresetsGraph::Condition> condition)
  48. {
  49. auto retval = cm::make_unique<cmCMakePresetsGraphInternal::NotCondition>();
  50. retval->SubCondition = std::move(condition);
  51. return retval;
  52. }
  53. auto const ConditionStringHelper = JSONHelperBuilder::String(
  54. ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION);
  55. auto const ConditionBoolHelper = JSONHelperBuilder::Bool(
  56. ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION);
  57. auto const ConditionStringListHelper = JSONHelperBuilder::Vector<std::string>(
  58. ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION,
  59. ConditionStringHelper);
  60. auto const ConstConditionHelper =
  61. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::ConstCondition>(
  62. ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false)
  63. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  64. .Bind("value"_s, &cmCMakePresetsGraphInternal::ConstCondition::Value,
  65. ConditionBoolHelper, true);
  66. auto const EqualsConditionHelper =
  67. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::EqualsCondition>(
  68. ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false)
  69. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  70. .Bind("lhs"_s, &cmCMakePresetsGraphInternal::EqualsCondition::Lhs,
  71. ConditionStringHelper, true)
  72. .Bind("rhs"_s, &cmCMakePresetsGraphInternal::EqualsCondition::Rhs,
  73. ConditionStringHelper, true);
  74. auto const InListConditionHelper =
  75. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::InListCondition>(
  76. ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false)
  77. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  78. .Bind("string"_s, &cmCMakePresetsGraphInternal::InListCondition::String,
  79. ConditionStringHelper, true)
  80. .Bind("list"_s, &cmCMakePresetsGraphInternal::InListCondition::List,
  81. ConditionStringListHelper, true);
  82. auto const MatchesConditionHelper =
  83. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::MatchesCondition>(
  84. ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false)
  85. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  86. .Bind("string"_s, &cmCMakePresetsGraphInternal::MatchesCondition::String,
  87. ConditionStringHelper, true)
  88. .Bind("regex"_s, &cmCMakePresetsGraphInternal::MatchesCondition::Regex,
  89. ConditionStringHelper, true);
  90. ReadFileResult SubConditionHelper(
  91. std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
  92. const Json::Value* value);
  93. auto const ListConditionVectorHelper =
  94. JSONHelperBuilder::Vector<std::unique_ptr<cmCMakePresetsGraph::Condition>>(
  95. ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION,
  96. SubConditionHelper);
  97. auto const AnyAllOfConditionHelper =
  98. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::AnyAllOfCondition>(
  99. ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false)
  100. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  101. .Bind("conditions"_s,
  102. &cmCMakePresetsGraphInternal::AnyAllOfCondition::Conditions,
  103. ListConditionVectorHelper);
  104. auto const NotConditionHelper =
  105. JSONHelperBuilder::Object<cmCMakePresetsGraphInternal::NotCondition>(
  106. ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false)
  107. .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
  108. .Bind("condition"_s,
  109. &cmCMakePresetsGraphInternal::NotCondition::SubCondition,
  110. SubConditionHelper);
  111. ReadFileResult ConditionHelper(
  112. std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
  113. const Json::Value* value)
  114. {
  115. if (!value) {
  116. out.reset();
  117. return ReadFileResult::READ_OK;
  118. }
  119. if (value->isBool()) {
  120. auto c = cm::make_unique<cmCMakePresetsGraphInternal::ConstCondition>();
  121. c->Value = value->asBool();
  122. out = std::move(c);
  123. return ReadFileResult::READ_OK;
  124. }
  125. if (value->isNull()) {
  126. out = cm::make_unique<cmCMakePresetsGraphInternal::NullCondition>();
  127. return ReadFileResult::READ_OK;
  128. }
  129. if (value->isObject()) {
  130. if (!value->isMember("type")) {
  131. return ReadFileResult::INVALID_CONDITION;
  132. }
  133. if (!(*value)["type"].isString()) {
  134. return ReadFileResult::INVALID_CONDITION;
  135. }
  136. auto type = (*value)["type"].asString();
  137. if (type == "const") {
  138. auto c = cm::make_unique<cmCMakePresetsGraphInternal::ConstCondition>();
  139. CHECK_OK(ConstConditionHelper(*c, value));
  140. out = std::move(c);
  141. return ReadFileResult::READ_OK;
  142. }
  143. if (type == "equals" || type == "notEquals") {
  144. auto c = cm::make_unique<cmCMakePresetsGraphInternal::EqualsCondition>();
  145. CHECK_OK(EqualsConditionHelper(*c, value));
  146. out = std::move(c);
  147. if (type == "notEquals") {
  148. out = InvertCondition(std::move(out));
  149. }
  150. return ReadFileResult::READ_OK;
  151. }
  152. if (type == "inList" || type == "notInList") {
  153. auto c = cm::make_unique<cmCMakePresetsGraphInternal::InListCondition>();
  154. CHECK_OK(InListConditionHelper(*c, value));
  155. out = std::move(c);
  156. if (type == "notInList") {
  157. out = InvertCondition(std::move(out));
  158. }
  159. return ReadFileResult::READ_OK;
  160. }
  161. if (type == "matches" || type == "notMatches") {
  162. auto c =
  163. cm::make_unique<cmCMakePresetsGraphInternal::MatchesCondition>();
  164. CHECK_OK(MatchesConditionHelper(*c, value));
  165. out = std::move(c);
  166. if (type == "notMatches") {
  167. out = InvertCondition(std::move(out));
  168. }
  169. return ReadFileResult::READ_OK;
  170. }
  171. if (type == "anyOf" || type == "allOf") {
  172. auto c =
  173. cm::make_unique<cmCMakePresetsGraphInternal::AnyAllOfCondition>();
  174. c->StopValue = (type == "anyOf");
  175. CHECK_OK(AnyAllOfConditionHelper(*c, value));
  176. out = std::move(c);
  177. return ReadFileResult::READ_OK;
  178. }
  179. if (type == "not") {
  180. auto c = cm::make_unique<cmCMakePresetsGraphInternal::NotCondition>();
  181. CHECK_OK(NotConditionHelper(*c, value));
  182. out = std::move(c);
  183. return ReadFileResult::READ_OK;
  184. }
  185. }
  186. return ReadFileResult::INVALID_CONDITION;
  187. }
  188. ReadFileResult SubConditionHelper(
  189. std::unique_ptr<cmCMakePresetsGraph::Condition>& out,
  190. const Json::Value* value)
  191. {
  192. std::unique_ptr<cmCMakePresetsGraph::Condition> ptr;
  193. auto result = ConditionHelper(ptr, value);
  194. if (ptr && ptr->IsNull()) {
  195. return ReadFileResult::INVALID_CONDITION;
  196. }
  197. out = std::move(ptr);
  198. return result;
  199. }
  200. ReadFileResult EnvironmentHelper(cm::optional<std::string>& out,
  201. const Json::Value* value)
  202. {
  203. if (!value || value->isNull()) {
  204. out = cm::nullopt;
  205. return ReadFileResult::READ_OK;
  206. }
  207. if (value->isString()) {
  208. out = value->asString();
  209. return ReadFileResult::READ_OK;
  210. }
  211. return ReadFileResult::INVALID_PRESET;
  212. }
  213. auto const VersionIntHelper = JSONHelperBuilder::Int(
  214. ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
  215. auto const VersionHelper = JSONHelperBuilder::Required<int>(
  216. ReadFileResult::NO_VERSION, VersionIntHelper);
  217. auto const RootVersionHelper =
  218. JSONHelperBuilder::Object<int>(ReadFileResult::READ_OK,
  219. ReadFileResult::INVALID_ROOT)
  220. .Bind("version"_s, VersionHelper, false);
  221. auto const CMakeVersionUIntHelper = JSONHelperBuilder::UInt(
  222. ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
  223. auto const CMakeVersionHelper =
  224. JSONHelperBuilder::Object<CMakeVersion>(
  225. ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false)
  226. .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false)
  227. .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
  228. .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
  229. auto const IncludeHelper = JSONHelperBuilder::String(
  230. ReadFileResult::READ_OK, ReadFileResult::INVALID_INCLUDE);
  231. auto const IncludeVectorHelper = JSONHelperBuilder::Vector<std::string>(
  232. ReadFileResult::READ_OK, ReadFileResult::INVALID_INCLUDE, IncludeHelper);
  233. auto const RootPresetsHelper =
  234. JSONHelperBuilder::Object<RootPresets>(ReadFileResult::READ_OK,
  235. ReadFileResult::INVALID_ROOT, false)
  236. .Bind<int>("version"_s, nullptr, VersionHelper)
  237. .Bind("configurePresets"_s, &RootPresets::ConfigurePresets,
  238. cmCMakePresetsGraphInternal::ConfigurePresetsHelper, false)
  239. .Bind("buildPresets"_s, &RootPresets::BuildPresets,
  240. cmCMakePresetsGraphInternal::BuildPresetsHelper, false)
  241. .Bind("testPresets"_s, &RootPresets::TestPresets,
  242. cmCMakePresetsGraphInternal::TestPresetsHelper, false)
  243. .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
  244. CMakeVersionHelper, false)
  245. .Bind("include"_s, &RootPresets::Include, IncludeVectorHelper, false)
  246. .Bind<std::nullptr_t>(
  247. "vendor"_s, nullptr,
  248. cmCMakePresetsGraphInternal::VendorHelper(ReadFileResult::INVALID_ROOT),
  249. false);
  250. }
  251. namespace cmCMakePresetsGraphInternal {
  252. cmCMakePresetsGraph::ReadFileResult PresetStringHelper(
  253. std::string& out, const Json::Value* value)
  254. {
  255. static auto const helper = JSONHelperBuilder::String(
  256. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
  257. return helper(out, value);
  258. }
  259. cmCMakePresetsGraph::ReadFileResult PresetVectorStringHelper(
  260. std::vector<std::string>& out, const Json::Value* value)
  261. {
  262. static auto const helper = JSONHelperBuilder::Vector<std::string>(
  263. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
  264. cmCMakePresetsGraphInternal::PresetStringHelper);
  265. return helper(out, value);
  266. }
  267. cmCMakePresetsGraph::ReadFileResult PresetBoolHelper(bool& out,
  268. const Json::Value* value)
  269. {
  270. static auto const helper = JSONHelperBuilder::Bool(
  271. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
  272. return helper(out, value);
  273. }
  274. cmCMakePresetsGraph::ReadFileResult PresetOptionalBoolHelper(
  275. cm::optional<bool>& out, const Json::Value* value)
  276. {
  277. static auto const helper = JSONHelperBuilder::Optional<bool>(
  278. ReadFileResult::READ_OK, PresetBoolHelper);
  279. return helper(out, value);
  280. }
  281. cmCMakePresetsGraph::ReadFileResult PresetIntHelper(int& out,
  282. const Json::Value* value)
  283. {
  284. static auto const helper = JSONHelperBuilder::Int(
  285. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
  286. return helper(out, value);
  287. }
  288. cmCMakePresetsGraph::ReadFileResult PresetOptionalIntHelper(
  289. cm::optional<int>& out, const Json::Value* value)
  290. {
  291. static auto const helper =
  292. JSONHelperBuilder::Optional<int>(ReadFileResult::READ_OK, PresetIntHelper);
  293. return helper(out, value);
  294. }
  295. cmCMakePresetsGraph::ReadFileResult PresetVectorIntHelper(
  296. std::vector<int>& out, const Json::Value* value)
  297. {
  298. static auto const helper = JSONHelperBuilder::Vector<int>(
  299. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper);
  300. return helper(out, value);
  301. }
  302. cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error)
  303. {
  304. return [error](std::nullptr_t& /*out*/,
  305. const Json::Value* value) -> ReadFileResult {
  306. if (!value) {
  307. return ReadFileResult::READ_OK;
  308. }
  309. if (!value->isObject()) {
  310. return error;
  311. }
  312. return ReadFileResult::READ_OK;
  313. };
  314. }
  315. ReadFileResult PresetConditionHelper(
  316. std::shared_ptr<cmCMakePresetsGraph::Condition>& out,
  317. const Json::Value* value)
  318. {
  319. std::unique_ptr<cmCMakePresetsGraph::Condition> ptr;
  320. auto result = ConditionHelper(ptr, value);
  321. out = std::move(ptr);
  322. return result;
  323. }
  324. ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out,
  325. const Json::Value* value)
  326. {
  327. out.clear();
  328. if (!value) {
  329. return ReadFileResult::READ_OK;
  330. }
  331. if (value->isString()) {
  332. out.push_back(value->asString());
  333. return ReadFileResult::READ_OK;
  334. }
  335. return PresetVectorStringHelper(out, value);
  336. }
  337. cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper(
  338. std::map<std::string, cm::optional<std::string>>& out,
  339. const Json::Value* value)
  340. {
  341. static auto const helper = JSONHelperBuilder::Map<cm::optional<std::string>>(
  342. ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
  343. EnvironmentHelper);
  344. return helper(out, value);
  345. }
  346. }
  347. cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
  348. const std::string& filename, RootType rootType, ReadReason readReason,
  349. std::vector<File*>& inProgressFiles, File*& file, std::string& errMsg)
  350. {
  351. ReadFileResult result;
  352. for (auto const& f : this->Files) {
  353. if (cmSystemTools::SameFile(filename, f->Filename)) {
  354. file = f.get();
  355. auto fileIt =
  356. std::find(inProgressFiles.begin(), inProgressFiles.end(), file);
  357. if (fileIt != inProgressFiles.end()) {
  358. return cmCMakePresetsGraph::ReadFileResult::CYCLIC_INCLUDE;
  359. }
  360. return cmCMakePresetsGraph::ReadFileResult::READ_OK;
  361. }
  362. }
  363. cmsys::ifstream fin(filename.c_str());
  364. if (!fin) {
  365. errMsg = cmStrCat(filename, ": Failed to read file\n", errMsg);
  366. return ReadFileResult::FILE_NOT_FOUND;
  367. }
  368. // If there's a BOM, toss it.
  369. cmsys::FStream::ReadBOM(fin);
  370. Json::Value root;
  371. Json::CharReaderBuilder builder;
  372. Json::CharReaderBuilder::strictMode(&builder.settings_);
  373. if (!Json::parseFromStream(builder, fin, &root, &errMsg)) {
  374. errMsg = cmStrCat(filename, ":\n", errMsg);
  375. return ReadFileResult::JSON_PARSE_ERROR;
  376. }
  377. int v = 0;
  378. if ((result = RootVersionHelper(v, &root)) != ReadFileResult::READ_OK) {
  379. return result;
  380. }
  381. if (v < MIN_VERSION || v > MAX_VERSION) {
  382. return ReadFileResult::UNRECOGNIZED_VERSION;
  383. }
  384. // Support for build and test presets added in version 2.
  385. if (v < 2 &&
  386. (root.isMember("buildPresets") || root.isMember("testPresets"))) {
  387. return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED;
  388. }
  389. // Support for include added in version 4.
  390. if (v < 4 && root.isMember("include")) {
  391. return ReadFileResult::INCLUDE_UNSUPPORTED;
  392. }
  393. RootPresets presets;
  394. if ((result = RootPresetsHelper(presets, &root)) !=
  395. ReadFileResult::READ_OK) {
  396. return result;
  397. }
  398. unsigned int currentMajor = cmVersion::GetMajorVersion();
  399. unsigned int currentMinor = cmVersion::GetMinorVersion();
  400. unsigned int currentPatch = cmVersion::GetPatchVersion();
  401. auto const& required = presets.CMakeMinimumRequired;
  402. if (required.Major > currentMajor ||
  403. (required.Major == currentMajor &&
  404. (required.Minor > currentMinor ||
  405. (required.Minor == currentMinor &&
  406. (required.Patch > currentPatch))))) {
  407. return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION;
  408. }
  409. auto filePtr = cm::make_unique<File>();
  410. file = filePtr.get();
  411. this->Files.emplace_back(std::move(filePtr));
  412. inProgressFiles.emplace_back(file);
  413. file->Filename = filename;
  414. file->Version = v;
  415. file->ReachableFiles.insert(file);
  416. for (auto& preset : presets.ConfigurePresets) {
  417. preset.OriginFile = file;
  418. if (preset.Name.empty()) {
  419. errMsg += R"(\n\t)";
  420. errMsg += filename;
  421. return ReadFileResult::INVALID_PRESET;
  422. }
  423. PresetPair<ConfigurePreset> presetPair;
  424. presetPair.Unexpanded = preset;
  425. presetPair.Expanded = cm::nullopt;
  426. if (!this->ConfigurePresets
  427. .emplace(std::make_pair(preset.Name, presetPair))
  428. .second) {
  429. return ReadFileResult::DUPLICATE_PRESETS;
  430. }
  431. // Support for installDir presets added in version 3.
  432. if (v < 3 && !preset.InstallDir.empty()) {
  433. return ReadFileResult::INSTALL_PREFIX_UNSUPPORTED;
  434. }
  435. // Support for conditions added in version 3.
  436. if (v < 3 && preset.ConditionEvaluator) {
  437. return ReadFileResult::CONDITION_UNSUPPORTED;
  438. }
  439. // Support for toolchainFile presets added in version 3.
  440. if (v < 3 && !preset.ToolchainFile.empty()) {
  441. return ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED;
  442. }
  443. this->ConfigurePresetOrder.push_back(preset.Name);
  444. }
  445. for (auto& preset : presets.BuildPresets) {
  446. preset.OriginFile = file;
  447. if (preset.Name.empty()) {
  448. errMsg += R"(\n\t)";
  449. errMsg += filename;
  450. return ReadFileResult::INVALID_PRESET;
  451. }
  452. PresetPair<BuildPreset> presetPair;
  453. presetPair.Unexpanded = preset;
  454. presetPair.Expanded = cm::nullopt;
  455. if (!this->BuildPresets.emplace(preset.Name, presetPair).second) {
  456. return ReadFileResult::DUPLICATE_PRESETS;
  457. }
  458. // Support for conditions added in version 3.
  459. if (v < 3 && preset.ConditionEvaluator) {
  460. return ReadFileResult::CONDITION_UNSUPPORTED;
  461. }
  462. this->BuildPresetOrder.push_back(preset.Name);
  463. }
  464. for (auto& preset : presets.TestPresets) {
  465. preset.OriginFile = file;
  466. if (preset.Name.empty()) {
  467. return ReadFileResult::INVALID_PRESET;
  468. }
  469. PresetPair<TestPreset> presetPair;
  470. presetPair.Unexpanded = preset;
  471. presetPair.Expanded = cm::nullopt;
  472. if (!this->TestPresets.emplace(preset.Name, presetPair).second) {
  473. return ReadFileResult::DUPLICATE_PRESETS;
  474. }
  475. // Support for conditions added in version 3.
  476. if (v < 3 && preset.ConditionEvaluator) {
  477. return ReadFileResult::CONDITION_UNSUPPORTED;
  478. }
  479. // Support for TestOutputTruncation added in version 5.
  480. if (v < 5 && preset.Output && preset.Output->TestOutputTruncation) {
  481. return ReadFileResult::TEST_OUTPUT_TRUNCATION_UNSUPPORTED;
  482. }
  483. this->TestPresetOrder.push_back(preset.Name);
  484. }
  485. auto const includeFile = [this, &inProgressFiles, file](
  486. const std::string& include, RootType rootType2,
  487. ReadReason readReason2,
  488. std::string& FailureMessage) -> ReadFileResult {
  489. ReadFileResult r;
  490. File* includedFile;
  491. if ((r = this->ReadJSONFile(include, rootType2, readReason2,
  492. inProgressFiles, includedFile,
  493. FailureMessage)) != ReadFileResult::READ_OK) {
  494. return r;
  495. }
  496. file->ReachableFiles.insert(includedFile->ReachableFiles.begin(),
  497. includedFile->ReachableFiles.end());
  498. return ReadFileResult::READ_OK;
  499. };
  500. for (auto include : presets.Include) {
  501. if (!cmSystemTools::FileIsFullPath(include)) {
  502. auto directory = cmSystemTools::GetFilenamePath(filename);
  503. include = cmStrCat(directory, '/', include);
  504. }
  505. if ((result = includeFile(include, rootType, ReadReason::Included,
  506. errMsg)) != ReadFileResult::READ_OK) {
  507. return result;
  508. }
  509. }
  510. if (rootType == RootType::User && readReason == ReadReason::Root) {
  511. auto cmakePresetsFilename = GetFilename(this->SourceDir);
  512. if (cmSystemTools::FileExists(cmakePresetsFilename)) {
  513. if ((result = includeFile(cmakePresetsFilename, RootType::Project,
  514. ReadReason::Root, errMsg)) !=
  515. ReadFileResult::READ_OK) {
  516. return result;
  517. }
  518. }
  519. }
  520. inProgressFiles.pop_back();
  521. return ReadFileResult::READ_OK;
  522. }