1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
13 #include "cmsys/Directory.hxx"
14 #include "cmsys/FStream.hxx"
16 #include "cmCryptoHash.h"
17 #include "cmFileAPICMakeFiles.h"
18 #include "cmFileAPICache.h"
19 #include "cmFileAPICodemodel.h"
20 #include "cmFileAPIConfigureLog.h"
21 #include "cmFileAPIToolchains.h"
22 #include "cmGlobalGenerator.h"
23 #include "cmStringAlgorithms.h"
24 #include "cmSystemTools.h"
25 #include "cmTimestamp.h"
28 cmFileAPI::cmFileAPI(cmake
* cm
)
32 this->CMakeInstance
->GetHomeOutputDirectory() + "/.cmake/api/v1";
34 Json::CharReaderBuilder rbuilder
;
35 rbuilder
["collectComments"] = false;
36 rbuilder
["failIfExtra"] = true;
37 rbuilder
["rejectDupKeys"] = false;
38 rbuilder
["strictRoot"] = true;
40 std::unique_ptr
<Json::CharReader
>(rbuilder
.newCharReader());
42 Json::StreamWriterBuilder wbuilder
;
43 wbuilder
["indentation"] = "\t";
45 std::unique_ptr
<Json::StreamWriter
>(wbuilder
.newStreamWriter());
48 void cmFileAPI::ReadQueries()
50 std::string
const query_dir
= this->APIv1
+ "/query";
51 this->QueryExists
= cmSystemTools::FileIsDirectory(query_dir
);
52 if (!this->QueryExists
) {
56 // Load queries at the top level.
57 std::vector
<std::string
> queries
= cmFileAPI::LoadDir(query_dir
);
59 // Read the queries and save for later.
60 for (std::string
& query
: queries
) {
61 if (cmHasLiteralPrefix(query
, "client-")) {
62 this->ReadClient(query
);
63 } else if (!cmFileAPI::ReadQuery(query
, this->TopQuery
.Known
)) {
64 this->TopQuery
.Unknown
.push_back(std::move(query
));
69 std::vector
<unsigned long> cmFileAPI::GetConfigureLogVersions()
71 std::vector
<unsigned long> versions
;
72 auto getConfigureLogVersions
= [&versions
](Query
const& q
) {
73 for (Object
const& o
: q
.Known
) {
74 if (o
.Kind
== ObjectKind::ConfigureLog
) {
75 versions
.emplace_back(o
.Version
);
79 getConfigureLogVersions(this->TopQuery
);
80 for (auto const& client
: this->ClientQueries
) {
81 getConfigureLogVersions(client
.second
.DirQuery
);
83 std::sort(versions
.begin(), versions
.end());
84 versions
.erase(std::unique(versions
.begin(), versions
.end()),
89 void cmFileAPI::WriteReplies()
91 if (this->QueryExists
) {
92 cmSystemTools::MakeDirectory(this->APIv1
+ "/reply");
93 this->WriteJsonFile(this->BuildReplyIndex(), "index", ComputeSuffixTime
);
96 this->RemoveOldReplyFiles();
99 std::vector
<std::string
> cmFileAPI::LoadDir(std::string
const& dir
)
101 std::vector
<std::string
> files
;
104 for (unsigned long i
= 0; i
< d
.GetNumberOfFiles(); ++i
) {
105 std::string f
= d
.GetFile(i
);
106 if (f
!= "." && f
!= "..") {
107 files
.push_back(std::move(f
));
110 std::sort(files
.begin(), files
.end());
114 void cmFileAPI::RemoveOldReplyFiles()
116 std::string
const reply_dir
= this->APIv1
+ "/reply";
117 std::vector
<std::string
> files
= this->LoadDir(reply_dir
);
118 for (std::string
const& f
: files
) {
119 if (this->ReplyFiles
.find(f
) == this->ReplyFiles
.end()) {
120 std::string file
= cmStrCat(reply_dir
, "/", f
);
121 cmSystemTools::RemoveFile(file
);
126 bool cmFileAPI::ReadJsonFile(std::string
const& file
, Json::Value
& value
,
129 std::vector
<char> content
;
132 if (!cmSystemTools::FileIsDirectory(file
)) {
133 fin
.open(file
.c_str(), std::ios::binary
);
135 auto finEnd
= fin
.rdbuf()->pubseekoff(0, std::ios::end
);
137 size_t finSize
= finEnd
;
139 // Allocate a buffer to read the whole file.
140 content
.resize(finSize
);
142 // Now read the file from the beginning.
143 fin
.seekg(0, std::ios::beg
);
144 fin
.read(content
.data(), finSize
);
146 fin
.setstate(std::ios::failbit
);
151 value
= Json::Value();
152 error
= "failed to read from file";
156 // Parse our buffer as json.
157 if (!this->JsonReader
->parse(content
.data(), content
.data() + content
.size(),
159 value
= Json::Value();
166 std::string
cmFileAPI::WriteJsonFile(
167 Json::Value
const& value
, std::string
const& prefix
,
168 std::string (*computeSuffix
)(std::string
const&))
170 std::string fileName
;
172 // Write the json file with a temporary name.
173 std::string
const& tmpFile
= this->APIv1
+ "/tmp.json";
174 cmsys::ofstream
ftmp(tmpFile
.c_str());
175 this->JsonWriter
->write(value
, &ftmp
);
179 cmSystemTools::RemoveFile(tmpFile
);
183 // Compute the final name for the file.
184 fileName
= prefix
+ "-" + computeSuffix(tmpFile
) + ".json";
186 // Create the destination.
187 std::string file
= this->APIv1
+ "/reply";
188 cmSystemTools::MakeDirectory(file
);
192 // If the final name already exists then assume it has proper content.
193 // Otherwise, atomically place the reply file at its final name
194 if (cmSystemTools::FileExists(file
, true) ||
195 !cmSystemTools::RenameFile(tmpFile
, file
)) {
196 cmSystemTools::RemoveFile(tmpFile
);
199 // Record this among files we have just written.
200 this->ReplyFiles
.insert(fileName
);
205 Json::Value
cmFileAPI::MaybeJsonFile(Json::Value in
, std::string
const& prefix
)
208 if (in
.isObject() || in
.isArray()) {
209 out
= Json::objectValue
;
210 out
["jsonFile"] = this->WriteJsonFile(in
, prefix
);
217 std::string
cmFileAPI::ComputeSuffixHash(std::string
const& file
)
219 cmCryptoHash
hasher(cmCryptoHash::AlgoSHA3_256
);
220 std::string hash
= hasher
.HashFile(file
);
221 hash
.resize(20, '0');
225 std::string
cmFileAPI::ComputeSuffixTime(std::string
const&)
227 std::chrono::milliseconds ms
=
228 std::chrono::duration_cast
<std::chrono::milliseconds
>(
229 std::chrono::system_clock::now().time_since_epoch());
230 std::chrono::seconds s
=
231 std::chrono::duration_cast
<std::chrono::seconds
>(ms
);
233 std::time_t ts
= s
.count();
234 std::size_t tms
= ms
.count() % 1000;
237 std::ostringstream ss
;
238 ss
<< cmts
.CreateTimestampFromTimeT(ts
, "%Y-%m-%dT%H-%M-%S", true) << '-'
239 << std::setfill('0') << std::setw(4) << tms
;
243 bool cmFileAPI::ReadQuery(std::string
const& query
,
244 std::vector
<Object
>& objects
)
246 // Parse the "<kind>-" syntax.
247 std::string::size_type sep_pos
= query
.find('-');
248 if (sep_pos
== std::string::npos
) {
251 std::string kindName
= query
.substr(0, sep_pos
);
252 std::string verStr
= query
.substr(sep_pos
+ 1);
253 if (kindName
== ObjectKindName(ObjectKind::CodeModel
)) {
255 o
.Kind
= ObjectKind::CodeModel
;
256 if (verStr
== "v2") {
261 objects
.push_back(o
);
264 if (kindName
== ObjectKindName(ObjectKind::ConfigureLog
)) {
266 o
.Kind
= ObjectKind::ConfigureLog
;
267 if (verStr
== "v1") {
272 objects
.push_back(o
);
275 if (kindName
== ObjectKindName(ObjectKind::Cache
)) {
277 o
.Kind
= ObjectKind::Cache
;
278 if (verStr
== "v2") {
283 objects
.push_back(o
);
286 if (kindName
== ObjectKindName(ObjectKind::CMakeFiles
)) {
288 o
.Kind
= ObjectKind::CMakeFiles
;
289 if (verStr
== "v1") {
294 objects
.push_back(o
);
297 if (kindName
== ObjectKindName(ObjectKind::Toolchains
)) {
299 o
.Kind
= ObjectKind::Toolchains
;
300 if (verStr
== "v1") {
305 objects
.push_back(o
);
308 if (kindName
== ObjectKindName(ObjectKind::InternalTest
)) {
310 o
.Kind
= ObjectKind::InternalTest
;
311 if (verStr
== "v1") {
313 } else if (verStr
== "v2") {
318 objects
.push_back(o
);
324 void cmFileAPI::ReadClient(std::string
const& client
)
326 // Load queries for the client.
327 std::string clientDir
= this->APIv1
+ "/query/" + client
;
328 std::vector
<std::string
> queries
= this->LoadDir(clientDir
);
330 // Read the queries and save for later.
331 ClientQuery
& clientQuery
= this->ClientQueries
[client
];
332 for (std::string
& query
: queries
) {
333 if (query
== "query.json") {
334 clientQuery
.HaveQueryJson
= true;
335 this->ReadClientQuery(client
, clientQuery
.QueryJson
);
336 } else if (!this->ReadQuery(query
, clientQuery
.DirQuery
.Known
)) {
337 clientQuery
.DirQuery
.Unknown
.push_back(std::move(query
));
342 void cmFileAPI::ReadClientQuery(std::string
const& client
, ClientQueryJson
& q
)
344 // Read the query.json file.
345 std::string queryFile
= this->APIv1
+ "/query/" + client
+ "/query.json";
347 if (!this->ReadJsonFile(queryFile
, query
, q
.Error
)) {
350 if (!query
.isObject()) {
351 q
.Error
= "query root is not an object";
355 Json::Value
const& clientValue
= query
["client"];
356 if (!clientValue
.isNull()) {
357 q
.ClientValue
= clientValue
;
359 q
.RequestsValue
= std::move(query
["requests"]);
360 q
.Requests
= this->BuildClientRequests(q
.RequestsValue
);
363 Json::Value
cmFileAPI::BuildReplyIndex()
365 Json::Value
index(Json::objectValue
);
367 // Report information about this version of CMake.
368 index
["cmake"] = this->BuildCMake();
370 // Reply to all queries that we loaded.
371 Json::Value
& reply
= index
["reply"] = this->BuildReply(this->TopQuery
);
372 for (auto const& client
: this->ClientQueries
) {
373 std::string
const& clientName
= client
.first
;
374 ClientQuery
const& clientQuery
= client
.second
;
375 reply
[clientName
] = this->BuildClientReply(clientQuery
);
378 // Move our index of generated objects into its field.
379 Json::Value
& objects
= index
["objects"] = Json::arrayValue
;
380 for (auto& entry
: this->ReplyIndexObjects
) {
381 objects
.append(std::move(entry
.second
)); // NOLINT(*)
387 Json::Value
cmFileAPI::BuildCMake()
389 Json::Value cmake
= Json::objectValue
;
390 cmake
["version"] = this->CMakeInstance
->ReportVersionJson();
391 Json::Value
& cmake_paths
= cmake
["paths"] = Json::objectValue
;
392 cmake_paths
["cmake"] = cmSystemTools::GetCMakeCommand();
393 cmake_paths
["ctest"] = cmSystemTools::GetCTestCommand();
394 cmake_paths
["cpack"] = cmSystemTools::GetCPackCommand();
395 cmake_paths
["root"] = cmSystemTools::GetCMakeRoot();
396 cmake
["generator"] = this->CMakeInstance
->GetGlobalGenerator()->GetJson();
400 Json::Value
cmFileAPI::BuildReply(Query
const& q
)
402 Json::Value reply
= Json::objectValue
;
403 for (Object
const& o
: q
.Known
) {
404 std::string
const& name
= ObjectName(o
);
405 reply
[name
] = this->AddReplyIndexObject(o
);
408 for (std::string
const& name
: q
.Unknown
) {
409 reply
[name
] = cmFileAPI::BuildReplyError("unknown query file");
414 Json::Value
cmFileAPI::BuildReplyError(std::string
const& error
)
416 Json::Value e
= Json::objectValue
;
421 Json::Value
const& cmFileAPI::AddReplyIndexObject(Object
const& o
)
423 Json::Value
& indexEntry
= this->ReplyIndexObjects
[o
];
424 if (!indexEntry
.isNull()) {
425 // The reply object has already been generated.
429 // Generate this reply object.
430 Json::Value
const& object
= this->BuildObject(o
);
431 assert(object
.isObject());
433 // Populate this index entry.
434 indexEntry
= Json::objectValue
;
435 indexEntry
["kind"] = object
["kind"];
436 indexEntry
["version"] = object
["version"];
437 indexEntry
["jsonFile"] = this->WriteJsonFile(object
, ObjectName(o
));
441 const char* cmFileAPI::ObjectKindName(ObjectKind kind
)
443 // Keep in sync with ObjectKind enum.
444 static const char* objectKindNames
[] = {
452 return objectKindNames
[static_cast<size_t>(kind
)];
455 std::string
cmFileAPI::ObjectName(Object
const& o
)
457 std::string name
= cmStrCat(ObjectKindName(o
.Kind
), "-v", o
.Version
);
461 Json::Value
cmFileAPI::BuildVersion(unsigned int major
, unsigned int minor
)
464 version
["major"] = major
;
465 version
["minor"] = minor
;
469 Json::Value
cmFileAPI::BuildObject(Object
const& object
)
473 switch (object
.Kind
) {
474 case ObjectKind::CodeModel
:
475 value
= this->BuildCodeModel(object
);
477 case ObjectKind::ConfigureLog
:
478 value
= this->BuildConfigureLog(object
);
480 case ObjectKind::Cache
:
481 value
= this->BuildCache(object
);
483 case ObjectKind::CMakeFiles
:
484 value
= this->BuildCMakeFiles(object
);
486 case ObjectKind::Toolchains
:
487 value
= this->BuildToolchains(object
);
489 case ObjectKind::InternalTest
:
490 value
= this->BuildInternalTest(object
);
497 cmFileAPI::ClientRequests
cmFileAPI::BuildClientRequests(
498 Json::Value
const& requests
)
500 ClientRequests result
;
501 if (requests
.isNull()) {
502 result
.Error
= "'requests' member missing";
505 if (!requests
.isArray()) {
506 result
.Error
= "'requests' member is not an array";
510 result
.reserve(requests
.size());
511 for (Json::Value
const& request
: requests
) {
512 result
.emplace_back(this->BuildClientRequest(request
));
518 cmFileAPI::ClientRequest
cmFileAPI::BuildClientRequest(
519 Json::Value
const& request
)
523 if (!request
.isObject()) {
524 r
.Error
= "request is not an object";
528 Json::Value
const& kind
= request
["kind"];
530 r
.Error
= "'kind' member missing";
533 if (!kind
.isString()) {
534 r
.Error
= "'kind' member is not a string";
537 std::string
const& kindName
= kind
.asString();
539 if (kindName
== this->ObjectKindName(ObjectKind::CodeModel
)) {
540 r
.Kind
= ObjectKind::CodeModel
;
541 } else if (kindName
== this->ObjectKindName(ObjectKind::ConfigureLog
)) {
542 r
.Kind
= ObjectKind::ConfigureLog
;
543 } else if (kindName
== this->ObjectKindName(ObjectKind::Cache
)) {
544 r
.Kind
= ObjectKind::Cache
;
545 } else if (kindName
== this->ObjectKindName(ObjectKind::CMakeFiles
)) {
546 r
.Kind
= ObjectKind::CMakeFiles
;
547 } else if (kindName
== this->ObjectKindName(ObjectKind::Toolchains
)) {
548 r
.Kind
= ObjectKind::Toolchains
;
549 } else if (kindName
== this->ObjectKindName(ObjectKind::InternalTest
)) {
550 r
.Kind
= ObjectKind::InternalTest
;
552 r
.Error
= "unknown request kind '" + kindName
+ "'";
556 Json::Value
const& version
= request
["version"];
557 if (version
.isNull()) {
558 r
.Error
= "'version' member missing";
561 std::vector
<RequestVersion
> versions
;
562 if (!cmFileAPI::ReadRequestVersions(version
, versions
, r
.Error
)) {
567 case ObjectKind::CodeModel
:
568 this->BuildClientRequestCodeModel(r
, versions
);
570 case ObjectKind::ConfigureLog
:
571 this->BuildClientRequestConfigureLog(r
, versions
);
573 case ObjectKind::Cache
:
574 this->BuildClientRequestCache(r
, versions
);
576 case ObjectKind::CMakeFiles
:
577 this->BuildClientRequestCMakeFiles(r
, versions
);
579 case ObjectKind::Toolchains
:
580 this->BuildClientRequestToolchains(r
, versions
);
582 case ObjectKind::InternalTest
:
583 this->BuildClientRequestInternalTest(r
, versions
);
590 Json::Value
cmFileAPI::BuildClientReply(ClientQuery
const& q
)
592 Json::Value reply
= this->BuildReply(q
.DirQuery
);
594 if (!q
.HaveQueryJson
) {
598 Json::Value
& reply_query_json
= reply
["query.json"];
599 ClientQueryJson
const& qj
= q
.QueryJson
;
601 if (!qj
.Error
.empty()) {
602 reply_query_json
= this->BuildReplyError(qj
.Error
);
606 if (!qj
.ClientValue
.isNull()) {
607 reply_query_json
["client"] = qj
.ClientValue
;
610 if (!qj
.RequestsValue
.isNull()) {
611 reply_query_json
["requests"] = qj
.RequestsValue
;
614 reply_query_json
["responses"] = this->BuildClientReplyResponses(qj
.Requests
);
619 Json::Value
cmFileAPI::BuildClientReplyResponses(
620 ClientRequests
const& requests
)
622 Json::Value responses
;
624 if (!requests
.Error
.empty()) {
625 responses
= this->BuildReplyError(requests
.Error
);
629 responses
= Json::arrayValue
;
630 for (ClientRequest
const& request
: requests
) {
631 responses
.append(this->BuildClientReplyResponse(request
));
637 Json::Value
cmFileAPI::BuildClientReplyResponse(ClientRequest
const& request
)
639 Json::Value response
;
640 if (!request
.Error
.empty()) {
641 response
= this->BuildReplyError(request
.Error
);
644 response
= this->AddReplyIndexObject(request
);
648 bool cmFileAPI::ReadRequestVersions(Json::Value
const& version
,
649 std::vector
<RequestVersion
>& versions
,
652 if (version
.isArray()) {
653 for (Json::Value
const& v
: version
) {
654 if (!ReadRequestVersion(v
, /*inArray=*/true, versions
, error
)) {
659 if (!ReadRequestVersion(version
, /*inArray=*/false, versions
, error
)) {
666 bool cmFileAPI::ReadRequestVersion(Json::Value
const& version
, bool inArray
,
667 std::vector
<RequestVersion
>& result
,
670 if (version
.isUInt()) {
672 v
.Major
= version
.asUInt();
677 if (!version
.isObject()) {
679 error
= "'version' array entry is not a non-negative integer or object";
682 "'version' member is not a non-negative integer, object, or array";
687 Json::Value
const& major
= version
["major"];
688 if (major
.isNull()) {
689 error
= "'version' object 'major' member missing";
692 if (!major
.isUInt()) {
693 error
= "'version' object 'major' member is not a non-negative integer";
698 v
.Major
= major
.asUInt();
700 Json::Value
const& minor
= version
["minor"];
701 if (minor
.isUInt()) {
702 v
.Minor
= minor
.asUInt();
703 } else if (!minor
.isNull()) {
704 error
= "'version' object 'minor' member is not a non-negative integer";
713 std::string
cmFileAPI::NoSupportedVersion(
714 std::vector
<RequestVersion
> const& versions
)
716 std::ostringstream msg
;
717 msg
<< "no supported version specified";
718 if (!versions
.empty()) {
720 for (RequestVersion
const& v
: versions
) {
721 msg
<< " " << v
.Major
<< "." << v
.Minor
;
727 // The "codemodel" object kind.
729 // Update Help/manual/cmake-file-api.7.rst when updating this constant.
730 static unsigned int const CodeModelV2Minor
= 7;
732 void cmFileAPI::BuildClientRequestCodeModel(
733 ClientRequest
& r
, std::vector
<RequestVersion
> const& versions
)
735 // Select a known version from those requested.
736 for (RequestVersion
const& v
: versions
) {
737 if ((v
.Major
== 2 && v
.Minor
<= CodeModelV2Minor
)) {
743 r
.Error
= NoSupportedVersion(versions
);
747 Json::Value
cmFileAPI::BuildCodeModel(Object
const& object
)
749 Json::Value codemodel
= cmFileAPICodemodelDump(*this, object
.Version
);
750 codemodel
["kind"] = this->ObjectKindName(object
.Kind
);
752 Json::Value
& version
= codemodel
["version"];
753 if (object
.Version
== 2) {
754 version
= BuildVersion(2, CodeModelV2Minor
);
756 return codemodel
; // should be unreachable
762 // The "configureLog" object kind.
764 // Update Help/manual/cmake-file-api.7.rst when updating this constant.
765 static unsigned int const ConfigureLogV1Minor
= 0;
767 void cmFileAPI::BuildClientRequestConfigureLog(
768 ClientRequest
& r
, std::vector
<RequestVersion
> const& versions
)
770 // Select a known version from those requested.
771 for (RequestVersion
const& v
: versions
) {
772 if ((v
.Major
== 1 && v
.Minor
<= ConfigureLogV1Minor
)) {
778 r
.Error
= NoSupportedVersion(versions
);
782 Json::Value
cmFileAPI::BuildConfigureLog(Object
const& object
)
784 Json::Value configureLog
= cmFileAPIConfigureLogDump(*this, object
.Version
);
785 configureLog
["kind"] = this->ObjectKindName(object
.Kind
);
787 Json::Value
& version
= configureLog
["version"];
788 if (object
.Version
== 1) {
789 version
= BuildVersion(1, ConfigureLogV1Minor
);
791 return configureLog
; // should be unreachable
797 // The "cache" object kind.
799 static unsigned int const CacheV2Minor
= 0;
801 void cmFileAPI::BuildClientRequestCache(
802 ClientRequest
& r
, std::vector
<RequestVersion
> const& versions
)
804 // Select a known version from those requested.
805 for (RequestVersion
const& v
: versions
) {
806 if ((v
.Major
== 2 && v
.Minor
<= CacheV2Minor
)) {
812 r
.Error
= NoSupportedVersion(versions
);
816 Json::Value
cmFileAPI::BuildCache(Object
const& object
)
818 Json::Value cache
= cmFileAPICacheDump(*this, object
.Version
);
819 cache
["kind"] = this->ObjectKindName(object
.Kind
);
821 Json::Value
& version
= cache
["version"];
822 if (object
.Version
== 2) {
823 version
= BuildVersion(2, CacheV2Minor
);
825 return cache
; // should be unreachable
831 // The "cmakeFiles" object kind.
833 static unsigned int const CMakeFilesV1Minor
= 1;
835 void cmFileAPI::BuildClientRequestCMakeFiles(
836 ClientRequest
& r
, std::vector
<RequestVersion
> const& versions
)
838 // Select a known version from those requested.
839 for (RequestVersion
const& v
: versions
) {
840 if ((v
.Major
== 1 && v
.Minor
<= CMakeFilesV1Minor
)) {
846 r
.Error
= NoSupportedVersion(versions
);
850 Json::Value
cmFileAPI::BuildCMakeFiles(Object
const& object
)
852 Json::Value cmakeFiles
= cmFileAPICMakeFilesDump(*this, object
.Version
);
853 cmakeFiles
["kind"] = this->ObjectKindName(object
.Kind
);
855 Json::Value
& version
= cmakeFiles
["version"];
856 if (object
.Version
== 1) {
857 version
= BuildVersion(1, CMakeFilesV1Minor
);
859 return cmakeFiles
; // should be unreachable
865 // The "toolchains" object kind.
867 static unsigned int const ToolchainsV1Minor
= 0;
869 void cmFileAPI::BuildClientRequestToolchains(
870 ClientRequest
& r
, std::vector
<RequestVersion
> const& versions
)
872 // Select a known version from those requested.
873 for (RequestVersion
const& v
: versions
) {
874 if ((v
.Major
== 1 && v
.Minor
<= ToolchainsV1Minor
)) {
880 r
.Error
= NoSupportedVersion(versions
);
884 Json::Value
cmFileAPI::BuildToolchains(Object
const& object
)
886 Json::Value toolchains
= cmFileAPIToolchainsDump(*this, object
.Version
);
887 toolchains
["kind"] = this->ObjectKindName(object
.Kind
);
889 Json::Value
& version
= toolchains
["version"];
890 if (object
.Version
== 1) {
891 version
= BuildVersion(1, ToolchainsV1Minor
);
893 return toolchains
; // should be unreachable
899 // The "__test" object kind is for internal testing of CMake.
901 static unsigned int const InternalTestV1Minor
= 3;
902 static unsigned int const InternalTestV2Minor
= 0;
904 void cmFileAPI::BuildClientRequestInternalTest(
905 ClientRequest
& r
, std::vector
<RequestVersion
> const& versions
)
907 // Select a known version from those requested.
908 for (RequestVersion
const& v
: versions
) {
909 if ((v
.Major
== 1 && v
.Minor
<= InternalTestV1Minor
) || //
910 (v
.Major
== 2 && v
.Minor
<= InternalTestV2Minor
)) {
916 r
.Error
= NoSupportedVersion(versions
);
920 Json::Value
cmFileAPI::BuildInternalTest(Object
const& object
)
922 Json::Value test
= Json::objectValue
;
923 test
["kind"] = this->ObjectKindName(object
.Kind
);
924 Json::Value
& version
= test
["version"];
925 if (object
.Version
== 2) {
926 version
= BuildVersion(2, InternalTestV2Minor
);
928 version
= BuildVersion(1, InternalTestV1Minor
);
933 Json::Value
cmFileAPI::ReportCapabilities()
935 Json::Value capabilities
= Json::objectValue
;
936 Json::Value
& requests
= capabilities
["requests"] = Json::arrayValue
;
939 Json::Value request
= Json::objectValue
;
940 request
["kind"] = ObjectKindName(ObjectKind::CodeModel
);
941 Json::Value
& versions
= request
["version"] = Json::arrayValue
;
942 versions
.append(BuildVersion(2, CodeModelV2Minor
));
943 requests
.append(std::move(request
)); // NOLINT(*)
947 Json::Value request
= Json::objectValue
;
948 request
["kind"] = ObjectKindName(ObjectKind::ConfigureLog
);
949 Json::Value
& versions
= request
["version"] = Json::arrayValue
;
950 versions
.append(BuildVersion(1, ConfigureLogV1Minor
));
951 requests
.append(std::move(request
)); // NOLINT(*)
955 Json::Value request
= Json::objectValue
;
956 request
["kind"] = ObjectKindName(ObjectKind::Cache
);
957 Json::Value
& versions
= request
["version"] = Json::arrayValue
;
958 versions
.append(BuildVersion(2, CacheV2Minor
));
959 requests
.append(std::move(request
)); // NOLINT(*)
963 Json::Value request
= Json::objectValue
;
964 request
["kind"] = ObjectKindName(ObjectKind::CMakeFiles
);
965 Json::Value
& versions
= request
["version"] = Json::arrayValue
;
966 versions
.append(BuildVersion(1, CMakeFilesV1Minor
));
967 requests
.append(std::move(request
)); // NOLINT(*)
971 Json::Value request
= Json::objectValue
;
972 request
["kind"] = ObjectKindName(ObjectKind::Toolchains
);
973 Json::Value
& versions
= request
["version"] = Json::arrayValue
;
974 versions
.append(BuildVersion(1, ToolchainsV1Minor
));
975 requests
.append(std::move(request
)); // NOLINT(*)
981 bool cmFileAPI::AddProjectQuery(cmFileAPI::ObjectKind kind
,
982 unsigned majorVersion
, unsigned minorVersion
)
985 case ObjectKind::CodeModel
:
986 if (majorVersion
!= 2 || minorVersion
> CodeModelV2Minor
) {
990 case ObjectKind::Cache
:
991 if (majorVersion
!= 2 || minorVersion
> CacheV2Minor
) {
995 case ObjectKind::CMakeFiles
:
996 if (majorVersion
!= 1 || minorVersion
> CMakeFilesV1Minor
) {
1000 case ObjectKind::Toolchains
:
1001 if (majorVersion
!= 1 || minorVersion
> ToolchainsV1Minor
) {
1005 // These cannot be requested by the project
1006 case ObjectKind::ConfigureLog
:
1007 case ObjectKind::InternalTest
:
1013 query
.Version
= majorVersion
;
1014 if (std::find(this->TopQuery
.Known
.begin(), this->TopQuery
.Known
.end(),
1015 query
) == this->TopQuery
.Known
.end()) {
1016 this->TopQuery
.Known
.emplace_back(query
);
1017 this->QueryExists
= true;