cmCMakePresetsGraphReadJSON.cxx 21 KB

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