/src/CMake/Source/cmFileAPI.h
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 | | #pragma once |
4 | | |
5 | | #include "cmConfigure.h" // IWYU pragma: keep |
6 | | |
7 | | #include <functional> |
8 | | #include <map> |
9 | | #include <memory> |
10 | | #include <string> |
11 | | #include <unordered_set> |
12 | | #include <vector> |
13 | | |
14 | | #include <cm3p/json/value.h> |
15 | | #include <cm3p/json/writer.h> |
16 | | |
17 | | class cmake; |
18 | | |
19 | | class cmFileAPI |
20 | | { |
21 | | public: |
22 | | cmFileAPI(cmake* cm); |
23 | | |
24 | | /** Read fileapi queries from disk. */ |
25 | | void ReadQueries(); |
26 | | |
27 | | /** Get the list of configureLog object kind versions requested. */ |
28 | | std::vector<unsigned int> GetConfigureLogVersions(); |
29 | | |
30 | | /** Identify the situation in which WriteReplies is called. */ |
31 | | enum class IndexFor |
32 | | { |
33 | | Success, |
34 | | FailedConfigure, |
35 | | FailedCompute, |
36 | | FailedGenerate, |
37 | | }; |
38 | | |
39 | | /** Write fileapi replies to disk. */ |
40 | | void WriteReplies(IndexFor indexFor); |
41 | | |
42 | | /** Get the "cmake" instance with which this was constructed. */ |
43 | 0 | cmake* GetCMakeInstance() const { return this->CMakeInstance; } |
44 | | |
45 | | /** Convert a JSON object or array into an object with a single |
46 | | "jsonFile" member specifying a file named with the given prefix |
47 | | and holding the original object. Other JSON types are unchanged. */ |
48 | | Json::Value MaybeJsonFile(Json::Value in, std::string const& prefix); |
49 | | |
50 | | /** Report file-api capabilities for cmake -E capabilities. */ |
51 | | static Json::Value ReportCapabilities(); |
52 | | |
53 | | // Keep in sync with ObjectKindName. |
54 | | enum class ObjectKind |
55 | | { |
56 | | CodeModel, |
57 | | ConfigureLog, |
58 | | Cache, |
59 | | CMakeFiles, |
60 | | Toolchains, |
61 | | InternalTest |
62 | | }; |
63 | | |
64 | | bool AddProjectQuery(ObjectKind kind, unsigned majorVersion, |
65 | | unsigned minorVersion); |
66 | | |
67 | | /** Build a JSON object with major and minor fields. */ |
68 | | static Json::Value BuildVersion(unsigned int major, unsigned int minor); |
69 | | |
70 | | /** Return the subset of 'entries' to delete after a configure: those not |
71 | | named in 'replyNames' whose identity ('getId') also matches no reply. |
72 | | Deciding by identity rather than name keeps an entry that aliases a |
73 | | just-written reply on a case-insensitive filesystem; an entry whose |
74 | | identity cannot be obtained is retained. Static/templated for tests. */ |
75 | | template <typename FileIdT> |
76 | | static std::vector<std::string> FilesToRemove( |
77 | | std::vector<std::string> const& entries, |
78 | | std::unordered_set<std::string> const& replyNames, |
79 | | std::function<bool(std::string const&, FileIdT&)> const& getId) |
80 | 0 | { |
81 | 0 | std::vector<FileIdT> keptIds; |
82 | 0 | for (std::string const& name : replyNames) { |
83 | 0 | FileIdT id; |
84 | 0 | if (getId(name, id)) { |
85 | 0 | keptIds.push_back(id); |
86 | 0 | } |
87 | 0 | } |
88 | |
|
89 | 0 | std::vector<std::string> toRemove; |
90 | 0 | for (std::string const& entry : entries) { |
91 | 0 | if (replyNames.find(entry) != replyNames.end()) { |
92 | 0 | continue; |
93 | 0 | } |
94 | 0 | FileIdT id; |
95 | 0 | if (!getId(entry, id)) { |
96 | 0 | continue; |
97 | 0 | } |
98 | 0 | bool aliasesKept = false; |
99 | 0 | for (FileIdT const& keptId : keptIds) { |
100 | 0 | if (id == keptId) { |
101 | 0 | aliasesKept = true; |
102 | 0 | break; |
103 | 0 | } |
104 | 0 | } |
105 | 0 | if (aliasesKept) { |
106 | 0 | continue; |
107 | 0 | } |
108 | 0 | toRemove.push_back(entry); |
109 | 0 | } |
110 | 0 | return toRemove; |
111 | 0 | } |
112 | | |
113 | | private: |
114 | | cmake* CMakeInstance; |
115 | | |
116 | | /** The api/v1 directory location. */ |
117 | | std::string APIv1; |
118 | | |
119 | | /** api/v1 directory in the user's shared CMake config directory. */ |
120 | | std::string UserAPIv1; |
121 | | |
122 | | /** The set of files we have just written to the reply directory. */ |
123 | | std::unordered_set<std::string> ReplyFiles; |
124 | | |
125 | | static std::vector<std::string> LoadDir(std::string const& dir); |
126 | | void RemoveOldReplyFiles(); |
127 | | |
128 | | /** Identify one object kind and major version. */ |
129 | | struct Object |
130 | | { |
131 | | ObjectKind Kind; |
132 | | unsigned int Version = 0; |
133 | | friend bool operator<(Object l, Object r) |
134 | 0 | { |
135 | 0 | if (l.Kind != r.Kind) { |
136 | 0 | return l.Kind < r.Kind; |
137 | 0 | } |
138 | 0 | return l.Version < r.Version; |
139 | 0 | } |
140 | | friend bool operator==(Object l, Object r) |
141 | 0 | { |
142 | 0 | return l.Kind == r.Kind && l.Version == r.Version; |
143 | 0 | } |
144 | 0 | friend bool operator!=(Object l, Object r) { return !(l == r); } |
145 | | }; |
146 | | |
147 | | /** Represent content of a query directory. */ |
148 | | struct Query |
149 | | { |
150 | | /** Known object kind-version pairs. */ |
151 | | std::vector<Object> Known; |
152 | | /** Unknown object kind names. */ |
153 | | std::vector<std::string> Unknown; |
154 | | }; |
155 | | |
156 | | /** Represent one request in a client 'query.json'. */ |
157 | | struct ClientRequest : public Object |
158 | | { |
159 | | /** Empty if request is valid, else the error string. */ |
160 | | std::string Error; |
161 | | }; |
162 | | |
163 | | /** Represent the "requests" in a client 'query.json'. */ |
164 | | struct ClientRequests : public std::vector<ClientRequest> |
165 | | { |
166 | | /** Empty if requests field is valid, else the error string. */ |
167 | | std::string Error; |
168 | | }; |
169 | | |
170 | | /** Represent the content of a client query.json file. */ |
171 | | struct ClientQueryJson |
172 | | { |
173 | | /** The error string if parsing failed, else empty. */ |
174 | | std::string Error; |
175 | | |
176 | | /** The 'query.json' object "client" member if it exists, else null. */ |
177 | | Json::Value ClientValue; |
178 | | |
179 | | /** The 'query.json' object "requests" member if it exists, else null. */ |
180 | | Json::Value RequestsValue; |
181 | | |
182 | | /** Requests extracted from 'query.json'. */ |
183 | | ClientRequests Requests; |
184 | | }; |
185 | | |
186 | | /** Represent content of a client query directory. */ |
187 | | struct ClientQuery |
188 | | { |
189 | | /** The content of the client query directory except 'query.json'. */ |
190 | | Query DirQuery; |
191 | | |
192 | | /** True if 'query.json' exists. */ |
193 | | bool HaveQueryJson = false; |
194 | | |
195 | | /** The 'query.json' content. */ |
196 | | ClientQueryJson QueryJson; |
197 | | }; |
198 | | |
199 | | /** Whether the top-level query directory exists at all. */ |
200 | | bool QueryExists = false; |
201 | | |
202 | | /** The content of the top-level query directory. */ |
203 | | Query TopQuery; |
204 | | |
205 | | /** The content of each "client-$client" query directory. */ |
206 | | std::map<std::string, ClientQuery> ClientQueries; |
207 | | |
208 | | /** Reply index object generated for object kind/version. |
209 | | This populates the "objects" field of the reply index. */ |
210 | | std::map<Object, Json::Value> ReplyIndexObjects; |
211 | | |
212 | | /** Identify the situation in which WriteReplies was called. */ |
213 | | IndexFor ReplyIndexFor = IndexFor::Success; |
214 | | |
215 | | std::unique_ptr<Json::StreamWriter> JsonWriter; |
216 | | |
217 | | bool ReadJsonFile(std::string const& file, Json::Value& value, |
218 | | std::string& error); |
219 | | |
220 | | std::string WriteJsonFile( |
221 | | Json::Value const& value, std::string const& prefix, |
222 | | std::string (*computeSuffix)(std::string const&) = ComputeSuffixHash); |
223 | | static std::string ComputeSuffixHash(std::string const&); |
224 | | static std::string ComputeSuffixTime(std::string const&); |
225 | | |
226 | | static bool ReadQuery(std::string const& query, |
227 | | std::vector<Object>& objects); |
228 | | void ReadClient(std::string const& client); |
229 | | void ReadClientQuery(std::string const& client, ClientQueryJson& q); |
230 | | |
231 | | Json::Value BuildReplyIndex(); |
232 | | Json::Value BuildCMake(); |
233 | | Json::Value BuildReply(Query const& q); |
234 | | Json::Value BuildReplyEntry(Object object); |
235 | | static Json::Value BuildReplyError(std::string const& error); |
236 | | Json::Value const& AddReplyIndexObject(Object o); |
237 | | |
238 | | static char const* ObjectKindName(ObjectKind kind); |
239 | | static std::string ObjectName(Object o); |
240 | | |
241 | | Json::Value BuildObject(Object object); |
242 | | |
243 | | ClientRequests BuildClientRequests(Json::Value const& requests); |
244 | | ClientRequest BuildClientRequest(Json::Value const& request); |
245 | | Json::Value BuildClientReply(ClientQuery const& q); |
246 | | Json::Value BuildClientReplyResponses(ClientRequests const& requests); |
247 | | Json::Value BuildClientReplyResponse(ClientRequest const& request); |
248 | | |
249 | | struct RequestVersion |
250 | | { |
251 | | unsigned int Major = 0; |
252 | | unsigned int Minor = 0; |
253 | | }; |
254 | | static bool ReadRequestVersions(Json::Value const& version, |
255 | | std::vector<RequestVersion>& versions, |
256 | | std::string& error); |
257 | | static bool ReadRequestVersion(Json::Value const& version, bool inArray, |
258 | | std::vector<RequestVersion>& result, |
259 | | std::string& error); |
260 | | static std::string NoSupportedVersion( |
261 | | std::vector<RequestVersion> const& versions); |
262 | | |
263 | | void BuildClientRequestCodeModel( |
264 | | ClientRequest& r, std::vector<RequestVersion> const& versions); |
265 | | Json::Value BuildCodeModel(Object object); |
266 | | |
267 | | void BuildClientRequestConfigureLog( |
268 | | ClientRequest& r, std::vector<RequestVersion> const& versions); |
269 | | Json::Value BuildConfigureLog(Object object); |
270 | | |
271 | | void BuildClientRequestCache(ClientRequest& r, |
272 | | std::vector<RequestVersion> const& versions); |
273 | | Json::Value BuildCache(Object object); |
274 | | |
275 | | void BuildClientRequestCMakeFiles( |
276 | | ClientRequest& r, std::vector<RequestVersion> const& versions); |
277 | | Json::Value BuildCMakeFiles(Object object); |
278 | | |
279 | | void BuildClientRequestToolchains( |
280 | | ClientRequest& r, std::vector<RequestVersion> const& versions); |
281 | | Json::Value BuildToolchains(Object object); |
282 | | |
283 | | void BuildClientRequestInternalTest( |
284 | | ClientRequest& r, std::vector<RequestVersion> const& versions); |
285 | | Json::Value BuildInternalTest(Object object); |
286 | | }; |