cmCMakePresetsGraphReadJSON.cxx 22 KB

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