Coverage Report

Created: 2026-09-14 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
};