cmCMakePresetsGraph.cxx 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440
  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 "cmCMakePresetsGraph.h"
  4. #include <algorithm>
  5. #include <cassert>
  6. #include <cstdlib>
  7. #include <functional>
  8. #include <iostream>
  9. #include <iterator>
  10. #include <utility>
  11. #include <cm/string_view>
  12. #include "cmsys/RegularExpression.hxx"
  13. #include "cmCMakePresetsGraphInternal.h"
  14. #include "cmStringAlgorithms.h"
  15. #include "cmSystemTools.h"
  16. #define CHECK_EXPAND(out, field, expanders, version) \
  17. do { \
  18. switch (ExpandMacros(field, expanders, version)) { \
  19. case ExpandMacroResult::Error: \
  20. return false; \
  21. case ExpandMacroResult::Ignore: \
  22. out.reset(); \
  23. return true; \
  24. case ExpandMacroResult::Ok: \
  25. break; \
  26. } \
  27. } while (false)
  28. namespace {
  29. enum class CycleStatus
  30. {
  31. Unvisited,
  32. InProgress,
  33. Verified,
  34. };
  35. using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
  36. using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset;
  37. using BuildPreset = cmCMakePresetsGraph::BuildPreset;
  38. using TestPreset = cmCMakePresetsGraph::TestPreset;
  39. using PackagePreset = cmCMakePresetsGraph::PackagePreset;
  40. using WorkflowPreset = cmCMakePresetsGraph::WorkflowPreset;
  41. template <typename T>
  42. using PresetPair = cmCMakePresetsGraph::PresetPair<T>;
  43. using ExpandMacroResult = cmCMakePresetsGraphInternal::ExpandMacroResult;
  44. using MacroExpander = cmCMakePresetsGraphInternal::MacroExpander;
  45. void InheritString(std::string& child, const std::string& parent)
  46. {
  47. if (child.empty()) {
  48. child = parent;
  49. }
  50. }
  51. template <typename T>
  52. void InheritOptionalValue(cm::optional<T>& child,
  53. const cm::optional<T>& parent)
  54. {
  55. if (!child) {
  56. child = parent;
  57. }
  58. }
  59. template <typename T>
  60. void InheritVector(std::vector<T>& child, const std::vector<T>& parent)
  61. {
  62. if (child.empty()) {
  63. child = parent;
  64. }
  65. }
  66. /**
  67. * Check preset inheritance for cycles (using a DAG check algorithm) while
  68. * also bubbling up fields through the inheritance hierarchy, then verify
  69. * that each preset has the required fields, either directly or through
  70. * inheritance.
  71. */
  72. template <class T>
  73. ReadFileResult VisitPreset(
  74. T& preset,
  75. std::map<std::string, cmCMakePresetsGraph::PresetPair<T>>& presets,
  76. std::map<std::string, CycleStatus> cycleStatus,
  77. const cmCMakePresetsGraph& graph)
  78. {
  79. switch (cycleStatus[preset.Name]) {
  80. case CycleStatus::InProgress:
  81. return ReadFileResult::CYCLIC_PRESET_INHERITANCE;
  82. case CycleStatus::Verified:
  83. return ReadFileResult::READ_OK;
  84. default:
  85. break;
  86. }
  87. cycleStatus[preset.Name] = CycleStatus::InProgress;
  88. if (preset.Environment.count("") != 0) {
  89. return ReadFileResult::INVALID_PRESET;
  90. }
  91. CHECK_OK(preset.VisitPresetBeforeInherit());
  92. for (auto const& i : preset.Inherits) {
  93. auto parent = presets.find(i);
  94. if (parent == presets.end()) {
  95. return ReadFileResult::INVALID_PRESET;
  96. }
  97. auto& parentPreset = parent->second.Unexpanded;
  98. if (!preset.OriginFile->ReachableFiles.count(parentPreset.OriginFile)) {
  99. return ReadFileResult::INHERITED_PRESET_UNREACHABLE_FROM_FILE;
  100. }
  101. auto result = VisitPreset(parentPreset, presets, cycleStatus, graph);
  102. if (result != ReadFileResult::READ_OK) {
  103. return result;
  104. }
  105. CHECK_OK(preset.VisitPresetInherit(parentPreset));
  106. for (auto const& v : parentPreset.Environment) {
  107. preset.Environment.insert(v);
  108. }
  109. if (!preset.ConditionEvaluator) {
  110. preset.ConditionEvaluator = parentPreset.ConditionEvaluator;
  111. }
  112. }
  113. if (preset.ConditionEvaluator && preset.ConditionEvaluator->IsNull()) {
  114. preset.ConditionEvaluator.reset();
  115. }
  116. CHECK_OK(preset.VisitPresetAfterInherit(graph.GetVersion(preset)));
  117. cycleStatus[preset.Name] = CycleStatus::Verified;
  118. return ReadFileResult::READ_OK;
  119. }
  120. template <class T>
  121. ReadFileResult ComputePresetInheritance(
  122. std::map<std::string, cmCMakePresetsGraph::PresetPair<T>>& presets,
  123. const cmCMakePresetsGraph& graph)
  124. {
  125. std::map<std::string, CycleStatus> cycleStatus;
  126. for (auto const& it : presets) {
  127. cycleStatus[it.first] = CycleStatus::Unvisited;
  128. }
  129. for (auto& it : presets) {
  130. auto& preset = it.second.Unexpanded;
  131. auto result = VisitPreset<T>(preset, presets, cycleStatus, graph);
  132. if (result != ReadFileResult::READ_OK) {
  133. return result;
  134. }
  135. }
  136. return ReadFileResult::READ_OK;
  137. }
  138. constexpr const char* ValidPrefixes[] = {
  139. "",
  140. "env",
  141. "penv",
  142. "vendor",
  143. };
  144. bool PrefixesValidMacroNamespace(const std::string& str)
  145. {
  146. return std::any_of(
  147. std::begin(ValidPrefixes), std::end(ValidPrefixes),
  148. [&str](const char* prefix) -> bool { return cmHasPrefix(prefix, str); });
  149. }
  150. bool IsValidMacroNamespace(const std::string& str)
  151. {
  152. return std::any_of(
  153. std::begin(ValidPrefixes), std::end(ValidPrefixes),
  154. [&str](const char* prefix) -> bool { return str == prefix; });
  155. }
  156. ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status,
  157. const std::vector<MacroExpander>& macroExpanders,
  158. int version);
  159. ExpandMacroResult ExpandMacros(
  160. std::string& out, const std::vector<MacroExpander>& macroExpanders,
  161. int version);
  162. ExpandMacroResult ExpandMacro(std::string& out,
  163. const std::string& macroNamespace,
  164. const std::string& macroName,
  165. const std::vector<MacroExpander>& macroExpanders,
  166. int version);
  167. bool ExpandMacros(const cmCMakePresetsGraph& graph,
  168. const ConfigurePreset& preset,
  169. cm::optional<ConfigurePreset>& out,
  170. const std::vector<MacroExpander>& macroExpanders)
  171. {
  172. std::string binaryDir = preset.BinaryDir;
  173. CHECK_EXPAND(out, binaryDir, macroExpanders, graph.GetVersion(preset));
  174. if (!binaryDir.empty()) {
  175. if (!cmSystemTools::FileIsFullPath(binaryDir)) {
  176. binaryDir = cmStrCat(graph.SourceDir, '/', binaryDir);
  177. }
  178. out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir);
  179. cmSystemTools::ConvertToUnixSlashes(out->BinaryDir);
  180. }
  181. if (!preset.InstallDir.empty()) {
  182. std::string installDir = preset.InstallDir;
  183. CHECK_EXPAND(out, installDir, macroExpanders, graph.GetVersion(preset));
  184. if (!cmSystemTools::FileIsFullPath(installDir)) {
  185. installDir = cmStrCat(graph.SourceDir, '/', installDir);
  186. }
  187. out->InstallDir = cmSystemTools::CollapseFullPath(installDir);
  188. cmSystemTools::ConvertToUnixSlashes(out->InstallDir);
  189. }
  190. if (!preset.ToolchainFile.empty()) {
  191. std::string toolchain = preset.ToolchainFile;
  192. CHECK_EXPAND(out, toolchain, macroExpanders, graph.GetVersion(preset));
  193. out->ToolchainFile = toolchain;
  194. }
  195. for (auto& variable : out->CacheVariables) {
  196. if (variable.second) {
  197. CHECK_EXPAND(out, variable.second->Value, macroExpanders,
  198. graph.GetVersion(preset));
  199. }
  200. }
  201. return true;
  202. }
  203. bool ExpandMacros(const cmCMakePresetsGraph& graph, const BuildPreset& preset,
  204. cm::optional<BuildPreset>& out,
  205. const std::vector<MacroExpander>& macroExpanders)
  206. {
  207. for (auto& target : out->Targets) {
  208. CHECK_EXPAND(out, target, macroExpanders, graph.GetVersion(preset));
  209. }
  210. for (auto& nativeToolOption : out->NativeToolOptions) {
  211. CHECK_EXPAND(out, nativeToolOption, macroExpanders,
  212. graph.GetVersion(preset));
  213. }
  214. return true;
  215. }
  216. bool ExpandMacros(const cmCMakePresetsGraph& graph, const TestPreset& preset,
  217. cm::optional<TestPreset>& out,
  218. const std::vector<MacroExpander>& macroExpanders)
  219. {
  220. for (auto& overwrite : out->OverwriteConfigurationFile) {
  221. CHECK_EXPAND(out, overwrite, macroExpanders, graph.GetVersion(preset));
  222. }
  223. if (out->Output) {
  224. CHECK_EXPAND(out, out->Output->OutputLogFile, macroExpanders,
  225. graph.GetVersion(preset));
  226. }
  227. if (out->Filter) {
  228. if (out->Filter->Include) {
  229. CHECK_EXPAND(out, out->Filter->Include->Name, macroExpanders,
  230. graph.GetVersion(preset));
  231. CHECK_EXPAND(out, out->Filter->Include->Label, macroExpanders,
  232. graph.GetVersion(preset));
  233. if (out->Filter->Include->Index) {
  234. CHECK_EXPAND(out, out->Filter->Include->Index->IndexFile,
  235. macroExpanders, graph.GetVersion(preset));
  236. }
  237. }
  238. if (out->Filter->Exclude) {
  239. CHECK_EXPAND(out, out->Filter->Exclude->Name, macroExpanders,
  240. graph.GetVersion(preset));
  241. CHECK_EXPAND(out, out->Filter->Exclude->Label, macroExpanders,
  242. graph.GetVersion(preset));
  243. if (out->Filter->Exclude->Fixtures) {
  244. CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Any, macroExpanders,
  245. graph.GetVersion(preset));
  246. CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Setup,
  247. macroExpanders, graph.GetVersion(preset));
  248. CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Cleanup,
  249. macroExpanders, graph.GetVersion(preset));
  250. }
  251. }
  252. }
  253. if (out->Execution) {
  254. CHECK_EXPAND(out, out->Execution->ResourceSpecFile, macroExpanders,
  255. graph.GetVersion(preset));
  256. }
  257. return true;
  258. }
  259. bool ExpandMacros(const cmCMakePresetsGraph& graph,
  260. const PackagePreset& preset,
  261. cm::optional<PackagePreset>& out,
  262. const std::vector<MacroExpander>& macroExpanders)
  263. {
  264. for (auto& variable : out->Variables) {
  265. CHECK_EXPAND(out, variable.second, macroExpanders,
  266. graph.GetVersion(preset));
  267. }
  268. CHECK_EXPAND(out, out->ConfigFile, macroExpanders, graph.GetVersion(preset));
  269. CHECK_EXPAND(out, out->PackageName, macroExpanders,
  270. graph.GetVersion(preset));
  271. CHECK_EXPAND(out, out->PackageVersion, macroExpanders,
  272. graph.GetVersion(preset));
  273. CHECK_EXPAND(out, out->PackageDirectory, macroExpanders,
  274. graph.GetVersion(preset));
  275. CHECK_EXPAND(out, out->VendorName, macroExpanders, graph.GetVersion(preset));
  276. return true;
  277. }
  278. bool ExpandMacros(const cmCMakePresetsGraph& /*graph*/,
  279. const WorkflowPreset& /*preset*/,
  280. cm::optional<WorkflowPreset>& /*out*/,
  281. const std::vector<MacroExpander>& /*macroExpanders*/)
  282. {
  283. return true;
  284. }
  285. template <class T>
  286. bool ExpandMacros(const cmCMakePresetsGraph& graph, const T& preset,
  287. cm::optional<T>& out)
  288. {
  289. out.emplace(preset);
  290. std::map<std::string, CycleStatus> envCycles;
  291. for (auto const& v : out->Environment) {
  292. envCycles[v.first] = CycleStatus::Unvisited;
  293. }
  294. std::vector<MacroExpander> macroExpanders;
  295. MacroExpander defaultMacroExpander =
  296. [&graph, &preset](const std::string& macroNamespace,
  297. const std::string& macroName, std::string& macroOut,
  298. int version) -> ExpandMacroResult {
  299. if (macroNamespace.empty()) {
  300. if (macroName == "sourceDir") {
  301. macroOut += graph.SourceDir;
  302. return ExpandMacroResult::Ok;
  303. }
  304. if (macroName == "sourceParentDir") {
  305. macroOut += cmSystemTools::GetParentDirectory(graph.SourceDir);
  306. return ExpandMacroResult::Ok;
  307. }
  308. if (macroName == "sourceDirName") {
  309. macroOut += cmSystemTools::GetFilenameName(graph.SourceDir);
  310. return ExpandMacroResult::Ok;
  311. }
  312. if (macroName == "presetName") {
  313. macroOut += preset.Name;
  314. return ExpandMacroResult::Ok;
  315. }
  316. if (macroName == "generator") {
  317. // Generator only makes sense if preset is not hidden.
  318. if (!preset.Hidden) {
  319. macroOut += graph.GetGeneratorForPreset(preset.Name);
  320. }
  321. return ExpandMacroResult::Ok;
  322. }
  323. if (macroName == "dollar") {
  324. macroOut += '$';
  325. return ExpandMacroResult::Ok;
  326. }
  327. if (macroName == "hostSystemName") {
  328. if (version < 3) {
  329. return ExpandMacroResult::Error;
  330. }
  331. macroOut += cmSystemTools::GetSystemName();
  332. return ExpandMacroResult::Ok;
  333. }
  334. if (macroName == "fileDir") {
  335. if (version < 4) {
  336. return ExpandMacroResult::Error;
  337. }
  338. macroOut +=
  339. cmSystemTools::GetParentDirectory(preset.OriginFile->Filename);
  340. return ExpandMacroResult::Ok;
  341. }
  342. if (macroName == "pathListSep") {
  343. if (version < 5) {
  344. return ExpandMacroResult::Error;
  345. }
  346. macroOut += cmSystemTools::GetSystemPathlistSeparator();
  347. return ExpandMacroResult::Ok;
  348. }
  349. }
  350. return ExpandMacroResult::Ignore;
  351. };
  352. MacroExpander environmentMacroExpander =
  353. [&macroExpanders, &out, &envCycles](
  354. const std::string& macroNamespace, const std::string& macroName,
  355. std::string& result, int version) -> ExpandMacroResult {
  356. if (macroNamespace == "env" && !macroName.empty() && out) {
  357. auto v = out->Environment.find(macroName);
  358. if (v != out->Environment.end() && v->second) {
  359. auto e =
  360. VisitEnv(*v->second, envCycles[macroName], macroExpanders, version);
  361. if (e != ExpandMacroResult::Ok) {
  362. return e;
  363. }
  364. result += *v->second;
  365. return ExpandMacroResult::Ok;
  366. }
  367. }
  368. if (macroNamespace == "env" || macroNamespace == "penv") {
  369. if (macroName.empty()) {
  370. return ExpandMacroResult::Error;
  371. }
  372. const char* value = std::getenv(macroName.c_str());
  373. if (value) {
  374. result += value;
  375. }
  376. return ExpandMacroResult::Ok;
  377. }
  378. return ExpandMacroResult::Ignore;
  379. };
  380. macroExpanders.push_back(defaultMacroExpander);
  381. macroExpanders.push_back(environmentMacroExpander);
  382. for (auto& v : out->Environment) {
  383. if (v.second) {
  384. switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders,
  385. graph.GetVersion(preset))) {
  386. case ExpandMacroResult::Error:
  387. return false;
  388. case ExpandMacroResult::Ignore:
  389. out.reset();
  390. return true;
  391. case ExpandMacroResult::Ok:
  392. break;
  393. }
  394. }
  395. }
  396. if (preset.ConditionEvaluator) {
  397. cm::optional<bool> result;
  398. if (!preset.ConditionEvaluator->Evaluate(
  399. macroExpanders, graph.GetVersion(preset), result)) {
  400. return false;
  401. }
  402. if (!result) {
  403. out.reset();
  404. return true;
  405. }
  406. out->ConditionResult = *result;
  407. }
  408. return ExpandMacros(graph, preset, out, macroExpanders);
  409. }
  410. ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status,
  411. const std::vector<MacroExpander>& macroExpanders,
  412. int version)
  413. {
  414. if (status == CycleStatus::Verified) {
  415. return ExpandMacroResult::Ok;
  416. }
  417. if (status == CycleStatus::InProgress) {
  418. return ExpandMacroResult::Error;
  419. }
  420. status = CycleStatus::InProgress;
  421. auto e = ExpandMacros(value, macroExpanders, version);
  422. if (e != ExpandMacroResult::Ok) {
  423. return e;
  424. }
  425. status = CycleStatus::Verified;
  426. return ExpandMacroResult::Ok;
  427. }
  428. ExpandMacroResult ExpandMacros(
  429. std::string& out, const std::vector<MacroExpander>& macroExpanders,
  430. int version)
  431. {
  432. std::string result;
  433. std::string macroNamespace;
  434. std::string macroName;
  435. enum class State
  436. {
  437. Default,
  438. MacroNamespace,
  439. MacroName,
  440. } state = State::Default;
  441. for (auto c : out) {
  442. switch (state) {
  443. case State::Default:
  444. if (c == '$') {
  445. state = State::MacroNamespace;
  446. } else {
  447. result += c;
  448. }
  449. break;
  450. case State::MacroNamespace:
  451. if (c == '{') {
  452. if (IsValidMacroNamespace(macroNamespace)) {
  453. state = State::MacroName;
  454. } else {
  455. result += '$';
  456. result += macroNamespace;
  457. result += '{';
  458. macroNamespace.clear();
  459. state = State::Default;
  460. }
  461. } else {
  462. macroNamespace += c;
  463. if (!PrefixesValidMacroNamespace(macroNamespace)) {
  464. result += '$';
  465. result += macroNamespace;
  466. macroNamespace.clear();
  467. state = State::Default;
  468. }
  469. }
  470. break;
  471. case State::MacroName:
  472. if (c == '}') {
  473. auto e = ExpandMacro(result, macroNamespace, macroName,
  474. macroExpanders, version);
  475. if (e != ExpandMacroResult::Ok) {
  476. return e;
  477. }
  478. macroNamespace.clear();
  479. macroName.clear();
  480. state = State::Default;
  481. } else {
  482. macroName += c;
  483. }
  484. break;
  485. }
  486. }
  487. switch (state) {
  488. case State::Default:
  489. break;
  490. case State::MacroNamespace:
  491. result += '$';
  492. result += macroNamespace;
  493. break;
  494. case State::MacroName:
  495. return ExpandMacroResult::Error;
  496. }
  497. out = std::move(result);
  498. return ExpandMacroResult::Ok;
  499. }
  500. ExpandMacroResult ExpandMacro(std::string& out,
  501. const std::string& macroNamespace,
  502. const std::string& macroName,
  503. const std::vector<MacroExpander>& macroExpanders,
  504. int version)
  505. {
  506. for (auto const& macroExpander : macroExpanders) {
  507. auto result = macroExpander(macroNamespace, macroName, out, version);
  508. if (result != ExpandMacroResult::Ignore) {
  509. return result;
  510. }
  511. }
  512. if (macroNamespace == "vendor") {
  513. return ExpandMacroResult::Ignore;
  514. }
  515. return ExpandMacroResult::Error;
  516. }
  517. template <typename T>
  518. ReadFileResult SetupWorkflowConfigurePreset(
  519. const T& preset, const ConfigurePreset*& configurePreset)
  520. {
  521. if (preset.ConfigurePreset != configurePreset->Name) {
  522. return ReadFileResult::INVALID_WORKFLOW_STEPS;
  523. }
  524. return ReadFileResult::READ_OK;
  525. }
  526. template <>
  527. ReadFileResult SetupWorkflowConfigurePreset<ConfigurePreset>(
  528. const ConfigurePreset& preset, const ConfigurePreset*& configurePreset)
  529. {
  530. configurePreset = &preset;
  531. return ReadFileResult::READ_OK;
  532. }
  533. template <typename T>
  534. ReadFileResult TryReachPresetFromWorkflow(
  535. const WorkflowPreset& origin,
  536. const std::map<std::string, PresetPair<T>>& presets, const std::string& name,
  537. const ConfigurePreset*& configurePreset)
  538. {
  539. auto it = presets.find(name);
  540. if (it == presets.end()) {
  541. return ReadFileResult::INVALID_WORKFLOW_STEPS;
  542. }
  543. if (!origin.OriginFile->ReachableFiles.count(
  544. it->second.Unexpanded.OriginFile)) {
  545. return ReadFileResult::WORKFLOW_STEP_UNREACHABLE_FROM_FILE;
  546. }
  547. return SetupWorkflowConfigurePreset<T>(it->second.Unexpanded,
  548. configurePreset);
  549. }
  550. }
  551. bool cmCMakePresetsGraphInternal::EqualsCondition::Evaluate(
  552. const std::vector<MacroExpander>& expanders, int version,
  553. cm::optional<bool>& out) const
  554. {
  555. std::string lhs = this->Lhs;
  556. CHECK_EXPAND(out, lhs, expanders, version);
  557. std::string rhs = this->Rhs;
  558. CHECK_EXPAND(out, rhs, expanders, version);
  559. out = (lhs == rhs);
  560. return true;
  561. }
  562. bool cmCMakePresetsGraphInternal::InListCondition::Evaluate(
  563. const std::vector<MacroExpander>& expanders, int version,
  564. cm::optional<bool>& out) const
  565. {
  566. std::string str = this->String;
  567. CHECK_EXPAND(out, str, expanders, version);
  568. for (auto item : this->List) {
  569. CHECK_EXPAND(out, item, expanders, version);
  570. if (str == item) {
  571. out = true;
  572. return true;
  573. }
  574. }
  575. out = false;
  576. return true;
  577. }
  578. bool cmCMakePresetsGraphInternal::MatchesCondition::Evaluate(
  579. const std::vector<MacroExpander>& expanders, int version,
  580. cm::optional<bool>& out) const
  581. {
  582. std::string str = this->String;
  583. CHECK_EXPAND(out, str, expanders, version);
  584. std::string regexStr = this->Regex;
  585. CHECK_EXPAND(out, regexStr, expanders, version);
  586. cmsys::RegularExpression regex;
  587. if (!regex.compile(regexStr)) {
  588. return false;
  589. }
  590. out = regex.find(str);
  591. return true;
  592. }
  593. bool cmCMakePresetsGraphInternal::AnyAllOfCondition::Evaluate(
  594. const std::vector<MacroExpander>& expanders, int version,
  595. cm::optional<bool>& out) const
  596. {
  597. for (auto const& condition : this->Conditions) {
  598. cm::optional<bool> result;
  599. if (!condition->Evaluate(expanders, version, result)) {
  600. out.reset();
  601. return false;
  602. }
  603. if (!result) {
  604. out.reset();
  605. return true;
  606. }
  607. if (result == this->StopValue) {
  608. out = result;
  609. return true;
  610. }
  611. }
  612. out = !this->StopValue;
  613. return true;
  614. }
  615. bool cmCMakePresetsGraphInternal::NotCondition::Evaluate(
  616. const std::vector<MacroExpander>& expanders, int version,
  617. cm::optional<bool>& out) const
  618. {
  619. out.reset();
  620. if (!this->SubCondition->Evaluate(expanders, version, out)) {
  621. out.reset();
  622. return false;
  623. }
  624. if (out) {
  625. *out = !*out;
  626. }
  627. return true;
  628. }
  629. cmCMakePresetsGraph::ReadFileResult
  630. cmCMakePresetsGraph::ConfigurePreset::VisitPresetInherit(
  631. const cmCMakePresetsGraph::Preset& parentPreset)
  632. {
  633. auto& preset = *this;
  634. const ConfigurePreset& parent =
  635. static_cast<const ConfigurePreset&>(parentPreset);
  636. InheritString(preset.Generator, parent.Generator);
  637. InheritString(preset.Architecture, parent.Architecture);
  638. InheritString(preset.Toolset, parent.Toolset);
  639. if (!preset.ArchitectureStrategy) {
  640. preset.ArchitectureStrategy = parent.ArchitectureStrategy;
  641. }
  642. if (!preset.ToolsetStrategy) {
  643. preset.ToolsetStrategy = parent.ToolsetStrategy;
  644. }
  645. InheritString(preset.BinaryDir, parent.BinaryDir);
  646. InheritString(preset.InstallDir, parent.InstallDir);
  647. InheritString(preset.ToolchainFile, parent.ToolchainFile);
  648. InheritOptionalValue(preset.WarnDev, parent.WarnDev);
  649. InheritOptionalValue(preset.ErrorDev, parent.ErrorDev);
  650. InheritOptionalValue(preset.WarnDeprecated, parent.WarnDeprecated);
  651. InheritOptionalValue(preset.ErrorDeprecated, parent.ErrorDeprecated);
  652. InheritOptionalValue(preset.WarnUninitialized, parent.WarnUninitialized);
  653. InheritOptionalValue(preset.WarnUnusedCli, parent.WarnUnusedCli);
  654. InheritOptionalValue(preset.WarnSystemVars, parent.WarnSystemVars);
  655. for (auto const& v : parent.CacheVariables) {
  656. preset.CacheVariables.insert(v);
  657. }
  658. return ReadFileResult::READ_OK;
  659. }
  660. cmCMakePresetsGraph::ReadFileResult
  661. cmCMakePresetsGraph::ConfigurePreset::VisitPresetBeforeInherit()
  662. {
  663. auto& preset = *this;
  664. if (preset.Environment.count("") != 0) {
  665. return ReadFileResult::INVALID_PRESET;
  666. }
  667. return ReadFileResult::READ_OK;
  668. }
  669. cmCMakePresetsGraph::ReadFileResult
  670. cmCMakePresetsGraph::ConfigurePreset::VisitPresetAfterInherit(int version)
  671. {
  672. auto& preset = *this;
  673. if (!preset.Hidden) {
  674. if (version < 3) {
  675. if (preset.Generator.empty()) {
  676. return ReadFileResult::INVALID_PRESET;
  677. }
  678. if (preset.BinaryDir.empty()) {
  679. return ReadFileResult::INVALID_PRESET;
  680. }
  681. }
  682. if (preset.WarnDev == false && preset.ErrorDev == true) {
  683. return ReadFileResult::INVALID_PRESET;
  684. }
  685. if (preset.WarnDeprecated == false && preset.ErrorDeprecated == true) {
  686. return ReadFileResult::INVALID_PRESET;
  687. }
  688. if (preset.CacheVariables.count("") != 0) {
  689. return ReadFileResult::INVALID_PRESET;
  690. }
  691. }
  692. return ReadFileResult::READ_OK;
  693. }
  694. cmCMakePresetsGraph::ReadFileResult
  695. cmCMakePresetsGraph::BuildPreset::VisitPresetInherit(
  696. const cmCMakePresetsGraph::Preset& parentPreset)
  697. {
  698. auto& preset = *this;
  699. const BuildPreset& parent = static_cast<const BuildPreset&>(parentPreset);
  700. InheritString(preset.ConfigurePreset, parent.ConfigurePreset);
  701. InheritOptionalValue(preset.InheritConfigureEnvironment,
  702. parent.InheritConfigureEnvironment);
  703. InheritOptionalValue(preset.Jobs, parent.Jobs);
  704. InheritVector(preset.Targets, parent.Targets);
  705. InheritString(preset.Configuration, parent.Configuration);
  706. InheritOptionalValue(preset.CleanFirst, parent.CleanFirst);
  707. InheritOptionalValue(preset.Verbose, parent.Verbose);
  708. InheritVector(preset.NativeToolOptions, parent.NativeToolOptions);
  709. if (!preset.ResolvePackageReferences) {
  710. preset.ResolvePackageReferences = parent.ResolvePackageReferences;
  711. }
  712. return ReadFileResult::READ_OK;
  713. }
  714. cmCMakePresetsGraph::ReadFileResult
  715. cmCMakePresetsGraph::BuildPreset::VisitPresetAfterInherit(int /* version */)
  716. {
  717. auto& preset = *this;
  718. if (!preset.Hidden && preset.ConfigurePreset.empty()) {
  719. return ReadFileResult::INVALID_PRESET;
  720. }
  721. return ReadFileResult::READ_OK;
  722. }
  723. cmCMakePresetsGraph::ReadFileResult
  724. cmCMakePresetsGraph::TestPreset::VisitPresetInherit(
  725. const cmCMakePresetsGraph::Preset& parentPreset)
  726. {
  727. auto& preset = *this;
  728. const TestPreset& parent = static_cast<const TestPreset&>(parentPreset);
  729. InheritString(preset.ConfigurePreset, parent.ConfigurePreset);
  730. InheritOptionalValue(preset.InheritConfigureEnvironment,
  731. parent.InheritConfigureEnvironment);
  732. InheritString(preset.Configuration, parent.Configuration);
  733. InheritVector(preset.OverwriteConfigurationFile,
  734. parent.OverwriteConfigurationFile);
  735. if (parent.Output) {
  736. if (preset.Output) {
  737. auto& output = preset.Output.value();
  738. const auto& parentOutput = parent.Output.value();
  739. InheritOptionalValue(output.ShortProgress, parentOutput.ShortProgress);
  740. InheritOptionalValue(output.Verbosity, parentOutput.Verbosity);
  741. InheritOptionalValue(output.Debug, parentOutput.Debug);
  742. InheritOptionalValue(output.OutputOnFailure,
  743. parentOutput.OutputOnFailure);
  744. InheritOptionalValue(output.Quiet, parentOutput.Quiet);
  745. InheritString(output.OutputLogFile, parentOutput.OutputLogFile);
  746. InheritOptionalValue(output.LabelSummary, parentOutput.LabelSummary);
  747. InheritOptionalValue(output.SubprojectSummary,
  748. parentOutput.SubprojectSummary);
  749. InheritOptionalValue(output.MaxPassedTestOutputSize,
  750. parentOutput.MaxPassedTestOutputSize);
  751. InheritOptionalValue(output.MaxFailedTestOutputSize,
  752. parentOutput.MaxFailedTestOutputSize);
  753. InheritOptionalValue(output.TestOutputTruncation,
  754. parentOutput.TestOutputTruncation);
  755. InheritOptionalValue(output.MaxTestNameWidth,
  756. parentOutput.MaxTestNameWidth);
  757. } else {
  758. preset.Output = parent.Output;
  759. }
  760. }
  761. if (parent.Filter) {
  762. if (parent.Filter->Include) {
  763. if (preset.Filter && preset.Filter->Include) {
  764. auto& include = *preset.Filter->Include;
  765. const auto& parentInclude = *parent.Filter->Include;
  766. InheritString(include.Name, parentInclude.Name);
  767. InheritString(include.Label, parentInclude.Label);
  768. InheritOptionalValue(include.Index, parentInclude.Index);
  769. } else {
  770. if (!preset.Filter) {
  771. preset.Filter.emplace();
  772. }
  773. preset.Filter->Include = parent.Filter->Include;
  774. }
  775. }
  776. if (parent.Filter->Exclude) {
  777. if (preset.Filter && preset.Filter->Exclude) {
  778. auto& exclude = *preset.Filter->Exclude;
  779. const auto& parentExclude = *parent.Filter->Exclude;
  780. InheritString(exclude.Name, parentExclude.Name);
  781. InheritString(exclude.Label, parentExclude.Label);
  782. InheritOptionalValue(exclude.Fixtures, parentExclude.Fixtures);
  783. } else {
  784. if (!preset.Filter) {
  785. preset.Filter.emplace();
  786. }
  787. preset.Filter->Exclude = parent.Filter->Exclude;
  788. }
  789. }
  790. }
  791. if (parent.Execution) {
  792. if (preset.Execution) {
  793. auto& execution = *preset.Execution;
  794. const auto& parentExecution = *parent.Execution;
  795. InheritOptionalValue(execution.StopOnFailure,
  796. parentExecution.StopOnFailure);
  797. InheritOptionalValue(execution.EnableFailover,
  798. parentExecution.EnableFailover);
  799. InheritOptionalValue(execution.Jobs, parentExecution.Jobs);
  800. InheritString(execution.ResourceSpecFile,
  801. parentExecution.ResourceSpecFile);
  802. InheritOptionalValue(execution.TestLoad, parentExecution.TestLoad);
  803. InheritOptionalValue(execution.ShowOnly, parentExecution.ShowOnly);
  804. InheritOptionalValue(execution.Repeat, parentExecution.Repeat);
  805. InheritOptionalValue(execution.InteractiveDebugging,
  806. parentExecution.InteractiveDebugging);
  807. InheritOptionalValue(execution.ScheduleRandom,
  808. parentExecution.ScheduleRandom);
  809. InheritOptionalValue(execution.Timeout, parentExecution.Timeout);
  810. InheritOptionalValue(execution.NoTestsAction,
  811. parentExecution.NoTestsAction);
  812. } else {
  813. preset.Execution = parent.Execution;
  814. }
  815. }
  816. return ReadFileResult::READ_OK;
  817. }
  818. cmCMakePresetsGraph::ReadFileResult
  819. cmCMakePresetsGraph::TestPreset::VisitPresetAfterInherit(int /* version */)
  820. {
  821. auto& preset = *this;
  822. if (!preset.Hidden && preset.ConfigurePreset.empty()) {
  823. return ReadFileResult::INVALID_PRESET;
  824. }
  825. return ReadFileResult::READ_OK;
  826. }
  827. cmCMakePresetsGraph::ReadFileResult
  828. cmCMakePresetsGraph::PackagePreset::VisitPresetInherit(
  829. const cmCMakePresetsGraph::Preset& parentPreset)
  830. {
  831. auto& preset = *this;
  832. const PackagePreset& parent =
  833. static_cast<const PackagePreset&>(parentPreset);
  834. InheritString(preset.ConfigurePreset, parent.ConfigurePreset);
  835. InheritOptionalValue(preset.InheritConfigureEnvironment,
  836. parent.InheritConfigureEnvironment);
  837. InheritVector(preset.Generators, parent.Generators);
  838. InheritVector(preset.Configurations, parent.Configurations);
  839. for (auto const& v : parent.Variables) {
  840. preset.Variables.insert(v);
  841. }
  842. InheritOptionalValue(preset.DebugOutput, parent.DebugOutput);
  843. InheritOptionalValue(preset.VerboseOutput, parent.VerboseOutput);
  844. InheritString(preset.PackageName, parent.PackageName);
  845. InheritString(preset.PackageVersion, parent.PackageVersion);
  846. InheritString(preset.PackageDirectory, parent.PackageDirectory);
  847. InheritString(preset.VendorName, parent.VendorName);
  848. return ReadFileResult::READ_OK;
  849. }
  850. cmCMakePresetsGraph::ReadFileResult
  851. cmCMakePresetsGraph::PackagePreset::VisitPresetAfterInherit(int /* version */)
  852. {
  853. auto& preset = *this;
  854. if (!preset.Hidden && preset.ConfigurePreset.empty()) {
  855. return ReadFileResult::INVALID_PRESET;
  856. }
  857. return ReadFileResult::READ_OK;
  858. }
  859. cmCMakePresetsGraph::ReadFileResult
  860. cmCMakePresetsGraph::WorkflowPreset::VisitPresetInherit(
  861. const cmCMakePresetsGraph::Preset& /*parentPreset*/)
  862. {
  863. return ReadFileResult::READ_OK;
  864. }
  865. cmCMakePresetsGraph::ReadFileResult
  866. cmCMakePresetsGraph::WorkflowPreset::VisitPresetAfterInherit(int /* version */)
  867. {
  868. return ReadFileResult::READ_OK;
  869. }
  870. std::string cmCMakePresetsGraph::GetFilename(const std::string& sourceDir)
  871. {
  872. return cmStrCat(sourceDir, "/CMakePresets.json");
  873. }
  874. std::string cmCMakePresetsGraph::GetUserFilename(const std::string& sourceDir)
  875. {
  876. return cmStrCat(sourceDir, "/CMakeUserPresets.json");
  877. }
  878. cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadProjectPresets(
  879. const std::string& sourceDir, bool allowNoFiles)
  880. {
  881. this->SourceDir = sourceDir;
  882. this->ClearPresets();
  883. auto result = this->ReadProjectPresetsInternal(allowNoFiles);
  884. if (result != ReadFileResult::READ_OK) {
  885. this->ClearPresets();
  886. }
  887. return result;
  888. }
  889. cmCMakePresetsGraph::ReadFileResult
  890. cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles)
  891. {
  892. bool haveOneFile = false;
  893. File* file;
  894. std::string filename = GetUserFilename(this->SourceDir);
  895. std::vector<File*> inProgressFiles;
  896. if (cmSystemTools::FileExists(filename)) {
  897. auto result =
  898. this->ReadJSONFile(filename, RootType::User, ReadReason::Root,
  899. inProgressFiles, file, this->errors);
  900. if (result != ReadFileResult::READ_OK) {
  901. return result;
  902. }
  903. haveOneFile = true;
  904. } else {
  905. filename = GetFilename(this->SourceDir);
  906. if (cmSystemTools::FileExists(filename)) {
  907. auto result =
  908. this->ReadJSONFile(filename, RootType::Project, ReadReason::Root,
  909. inProgressFiles, file, this->errors);
  910. if (result != ReadFileResult::READ_OK) {
  911. return result;
  912. }
  913. haveOneFile = true;
  914. }
  915. }
  916. assert(inProgressFiles.empty());
  917. if (!haveOneFile) {
  918. return allowNoFiles ? ReadFileResult::READ_OK
  919. : ReadFileResult::FILE_NOT_FOUND;
  920. }
  921. CHECK_OK(ComputePresetInheritance(this->ConfigurePresets, *this));
  922. CHECK_OK(ComputePresetInheritance(this->BuildPresets, *this));
  923. CHECK_OK(ComputePresetInheritance(this->TestPresets, *this));
  924. CHECK_OK(ComputePresetInheritance(this->PackagePresets, *this));
  925. CHECK_OK(ComputePresetInheritance(this->WorkflowPresets, *this));
  926. for (auto& it : this->ConfigurePresets) {
  927. if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
  928. return ReadFileResult::INVALID_MACRO_EXPANSION;
  929. }
  930. }
  931. for (auto& it : this->BuildPresets) {
  932. if (!it.second.Unexpanded.Hidden) {
  933. const auto configurePreset =
  934. this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset);
  935. if (configurePreset == this->ConfigurePresets.end()) {
  936. return ReadFileResult::INVALID_CONFIGURE_PRESET;
  937. }
  938. if (!it.second.Unexpanded.OriginFile->ReachableFiles.count(
  939. configurePreset->second.Unexpanded.OriginFile)) {
  940. return ReadFileResult::CONFIGURE_PRESET_UNREACHABLE_FROM_FILE;
  941. }
  942. if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) {
  943. it.second.Unexpanded.Environment.insert(
  944. configurePreset->second.Unexpanded.Environment.begin(),
  945. configurePreset->second.Unexpanded.Environment.end());
  946. }
  947. }
  948. if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
  949. return ReadFileResult::INVALID_MACRO_EXPANSION;
  950. }
  951. }
  952. for (auto& it : this->TestPresets) {
  953. if (!it.second.Unexpanded.Hidden) {
  954. const auto configurePreset =
  955. this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset);
  956. if (configurePreset == this->ConfigurePresets.end()) {
  957. return ReadFileResult::INVALID_CONFIGURE_PRESET;
  958. }
  959. if (!it.second.Unexpanded.OriginFile->ReachableFiles.count(
  960. configurePreset->second.Unexpanded.OriginFile)) {
  961. return ReadFileResult::CONFIGURE_PRESET_UNREACHABLE_FROM_FILE;
  962. }
  963. if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) {
  964. it.second.Unexpanded.Environment.insert(
  965. configurePreset->second.Unexpanded.Environment.begin(),
  966. configurePreset->second.Unexpanded.Environment.end());
  967. }
  968. }
  969. if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
  970. return ReadFileResult::INVALID_MACRO_EXPANSION;
  971. }
  972. }
  973. for (auto& it : this->PackagePresets) {
  974. if (!it.second.Unexpanded.Hidden) {
  975. const auto configurePreset =
  976. this->ConfigurePresets.find(it.second.Unexpanded.ConfigurePreset);
  977. if (configurePreset == this->ConfigurePresets.end()) {
  978. return ReadFileResult::INVALID_CONFIGURE_PRESET;
  979. }
  980. if (!it.second.Unexpanded.OriginFile->ReachableFiles.count(
  981. configurePreset->second.Unexpanded.OriginFile)) {
  982. return ReadFileResult::CONFIGURE_PRESET_UNREACHABLE_FROM_FILE;
  983. }
  984. if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) {
  985. it.second.Unexpanded.Environment.insert(
  986. configurePreset->second.Unexpanded.Environment.begin(),
  987. configurePreset->second.Unexpanded.Environment.end());
  988. }
  989. }
  990. if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
  991. return ReadFileResult::INVALID_MACRO_EXPANSION;
  992. }
  993. }
  994. for (auto& it : this->WorkflowPresets) {
  995. using Type = WorkflowPreset::WorkflowStep::Type;
  996. const ConfigurePreset* configurePreset = nullptr;
  997. for (auto const& step : it.second.Unexpanded.Steps) {
  998. if (configurePreset == nullptr && step.PresetType != Type::Configure) {
  999. return ReadFileResult::INVALID_WORKFLOW_STEPS;
  1000. }
  1001. if (configurePreset != nullptr && step.PresetType == Type::Configure) {
  1002. return ReadFileResult::INVALID_WORKFLOW_STEPS;
  1003. }
  1004. ReadFileResult result;
  1005. switch (step.PresetType) {
  1006. case Type::Configure:
  1007. result = TryReachPresetFromWorkflow(
  1008. it.second.Unexpanded, this->ConfigurePresets, step.PresetName,
  1009. configurePreset);
  1010. break;
  1011. case Type::Build:
  1012. result = TryReachPresetFromWorkflow(
  1013. it.second.Unexpanded, this->BuildPresets, step.PresetName,
  1014. configurePreset);
  1015. break;
  1016. case Type::Test:
  1017. result =
  1018. TryReachPresetFromWorkflow(it.second.Unexpanded, this->TestPresets,
  1019. step.PresetName, configurePreset);
  1020. break;
  1021. case Type::Package:
  1022. result = TryReachPresetFromWorkflow(
  1023. it.second.Unexpanded, this->PackagePresets, step.PresetName,
  1024. configurePreset);
  1025. break;
  1026. }
  1027. if (result != ReadFileResult::READ_OK) {
  1028. return result;
  1029. }
  1030. }
  1031. if (configurePreset == nullptr) {
  1032. return ReadFileResult::INVALID_WORKFLOW_STEPS;
  1033. }
  1034. if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
  1035. return ReadFileResult::INVALID_MACRO_EXPANSION;
  1036. }
  1037. }
  1038. return ReadFileResult::READ_OK;
  1039. }
  1040. const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result)
  1041. {
  1042. switch (result) {
  1043. case ReadFileResult::READ_OK:
  1044. return "OK";
  1045. case ReadFileResult::FILE_NOT_FOUND:
  1046. return "File not found";
  1047. case ReadFileResult::JSON_PARSE_ERROR:
  1048. return "JSON parse error";
  1049. case ReadFileResult::INVALID_ROOT:
  1050. return "Invalid root object";
  1051. case ReadFileResult::NO_VERSION:
  1052. return "No \"version\" field";
  1053. case ReadFileResult::INVALID_VERSION:
  1054. return "Invalid \"version\" field";
  1055. case ReadFileResult::UNRECOGNIZED_VERSION:
  1056. return "Unrecognized \"version\" field";
  1057. case ReadFileResult::INVALID_CMAKE_VERSION:
  1058. return "Invalid \"cmakeMinimumRequired\" field";
  1059. case ReadFileResult::UNRECOGNIZED_CMAKE_VERSION:
  1060. return "\"cmakeMinimumRequired\" version too new";
  1061. case ReadFileResult::INVALID_PRESETS:
  1062. return "Invalid \"configurePresets\" field";
  1063. case ReadFileResult::INVALID_PRESET:
  1064. return "Invalid preset";
  1065. case ReadFileResult::INVALID_VARIABLE:
  1066. return "Invalid CMake variable definition";
  1067. case ReadFileResult::DUPLICATE_PRESETS:
  1068. return "Duplicate presets";
  1069. case ReadFileResult::CYCLIC_PRESET_INHERITANCE:
  1070. return "Cyclic preset inheritance";
  1071. case ReadFileResult::INHERITED_PRESET_UNREACHABLE_FROM_FILE:
  1072. return "Inherited preset is unreachable from preset's file";
  1073. case ReadFileResult::CONFIGURE_PRESET_UNREACHABLE_FROM_FILE:
  1074. return "Configure preset is unreachable from preset's file";
  1075. case ReadFileResult::INVALID_MACRO_EXPANSION:
  1076. return "Invalid macro expansion";
  1077. case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED:
  1078. return "File version must be 2 or higher for build and test preset "
  1079. "support.";
  1080. case ReadFileResult::PACKAGE_PRESETS_UNSUPPORTED:
  1081. return "File version must be 6 or higher for package preset support";
  1082. case ReadFileResult::WORKFLOW_PRESETS_UNSUPPORTED:
  1083. return "File version must be 6 or higher for workflow preset support";
  1084. case ReadFileResult::INCLUDE_UNSUPPORTED:
  1085. return "File version must be 4 or higher for include support";
  1086. case ReadFileResult::INVALID_INCLUDE:
  1087. return "Invalid \"include\" field";
  1088. case ReadFileResult::INVALID_CONFIGURE_PRESET:
  1089. return "Invalid \"configurePreset\" field";
  1090. case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED:
  1091. return "File version must be 3 or higher for installDir preset "
  1092. "support.";
  1093. case ReadFileResult::INVALID_CONDITION:
  1094. return "Invalid preset condition";
  1095. case ReadFileResult::CONDITION_UNSUPPORTED:
  1096. return "File version must be 3 or higher for condition support";
  1097. case ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED:
  1098. return "File version must be 3 or higher for toolchainFile preset "
  1099. "support.";
  1100. case ReadFileResult::CYCLIC_INCLUDE:
  1101. return "Cyclic include among preset files";
  1102. case ReadFileResult::TEST_OUTPUT_TRUNCATION_UNSUPPORTED:
  1103. return "File version must be 5 or higher for testOutputTruncation "
  1104. "preset support.";
  1105. case ReadFileResult::INVALID_WORKFLOW_STEPS:
  1106. return "Invalid workflow steps";
  1107. case ReadFileResult::WORKFLOW_STEP_UNREACHABLE_FROM_FILE:
  1108. return "Workflow step is unreachable from preset's file";
  1109. }
  1110. return "Unknown error";
  1111. }
  1112. void cmCMakePresetsGraph::ClearPresets()
  1113. {
  1114. this->ConfigurePresets.clear();
  1115. this->BuildPresets.clear();
  1116. this->TestPresets.clear();
  1117. this->PackagePresets.clear();
  1118. this->WorkflowPresets.clear();
  1119. this->ConfigurePresetOrder.clear();
  1120. this->BuildPresetOrder.clear();
  1121. this->TestPresetOrder.clear();
  1122. this->PackagePresetOrder.clear();
  1123. this->WorkflowPresetOrder.clear();
  1124. this->Files.clear();
  1125. }
  1126. void cmCMakePresetsGraph::printPrecedingNewline(PrintPrecedingNewline* newline)
  1127. {
  1128. if (newline) {
  1129. if (*newline == PrintPrecedingNewline::True) {
  1130. std::cout << std::endl;
  1131. }
  1132. *newline = PrintPrecedingNewline::True;
  1133. }
  1134. }
  1135. void cmCMakePresetsGraph::PrintPresets(
  1136. const std::vector<const cmCMakePresetsGraph::Preset*>& presets)
  1137. {
  1138. if (presets.empty()) {
  1139. return;
  1140. }
  1141. auto longestPresetName =
  1142. std::max_element(presets.begin(), presets.end(),
  1143. [](const cmCMakePresetsGraph::Preset* a,
  1144. const cmCMakePresetsGraph::Preset* b) {
  1145. return a->Name.length() < b->Name.length();
  1146. });
  1147. auto longestLength = (*longestPresetName)->Name.length();
  1148. for (const auto* preset : presets) {
  1149. std::cout << " \"" << preset->Name << '"';
  1150. const auto& description = preset->DisplayName;
  1151. if (!description.empty()) {
  1152. for (std::size_t i = 0; i < longestLength - preset->Name.length(); ++i) {
  1153. std::cout << ' ';
  1154. }
  1155. std::cout << " - " << description;
  1156. }
  1157. std::cout << '\n';
  1158. }
  1159. }
  1160. void cmCMakePresetsGraph::PrintConfigurePresetList(
  1161. PrintPrecedingNewline* newline) const
  1162. {
  1163. PrintConfigurePresetList([](const ConfigurePreset&) { return true; },
  1164. newline);
  1165. }
  1166. void cmCMakePresetsGraph::PrintConfigurePresetList(
  1167. const std::function<bool(const ConfigurePreset&)>& filter,
  1168. PrintPrecedingNewline* newline) const
  1169. {
  1170. std::vector<const cmCMakePresetsGraph::Preset*> presets;
  1171. for (auto const& p : this->ConfigurePresetOrder) {
  1172. auto const& preset = this->ConfigurePresets.at(p);
  1173. if (!preset.Unexpanded.Hidden && preset.Expanded &&
  1174. preset.Expanded->ConditionResult && filter(preset.Unexpanded)) {
  1175. presets.push_back(
  1176. static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded));
  1177. }
  1178. }
  1179. if (!presets.empty()) {
  1180. printPrecedingNewline(newline);
  1181. std::cout << "Available configure presets:\n\n";
  1182. cmCMakePresetsGraph::PrintPresets(presets);
  1183. }
  1184. }
  1185. void cmCMakePresetsGraph::PrintBuildPresetList(
  1186. PrintPrecedingNewline* newline) const
  1187. {
  1188. std::vector<const cmCMakePresetsGraph::Preset*> presets;
  1189. for (auto const& p : this->BuildPresetOrder) {
  1190. auto const& preset = this->BuildPresets.at(p);
  1191. if (!preset.Unexpanded.Hidden && preset.Expanded &&
  1192. preset.Expanded->ConditionResult) {
  1193. presets.push_back(
  1194. static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded));
  1195. }
  1196. }
  1197. if (!presets.empty()) {
  1198. printPrecedingNewline(newline);
  1199. std::cout << "Available build presets:\n\n";
  1200. cmCMakePresetsGraph::PrintPresets(presets);
  1201. }
  1202. }
  1203. void cmCMakePresetsGraph::PrintTestPresetList(
  1204. PrintPrecedingNewline* newline) const
  1205. {
  1206. std::vector<const cmCMakePresetsGraph::Preset*> presets;
  1207. for (auto const& p : this->TestPresetOrder) {
  1208. auto const& preset = this->TestPresets.at(p);
  1209. if (!preset.Unexpanded.Hidden && preset.Expanded &&
  1210. preset.Expanded->ConditionResult) {
  1211. presets.push_back(
  1212. static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded));
  1213. }
  1214. }
  1215. if (!presets.empty()) {
  1216. printPrecedingNewline(newline);
  1217. std::cout << "Available test presets:\n\n";
  1218. cmCMakePresetsGraph::PrintPresets(presets);
  1219. }
  1220. }
  1221. void cmCMakePresetsGraph::PrintPackagePresetList(
  1222. PrintPrecedingNewline* newline) const
  1223. {
  1224. this->PrintPackagePresetList([](const PackagePreset&) { return true; },
  1225. newline);
  1226. }
  1227. void cmCMakePresetsGraph::PrintPackagePresetList(
  1228. const std::function<bool(const PackagePreset&)>& filter,
  1229. PrintPrecedingNewline* newline) const
  1230. {
  1231. std::vector<const cmCMakePresetsGraph::Preset*> presets;
  1232. for (auto const& p : this->PackagePresetOrder) {
  1233. auto const& preset = this->PackagePresets.at(p);
  1234. if (!preset.Unexpanded.Hidden && preset.Expanded &&
  1235. preset.Expanded->ConditionResult && filter(preset.Unexpanded)) {
  1236. presets.push_back(
  1237. static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded));
  1238. }
  1239. }
  1240. if (!presets.empty()) {
  1241. printPrecedingNewline(newline);
  1242. std::cout << "Available package presets:\n\n";
  1243. cmCMakePresetsGraph::PrintPresets(presets);
  1244. }
  1245. }
  1246. void cmCMakePresetsGraph::PrintWorkflowPresetList(
  1247. PrintPrecedingNewline* newline) const
  1248. {
  1249. std::vector<const cmCMakePresetsGraph::Preset*> presets;
  1250. for (auto const& p : this->WorkflowPresetOrder) {
  1251. auto const& preset = this->WorkflowPresets.at(p);
  1252. if (!preset.Unexpanded.Hidden && preset.Expanded &&
  1253. preset.Expanded->ConditionResult) {
  1254. presets.push_back(
  1255. static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded));
  1256. }
  1257. }
  1258. if (!presets.empty()) {
  1259. printPrecedingNewline(newline);
  1260. std::cout << "Available workflow presets:\n\n";
  1261. cmCMakePresetsGraph::PrintPresets(presets);
  1262. }
  1263. }
  1264. void cmCMakePresetsGraph::PrintAllPresets() const
  1265. {
  1266. PrintPrecedingNewline newline = PrintPrecedingNewline::False;
  1267. this->PrintConfigurePresetList(&newline);
  1268. this->PrintBuildPresetList(&newline);
  1269. this->PrintTestPresetList(&newline);
  1270. this->PrintPackagePresetList(&newline);
  1271. this->PrintWorkflowPresetList(&newline);
  1272. }