/src/CMake/Source/cmCMakePresetsErrors.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #include "cmConfigure.h" // IWYU pragma: keep |
4 | | |
5 | | #include "cmCMakePresetsErrors.h" |
6 | | |
7 | | #include <functional> |
8 | | #include <utility> |
9 | | #include <vector> |
10 | | |
11 | | #include <cm3p/json/value.h> |
12 | | |
13 | | #include "cmJSONHelpers.h" |
14 | | #include "cmJSONState.h" |
15 | | #include "cmStringAlgorithms.h" |
16 | | |
17 | | namespace cmCMakePresetsErrors { |
18 | | namespace { |
19 | | std::string CapitalizePresetKind(std::string kind) |
20 | 1.05k | { |
21 | 1.05k | if (!kind.empty() && kind.front() >= 'a' && kind.front() <= 'z') { |
22 | 1.05k | kind.front() = static_cast<char>(kind.front() - 'a' + 'A'); |
23 | 1.05k | } |
24 | 1.05k | return kind; |
25 | 1.05k | } |
26 | | } |
27 | | |
28 | | Json::Value const* getPreset(cmJSONState* state) |
29 | 208k | { |
30 | 208k | if (state->parseStack.size() < 2) { |
31 | 0 | return nullptr; |
32 | 0 | } |
33 | 208k | std::string firstKey = state->parseStack[0].first; |
34 | 208k | if (firstKey == "configurePresets" || firstKey == "packagePresets" || |
35 | 208k | firstKey == "buildPresets" || firstKey == "testPresets") { |
36 | 208k | return state->parseStack[1].second; |
37 | 208k | } |
38 | 0 | return nullptr; |
39 | 208k | } |
40 | | |
41 | | std::string getPresetName(cmJSONState* state) |
42 | 208k | { |
43 | 208k | Json::Value const* preset = getPreset(state); |
44 | 208k | if (preset && preset->isMember("name")) { |
45 | 154k | Json::Value const& name = preset->operator[]("name"); |
46 | 154k | if (name.isConvertibleTo(Json::ValueType::stringValue)) { |
47 | 152k | return name.asString(); |
48 | 152k | } |
49 | 154k | } |
50 | 55.5k | return ""; |
51 | 208k | } |
52 | | |
53 | | std::string getVariableName(cmJSONState* state) |
54 | 29.5k | { |
55 | 29.5k | std::string var = state->key_after("cacheVariables"); |
56 | 29.5k | if (var.empty()) { |
57 | 21.7k | var = state->key_after("variables"); |
58 | 21.7k | } |
59 | 29.5k | std::string errMsg = |
60 | 29.5k | var.empty() ? "variable" : cmStrCat("variable \"", var, '"'); |
61 | 29.5k | errMsg = |
62 | 29.5k | cmStrCat(std::move(errMsg), " for preset \"", getPresetName(state), '"'); |
63 | 29.5k | return errMsg; |
64 | 29.5k | } |
65 | | |
66 | | void FILE_NOT_FOUND(std::string const& filename, cmJSONState* state) |
67 | 0 | { |
68 | 0 | state->AddError(cmStrCat("File not found: ", filename)); |
69 | 0 | } |
70 | | |
71 | | void INVALID_ROOT(Json::Value const* value, cmJSONState* state) |
72 | 3 | { |
73 | 3 | state->AddErrorAtValue("Invalid root object", value); |
74 | 3 | } |
75 | | |
76 | | void NO_VERSION(Json::Value const* value, cmJSONState* state) |
77 | 261 | { |
78 | 261 | state->AddErrorAtValue("No \"version\" field", value); |
79 | 261 | } |
80 | | |
81 | | void INVALID_VERSION(Json::Value const* value, cmJSONState* state) |
82 | 1.01k | { |
83 | 1.01k | state->AddErrorAtValue("Invalid \"version\" field", value); |
84 | 1.01k | } |
85 | | |
86 | | void UNRECOGNIZED_VERSION(Json::Value const* value, cmJSONState* state) |
87 | 0 | { |
88 | 0 | state->AddErrorAtValue("Unrecognized \"version\" field", value); |
89 | 0 | } |
90 | | |
91 | | void INVALID_PRESETS(Json::Value const* value, cmJSONState* state) |
92 | 48 | { |
93 | 48 | state->AddErrorAtValue(cmStrCat("Invalid \"", state->key(), "\" field"), |
94 | 48 | value); |
95 | 48 | } |
96 | | |
97 | | void INVALID_PRESET(Json::Value const* value, cmJSONState* state) |
98 | 19.9k | { |
99 | 19.9k | state->AddErrorAtValue("Invalid preset", value); |
100 | 19.9k | } |
101 | | |
102 | | void INVALID_PRESET_NAMED(std::string const& presetName, |
103 | | std::string const& kind, cmJSONState* state, |
104 | | std::string const& detail) |
105 | 5.66k | { |
106 | 5.66k | std::string err_msg = |
107 | 5.66k | cmStrCat("Invalid ", kind, " preset: \"", presetName, '"'); |
108 | 5.66k | if (!detail.empty()) { |
109 | 5.12k | err_msg = cmStrCat(std::move(err_msg), ": ", detail); |
110 | 5.12k | } |
111 | 5.66k | state->AddError(err_msg); |
112 | 5.66k | } |
113 | | |
114 | | void INVALID_VARIABLE(Json::Value const* value, cmJSONState* state) |
115 | 23.1k | { |
116 | 23.1k | std::string var = cmCMakePresetsErrors::getVariableName(state); |
117 | 23.1k | state->AddErrorAtValue(cmStrCat("Invalid CMake ", var), value); |
118 | 23.1k | } |
119 | | |
120 | | void DUPLICATE_PRESETS(std::string const& presetName, cmJSONState* state) |
121 | 456 | { |
122 | 456 | state->AddError(cmStrCat("Duplicate preset: \"", presetName, '"')); |
123 | 456 | } |
124 | | |
125 | | void CYCLIC_PRESET_INHERITANCE(std::string const& presetName, |
126 | | std::string const& kind, cmJSONState* state) |
127 | | |
128 | 30 | { |
129 | 30 | state->AddError(cmStrCat("Cyclic preset inheritance for ", kind, |
130 | 30 | " preset \"", presetName, '"')); |
131 | 30 | } |
132 | | |
133 | | void INHERITED_PRESET_UNREACHABLE_FROM_FILE(std::string const& presetName, |
134 | | std::string const& inheritedPreset, |
135 | | std::string const& kind, |
136 | | cmJSONState* state) |
137 | 0 | { |
138 | 0 | state->AddError(cmStrCat(CapitalizePresetKind(kind), " preset \"", |
139 | 0 | presetName, "\" inherits preset \"", |
140 | 0 | inheritedPreset, "\", but \"", inheritedPreset, |
141 | 0 | "\" is not reachable from the preset's file")); |
142 | 0 | } |
143 | | |
144 | | void CONFIGURE_PRESET_UNREACHABLE_FROM_FILE(std::string const& presetName, |
145 | | std::string const& kind, |
146 | | std::string const& configurePreset, |
147 | | cmJSONState* state) |
148 | 0 | { |
149 | 0 | state->AddError(cmStrCat(CapitalizePresetKind(kind), " preset \"", |
150 | 0 | presetName, "\" references configure preset \"", |
151 | 0 | configurePreset, "\", but \"", configurePreset, |
152 | 0 | "\" is not reachable from the preset's file")); |
153 | 0 | } |
154 | | |
155 | | void INVALID_MACRO_EXPANSION(std::string const& presetName, cmJSONState* state) |
156 | 3.25k | { |
157 | 3.25k | state->AddError(cmStrCat("Invalid macro expansion in \"", presetName, '"')); |
158 | 3.25k | } |
159 | | |
160 | | void BUILD_TEST_PRESETS_UNSUPPORTED(Json::Value const*, cmJSONState* state) |
161 | 6 | { |
162 | 6 | state->AddError("File version must be 2 or higher for build and test preset " |
163 | 6 | "support"); |
164 | 6 | } |
165 | | |
166 | | void PACKAGE_PRESETS_UNSUPPORTED(Json::Value const*, cmJSONState* state) |
167 | 3 | { |
168 | 3 | state->AddError( |
169 | 3 | "File version must be 6 or higher for package preset support"); |
170 | 3 | } |
171 | | |
172 | | void WORKFLOW_PRESETS_UNSUPPORTED(Json::Value const*, cmJSONState* state) |
173 | 3 | { |
174 | 3 | state->AddError( |
175 | 3 | "File version must be 6 or higher for workflow preset support"); |
176 | 3 | } |
177 | | |
178 | | void INCLUDE_UNSUPPORTED(Json::Value const*, cmJSONState* state) |
179 | 3 | { |
180 | 3 | state->AddError("File version must be 4 or higher for include support"); |
181 | 3 | } |
182 | | |
183 | | void INVALID_INCLUDE(Json::Value const* value, cmJSONState* state) |
184 | 2.04k | { |
185 | 2.04k | state->AddErrorAtValue("Invalid \"include\" field", value); |
186 | 2.04k | } |
187 | | |
188 | | void CONFIGURE_PRESET_NOT_FOUND(std::string const& presetName, |
189 | | std::string const& kind, |
190 | | std::string const& configurePreset, |
191 | | cmJSONState* state) |
192 | 1.04k | { |
193 | 1.04k | state->AddError(cmStrCat( |
194 | 1.04k | CapitalizePresetKind(kind), " preset \"", presetName, |
195 | 1.04k | "\" references unknown configure preset \"", configurePreset, '"')); |
196 | 1.04k | } |
197 | | |
198 | | void INSTALL_PREFIX_UNSUPPORTED(Json::Value const* value, cmJSONState* state) |
199 | 24 | { |
200 | 24 | state->AddErrorAtValue( |
201 | 24 | "File version must be 3 or higher for installDir preset " |
202 | 24 | "support", |
203 | 24 | value); |
204 | 24 | } |
205 | | |
206 | | void CONDITION_UNSUPPORTED(cmJSONState* state) |
207 | 57 | { |
208 | 57 | state->AddError("File version must be 3 or higher for condition support"); |
209 | 57 | } |
210 | | |
211 | | void TOOLCHAIN_FILE_UNSUPPORTED(cmJSONState* state) |
212 | 30 | { |
213 | 30 | state->AddError("File version must be 3 or higher for toolchainFile preset " |
214 | 30 | "support"); |
215 | 30 | } |
216 | | |
217 | | void GRAPHVIZ_FILE_UNSUPPORTED(cmJSONState* state) |
218 | 39 | { |
219 | 39 | state->AddError( |
220 | 39 | "File version must be 10 or higher for graphviz preset support"); |
221 | 39 | } |
222 | | |
223 | | void JOBS_PROC_UNSUPPORTED(cmJSONState* state) |
224 | 0 | { |
225 | 0 | state->AddError("File version must be 11 or higher for " |
226 | 0 | "processor-count-based jobs preset support"); |
227 | 0 | } |
228 | | |
229 | | void PASSTHROUGH_ARGS_UNSUPPORTED(cmJSONState* state) |
230 | 0 | { |
231 | 0 | state->AddError("File version must be 12 or higher for " |
232 | 0 | "testPassthroughArguments preset support"); |
233 | 0 | } |
234 | | |
235 | | void CYCLIC_INCLUDE(std::string const& file, cmJSONState* state) |
236 | 1.94k | { |
237 | 1.94k | state->AddError(cmStrCat("Cyclic include among presets files: ", file)); |
238 | 1.94k | } |
239 | | |
240 | | void TEST_OUTPUT_TRUNCATION_UNSUPPORTED(cmJSONState* state) |
241 | 0 | { |
242 | 0 | state->AddError("File version must be 5 or higher for testOutputTruncation " |
243 | 0 | "preset support"); |
244 | 0 | } |
245 | | |
246 | | namespace { |
247 | | std::string WorkflowStepLabel(cm::string_view stepType, |
248 | | std::string const& stepName) |
249 | 996 | { |
250 | 996 | return cmStrCat("of type \"", stepType, "\" named \"", stepName, '"'); |
251 | 996 | } |
252 | | } |
253 | | |
254 | | void INVALID_WORKFLOW_STEPS(cm::string_view stepType, |
255 | | std::string const& stepName, cmJSONState* state) |
256 | 849 | { |
257 | 849 | state->AddError( |
258 | 849 | cmStrCat("Invalid workflow step ", WorkflowStepLabel(stepType, stepName))); |
259 | 849 | } |
260 | | |
261 | | void WORKFLOW_STEP_CONFIGURE_PRESET_MISMATCH( |
262 | | std::string const& kind, std::string const& workflowStep, |
263 | | std::string const& stepConfigurePreset, |
264 | | std::string const& workflowConfigurePreset, cmJSONState* state) |
265 | 6 | { |
266 | 6 | state->AddError(cmStrCat( |
267 | 6 | CapitalizePresetKind(kind), " workflow step \"", workflowStep, |
268 | 6 | "\" uses configure preset \"", stepConfigurePreset, |
269 | 6 | "\", but workflow configure preset is \"", workflowConfigurePreset, '"')); |
270 | 6 | } |
271 | | |
272 | | void INVALID_TEST_FILTER_INCLUDE_INDEX(Json::Value const* value, |
273 | | cmJSONState* state) |
274 | 0 | { |
275 | 0 | state->AddErrorAtValue( |
276 | 0 | "Invalid \"filter.include.index\" field: expected a string or object", |
277 | 0 | value); |
278 | 0 | } |
279 | | |
280 | | void NO_WORKFLOW_STEPS(std::string const& presetName, cmJSONState* state) |
281 | 12 | { |
282 | 12 | state->AddError( |
283 | 12 | cmStrCat("No workflow steps specified for \"", presetName, '"')); |
284 | 12 | } |
285 | | |
286 | | void FIRST_WORKFLOW_STEP_NOT_CONFIGURE(cm::string_view stepType, |
287 | | std::string const& stepName, |
288 | | cmJSONState* state) |
289 | 138 | { |
290 | 138 | state->AddError(cmStrCat("First workflow step ", |
291 | 138 | WorkflowStepLabel(stepType, stepName), |
292 | 138 | " must be a configure step")); |
293 | 138 | } |
294 | | |
295 | | void CONFIGURE_WORKFLOW_STEP_NOT_FIRST(cm::string_view stepType, |
296 | | std::string const& stepName, |
297 | | cmJSONState* state) |
298 | 9 | { |
299 | 9 | state->AddError(cmStrCat("Workflow step ", |
300 | 9 | WorkflowStepLabel(stepType, stepName), |
301 | 9 | " must be the first step")); |
302 | 9 | } |
303 | | |
304 | | void WORKFLOW_STEP_UNREACHABLE_FROM_FILE(cm::string_view stepType, |
305 | | std::string const& stepName, |
306 | | cmJSONState* state) |
307 | 0 | { |
308 | 0 | state->AddError(cmStrCat("Workflow step ", |
309 | 0 | WorkflowStepLabel(stepType, stepName), |
310 | 0 | " is unreachable from preset's file")); |
311 | 0 | } |
312 | | |
313 | | void CTEST_JUNIT_UNSUPPORTED(cmJSONState* state) |
314 | 0 | { |
315 | 0 | state->AddError( |
316 | 0 | "File version must be 6 or higher for CTest JUnit output support"); |
317 | 0 | } |
318 | | |
319 | | void TRACE_UNSUPPORTED(cmJSONState* state) |
320 | 0 | { |
321 | 0 | state->AddError("File version must be 7 or higher for trace preset support"); |
322 | 0 | } |
323 | | |
324 | | JsonErrors::ErrorGenerator UNRECOGNIZED_VERSION_RANGE(int min, int max) |
325 | 12 | { |
326 | 423 | return [min, max](Json::Value const* value, cmJSONState* state) -> void { |
327 | 423 | state->AddErrorAtValue(cmStrCat("Unrecognized \"version\" ", |
328 | 423 | value->asString(), ": must be >=", min, |
329 | 423 | " and <=", max), |
330 | 423 | value); |
331 | 423 | }; |
332 | 12 | } |
333 | | |
334 | | JsonErrors::ErrorGenerator UNRECOGNIZED_CMAKE_VERSION( |
335 | | std::string const& version, int current, int required) |
336 | 255 | { |
337 | 255 | return [version, current, required](Json::Value const* value, |
338 | 255 | cmJSONState* state) -> void { |
339 | 255 | state->AddErrorAtValue(cmStrCat("\"cmakeMinimumRequired\" ", version, |
340 | 255 | " version ", required, |
341 | 255 | " must be less than ", current), |
342 | 255 | value); |
343 | 255 | }; |
344 | 255 | } |
345 | | |
346 | | void INVALID_PRESET_NAME(Json::Value const* value, cmJSONState* state) |
347 | 7.43k | { |
348 | 7.43k | std::string errMsg = "Invalid Preset Name"; |
349 | 7.43k | if (value && value->isConvertibleTo(Json::ValueType::stringValue) && |
350 | 7.06k | !value->asString().empty()) { |
351 | 5.76k | errMsg = cmStrCat(std::move(errMsg), ": ", value->asString()); |
352 | 5.76k | } |
353 | 7.43k | state->AddErrorAtValue(errMsg, value); |
354 | 7.43k | } |
355 | | |
356 | | void INVALID_CONDITION(Json::Value const* value, cmJSONState* state) |
357 | 97.7k | { |
358 | 97.7k | state->AddErrorAtValue( |
359 | 97.7k | cmStrCat("Invalid condition for preset \"", getPresetName(state), '"'), |
360 | 97.7k | value); |
361 | 97.7k | } |
362 | | |
363 | | JsonErrors::ErrorGenerator INVALID_CONDITION_OBJECT( |
364 | | JsonErrors::ObjectError errorType, Json::Value::Members const& extraFields) |
365 | 80.8k | { |
366 | 80.8k | return JsonErrors::INVALID_NAMED_OBJECT( |
367 | 80.8k | [](Json::Value const*, cmJSONState* state) -> std::string { |
368 | 80.8k | return cmStrCat(" condition for preset \"", getPresetName(state), '"'); |
369 | 80.8k | })(errorType, extraFields); |
370 | 80.8k | } |
371 | | |
372 | | JsonErrors::ErrorGenerator INVALID_VARIABLE_OBJECT( |
373 | | JsonErrors::ObjectError errorType, Json::Value::Members const& extraFields) |
374 | 6.43k | { |
375 | 6.43k | return JsonErrors::INVALID_NAMED_OBJECT( |
376 | 6.43k | [](Json::Value const*, cmJSONState* state) -> std::string { |
377 | 6.43k | return getVariableName(state); |
378 | 6.43k | })(errorType, extraFields); |
379 | 6.43k | } |
380 | | |
381 | | JsonErrors::ErrorGenerator INVALID_PRESET_OBJECT( |
382 | | JsonErrors::ObjectError errorType, Json::Value::Members const& extraFields) |
383 | 383k | { |
384 | 383k | return JsonErrors::INVALID_NAMED_OBJECT( |
385 | 383k | [](Json::Value const*, cmJSONState*) -> std::string { return "Preset"; })( |
386 | 383k | errorType, extraFields); |
387 | 383k | } |
388 | | |
389 | | JsonErrors::ErrorGenerator INVALID_ROOT_OBJECT( |
390 | | JsonErrors::ObjectError errorType, Json::Value::Members const& extraFields) |
391 | 2.68k | { |
392 | 2.68k | return JsonErrors::INVALID_NAMED_OBJECT( |
393 | 2.68k | [](Json::Value const*, cmJSONState*) -> std::string { |
394 | 2.68k | return "root object"; |
395 | 2.68k | })(errorType, extraFields); |
396 | 2.68k | } |
397 | | |
398 | | void PRESET_MISSING_FIELD(std::string const& presetName, |
399 | | std::string const& missingField, cmJSONState* state) |
400 | 546 | { |
401 | 546 | state->AddError(cmStrCat("Preset \"", presetName, "\" missing field \"", |
402 | 546 | missingField, '"')); |
403 | 546 | } |
404 | | |
405 | | void SCHEMA_UNSUPPORTED(cmJSONState* state) |
406 | 3 | { |
407 | 3 | state->AddError("File version must be 8 or higher for $schema support"); |
408 | 3 | } |
409 | | |
410 | | void DIAGNOSTIC_UNSUPPORTED(cm::string_view name, cm::string_view context, |
411 | | int version, cmJSONState* state) |
412 | 0 | { |
413 | 0 | state->AddError(cmStrCat("File version must be ", std::to_string(version), |
414 | 0 | " or higher for ", context, '.', name, " support")); |
415 | 0 | } |
416 | | |
417 | | void DIAGNOSTIC_REMOVED(cm::string_view name, cm::string_view context, |
418 | | int version, cmJSONState* state) |
419 | 0 | { |
420 | 0 | state->AddError(cmStrCat("File version must be ", std::to_string(version), |
421 | 0 | " or lower for ", context, '.', name, " support")); |
422 | 0 | } |
423 | | } |