cmCMakePresetsGraph.cxx 46 KB

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