/src/CMake/Source/cmInstrumentationQuery.cxx
Line | Count | Source |
1 | | #include "cmInstrumentationQuery.h" |
2 | | |
3 | | #include <algorithm> |
4 | | #include <ctime> |
5 | | #include <functional> |
6 | | #include <iterator> |
7 | | #include <set> |
8 | | #include <vector> |
9 | | |
10 | | #include <cmext/string_view> |
11 | | |
12 | | #include <cm3p/json/value.h> |
13 | | |
14 | | #include "cmJSONHelpers.h" |
15 | | #include "cmStringAlgorithms.h" |
16 | | |
17 | | std::vector<std::string> const cmInstrumentationQuery::OptionString{ |
18 | | "staticSystemInformation", |
19 | | "dynamicSystemInformation", |
20 | | "captureOutput", |
21 | | "compileTrace", |
22 | | "cdashSubmit", |
23 | | "cdashVerbose", |
24 | | "trace" |
25 | | }; |
26 | | std::vector<std::string> const cmInstrumentationQuery::HookString{ |
27 | | "postGenerate", "preBuild", "postBuild", "preCMakeBuild", |
28 | | "postCMakeBuild", "postCTest", "postCMakeInstall", "postCMakeWorkflow", |
29 | | "prepareForCDash", "manual" |
30 | | }; |
31 | | |
32 | | namespace ErrorMessages { |
33 | | using ErrorGenerator = |
34 | | std::function<void(Json::Value const*, cmJSONState* state)>; |
35 | | ErrorGenerator ErrorGeneratorBuilder(std::string const& errorMessage) |
36 | 4 | { |
37 | 4 | return [errorMessage](Json::Value const* value, cmJSONState* state) -> void { |
38 | 0 | state->AddErrorAtValue(errorMessage, value); |
39 | 0 | }; |
40 | 4 | }; |
41 | | |
42 | | static ErrorGenerator InvalidArray = ErrorGeneratorBuilder("Invalid Array"); |
43 | | JsonErrors::ErrorGenerator InvalidRootQueryObject( |
44 | | JsonErrors::ObjectError errorType, Json::Value::Members const& extraFields) |
45 | 0 | { |
46 | 0 | return JsonErrors::INVALID_NAMED_OBJECT( |
47 | 0 | [](Json::Value const*, cmJSONState*) -> std::string { |
48 | 0 | return "root object"; |
49 | 0 | })(errorType, extraFields); |
50 | 0 | } |
51 | | }; |
52 | | |
53 | | using JSONHelperBuilder = cmJSONHelperBuilder; |
54 | | using Version = cmInstrumentationQuery::Version; |
55 | | |
56 | | template <typename E> |
57 | | static std::function<bool(E&, Json::Value const*, cmJSONState*)> EnumHelper( |
58 | | std::vector<std::string> const toString, std::string const& type) |
59 | 8 | { |
60 | 8 | return [toString, type](E& out, Json::Value const* value, |
61 | 8 | cmJSONState* state) -> bool { |
62 | 0 | for (size_t i = 0; i < toString.size(); ++i) { |
63 | 0 | if (value->asString() == toString[i]) { |
64 | 0 | out = (E)i; |
65 | 0 | return true; |
66 | 0 | } |
67 | 0 | } |
68 | 0 | state->AddErrorAtValue( |
69 | 0 | cmStrCat("Not a valid ", type, ": \"", value->asString(), '"'), value); |
70 | 0 | return false; |
71 | 0 | }; Unexecuted instantiation: cmInstrumentationQuery.cxx:EnumHelper<cmInstrumentationQuery::Option>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::{lambda(cmInstrumentationQuery::Option&, Json::Value const*, cmJSONState*)#1}::operator()(cmInstrumentationQuery::Option&, Json::Value const*, cmJSONState*) constUnexecuted instantiation: cmInstrumentationQuery.cxx:EnumHelper<cmInstrumentationQuery::Hook>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::{lambda(cmInstrumentationQuery::Hook&, Json::Value const*, cmJSONState*)#1}::operator()(cmInstrumentationQuery::Hook&, Json::Value const*, cmJSONState*) const |
72 | 8 | } cmInstrumentationQuery.cxx:std::__1::function<bool (cmInstrumentationQuery::Option&, Json::Value const*, cmJSONState*)> EnumHelper<cmInstrumentationQuery::Option>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) Line | Count | Source | 59 | 4 | { | 60 | 4 | return [toString, type](E& out, Json::Value const* value, | 61 | 4 | cmJSONState* state) -> bool { | 62 | 4 | for (size_t i = 0; i < toString.size(); ++i) { | 63 | 4 | if (value->asString() == toString[i]) { | 64 | 4 | out = (E)i; | 65 | 4 | return true; | 66 | 4 | } | 67 | 4 | } | 68 | 4 | state->AddErrorAtValue( | 69 | 4 | cmStrCat("Not a valid ", type, ": \"", value->asString(), '"'), value); | 70 | 4 | return false; | 71 | 4 | }; | 72 | 4 | } |
cmInstrumentationQuery.cxx:std::__1::function<bool (cmInstrumentationQuery::Hook&, Json::Value const*, cmJSONState*)> EnumHelper<cmInstrumentationQuery::Hook>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) Line | Count | Source | 59 | 4 | { | 60 | 4 | return [toString, type](E& out, Json::Value const* value, | 61 | 4 | cmJSONState* state) -> bool { | 62 | 4 | for (size_t i = 0; i < toString.size(); ++i) { | 63 | 4 | if (value->asString() == toString[i]) { | 64 | 4 | out = (E)i; | 65 | 4 | return true; | 66 | 4 | } | 67 | 4 | } | 68 | 4 | state->AddErrorAtValue( | 69 | 4 | cmStrCat("Not a valid ", type, ": \"", value->asString(), '"'), value); | 70 | 4 | return false; | 71 | 4 | }; | 72 | 4 | } |
|
73 | | static auto const OptionHelper = EnumHelper<cmInstrumentationQuery::Option>( |
74 | | cmInstrumentationQuery::OptionString, "option"); |
75 | | static auto const OptionListHelper = |
76 | | JSONHelperBuilder::Vector<cmInstrumentationQuery::Option>( |
77 | | ErrorMessages::InvalidArray, OptionHelper); |
78 | | static auto const HookHelper = EnumHelper<cmInstrumentationQuery::Hook>( |
79 | | cmInstrumentationQuery::HookString, "hook"); |
80 | | static auto const HookListHelper = |
81 | | JSONHelperBuilder::Vector<cmInstrumentationQuery::Hook>( |
82 | | ErrorMessages::InvalidArray, HookHelper); |
83 | | static auto const CallbackHelper = JSONHelperBuilder::String(); |
84 | | static auto const CallbackListHelper = JSONHelperBuilder::Vector<std::string>( |
85 | | ErrorMessages::InvalidArray, CallbackHelper); |
86 | | |
87 | | JsonErrors::ErrorGenerator InvalidVersionObject( |
88 | | JsonErrors::ObjectError errorType, Json::Value::Members const& extraFields) |
89 | 0 | { |
90 | 0 | return JsonErrors::INVALID_NAMED_OBJECT( |
91 | 0 | [](Json::Value const*, cmJSONState*) -> std::string { |
92 | 0 | return "version object"; |
93 | 0 | })(errorType, extraFields); |
94 | 0 | } |
95 | | |
96 | | static auto const VersionObjectHelper = |
97 | | JSONHelperBuilder::Object<Version>(InvalidVersionObject, false) |
98 | | .Bind("major"_s, &Version::Major, JSONHelperBuilder::Int(), true) |
99 | | .Bind("minor"_s, &Version::Minor, JSONHelperBuilder::Int(), false); |
100 | | |
101 | | bool VersionHelper(Version& out, Json::Value const* value, cmJSONState* state) |
102 | 0 | { |
103 | 0 | out.Minor = 0; |
104 | 0 | if (value->isInt()) { |
105 | 0 | out.Major = value->asInt(); |
106 | 0 | } else if (value->isObject()) { |
107 | 0 | if (!VersionObjectHelper(out, value, state)) { |
108 | 0 | return false; |
109 | 0 | } |
110 | 0 | } else { |
111 | 0 | state->AddErrorAtValue("Version must be an integer or object", value); |
112 | 0 | return false; |
113 | 0 | } |
114 | 0 | return true; |
115 | 0 | } |
116 | | |
117 | | using QueryRoot = cmInstrumentationQuery::QueryJSONRoot; |
118 | | |
119 | | static auto const QueryRootHelper = |
120 | | JSONHelperBuilder::Object<QueryRoot>(ErrorMessages::InvalidRootQueryObject, |
121 | | false) |
122 | | .Bind("version"_s, &QueryRoot::version, VersionHelper, true) |
123 | | .Bind("options"_s, &QueryRoot::options, OptionListHelper, false) |
124 | | .Bind("hooks"_s, &QueryRoot::hooks, HookListHelper, false) |
125 | | .Bind("callbacks"_s, &QueryRoot::callbacks, CallbackListHelper, false); |
126 | | |
127 | | static auto const QueryRootVersionOnlyHelper = |
128 | | JSONHelperBuilder::Object<QueryRoot>(ErrorMessages::InvalidRootQueryObject, |
129 | | true) |
130 | | .Bind("version"_s, &QueryRoot::version, VersionHelper, true); |
131 | | |
132 | | bool cmInstrumentationQuery::ReadJSON(std::string const& filename, |
133 | | std::string& errorMessage, |
134 | | std::set<Option>& options, |
135 | | std::set<Hook>& hooks, |
136 | | std::vector<Callback>& callbacks) |
137 | 0 | { |
138 | 0 | Json::Value root; |
139 | 0 | this->parseState = cmJSONState(filename, &root); |
140 | 0 | if (!this->parseState.errors.empty()) { |
141 | 0 | errorMessage = this->parseState.GetErrorMessage(true); |
142 | 0 | return false; |
143 | 0 | } |
144 | 0 | if (!QueryRootVersionOnlyHelper(this->queryRoot, &root, &this->parseState)) { |
145 | 0 | errorMessage = this->parseState.GetErrorMessage(true); |
146 | 0 | return false; |
147 | 0 | } |
148 | 0 | if (!ValidDataVersion(this->queryRoot.version)) { |
149 | | // Ignore invalid data versions |
150 | 0 | return true; |
151 | 0 | } |
152 | 0 | if (!QueryRootHelper(this->queryRoot, &root, &this->parseState)) { |
153 | 0 | errorMessage = this->parseState.GetErrorMessage(true); |
154 | 0 | return false; |
155 | 0 | } |
156 | 0 | std::move(this->queryRoot.options.begin(), this->queryRoot.options.end(), |
157 | 0 | std::inserter(options, options.end())); |
158 | 0 | std::move(this->queryRoot.hooks.begin(), this->queryRoot.hooks.end(), |
159 | 0 | std::inserter(hooks, hooks.end())); |
160 | 0 | for (auto const& callback : this->queryRoot.callbacks) { |
161 | 0 | callbacks.push_back({ callback, this->queryRoot.version }); |
162 | 0 | } |
163 | 0 | return true; |
164 | 0 | } |
165 | | |
166 | | bool cmInstrumentationQuery::ValidDataVersion(Version version) |
167 | 0 | { |
168 | 0 | auto const latest = LatestDataVersion(); |
169 | 0 | return version.Major == latest.Major && version.Minor <= latest.Minor; |
170 | 0 | } |
171 | | |
172 | | Version cmInstrumentationQuery::LatestDataVersion() |
173 | 4 | { |
174 | 4 | Version latest; |
175 | 4 | latest.Major = 1; |
176 | 4 | latest.Minor = 1; |
177 | 4 | return latest; |
178 | 4 | } |