| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #pragma once | |
| #include "cmConfigure.h" // IWYU pragma: keep | |
| #include <functional> | |
| #include <map> | |
| #include <memory> | |
| #include <string> | |
| #include <unordered_set> | |
| #include <vector> | |
| #include <cm3p/json/value.h> | |
| #include <cm3p/json/writer.h> | |
| class cmake; | |
| class cmFileAPI | |
| { | |
| public: | |
| cmFileAPI(cmake* cm); | |
| /** Read fileapi queries from disk. */ | |
| void ReadQueries(); | |
| /** Get the list of configureLog object kind versions requested. */ | |
| std::vector<unsigned int> GetConfigureLogVersions(); | |
| /** Identify the situation in which WriteReplies is called. */ | |
| enum class IndexFor | |
| { | |
| Success, | |
| FailedConfigure, | |
| FailedCompute, | |
| FailedGenerate, | |
| }; | |
| /** Write fileapi replies to disk. */ | |
| void WriteReplies(IndexFor indexFor); | |
| /** Get the "cmake" instance with which this was constructed. */ | |
| cmake* GetCMakeInstance() const { return this->CMakeInstance; } | |
| /** Convert a JSON object or array into an object with a single | |
| "jsonFile" member specifying a file named with the given prefix | |
| and holding the original object. Other JSON types are unchanged. */ | |
| Json::Value MaybeJsonFile(Json::Value in, std::string const& prefix); | |
| /** Report file-api capabilities for cmake -E capabilities. */ | |
| static Json::Value ReportCapabilities(); | |
| // Keep in sync with ObjectKindName. | |
| enum class ObjectKind | |
| { | |
| CodeModel, | |
| ConfigureLog, | |
| Cache, | |
| CMakeFiles, | |
| Toolchains, | |
| InternalTest | |
| }; | |
| bool AddProjectQuery(ObjectKind kind, unsigned majorVersion, | |
| unsigned minorVersion); | |
| /** Build a JSON object with major and minor fields. */ | |
| static Json::Value BuildVersion(unsigned int major, unsigned int minor); | |
| /** Return the subset of 'entries' to delete after a configure: those not | |
| named in 'replyNames' whose identity ('getId') also matches no reply. | |
| Deciding by identity rather than name keeps an entry that aliases a | |
| just-written reply on a case-insensitive filesystem; an entry whose | |
| identity cannot be obtained is retained. Static/templated for tests. */ | |
| template <typename FileIdT> | |
| static std::vector<std::string> FilesToRemove( | |
| std::vector<std::string> const& entries, | |
| std::unordered_set<std::string> const& replyNames, | |
| std::function<bool(std::string const&, FileIdT&)> const& getId) | |
| { | |
| std::vector<FileIdT> keptIds; | |
| for (std::string const& name : replyNames) { | |
| FileIdT id; | |
| if (getId(name, id)) { | |
| keptIds.push_back(id); | |
| } | |
| } | |
| std::vector<std::string> toRemove; | |
| for (std::string const& entry : entries) { | |
| if (replyNames.find(entry) != replyNames.end()) { | |
| continue; | |
| } | |
| FileIdT id; | |
| if (!getId(entry, id)) { | |
| continue; | |
| } | |
| bool aliasesKept = false; | |
| for (FileIdT const& keptId : keptIds) { | |
| if (id == keptId) { | |
| aliasesKept = true; | |
| break; | |
| } | |
| } | |
| if (aliasesKept) { | |
| continue; | |
| } | |
| toRemove.push_back(entry); | |
| } | |
| return toRemove; | |
| } | |
| private: | |
| cmake* CMakeInstance; | |
| /** The api/v1 directory location. */ | |
| std::string APIv1; | |
| /** api/v1 directory in the user's shared CMake config directory. */ | |
| std::string UserAPIv1; | |
| /** The set of files we have just written to the reply directory. */ | |
| std::unordered_set<std::string> ReplyFiles; | |
| static std::vector<std::string> LoadDir(std::string const& dir); | |
| void RemoveOldReplyFiles(); | |
| /** Identify one object kind and major version. */ | |
| struct Object | |
| { | |
| ObjectKind Kind; | |
| unsigned int Version = 0; | |
| friend bool operator<(Object l, Object r) | |
| { | |
| if (l.Kind != r.Kind) { | |
| return l.Kind < r.Kind; | |
| } | |
| return l.Version < r.Version; | |
| } | |
| friend bool operator==(Object l, Object r) | |
| { | |
| return l.Kind == r.Kind && l.Version == r.Version; | |
| } | |
| friend bool operator!=(Object l, Object r) { return !(l == r); } | |
| }; | |
| /** Represent content of a query directory. */ | |
| struct Query | |
| { | |
| /** Known object kind-version pairs. */ | |
| std::vector<Object> Known; | |
| /** Unknown object kind names. */ | |
| std::vector<std::string> Unknown; | |
| }; | |
| /** Represent one request in a client 'query.json'. */ | |
| struct ClientRequest : public Object | |
| { | |
| /** Empty if request is valid, else the error string. */ | |
| std::string Error; | |
| }; | |
| /** Represent the "requests" in a client 'query.json'. */ | |
| struct ClientRequests : public std::vector<ClientRequest> | |
| { | |
| /** Empty if requests field is valid, else the error string. */ | |
| std::string Error; | |
| }; | |
| /** Represent the content of a client query.json file. */ | |
| struct ClientQueryJson | |
| { | |
| /** The error string if parsing failed, else empty. */ | |
| std::string Error; | |
| /** The 'query.json' object "client" member if it exists, else null. */ | |
| Json::Value ClientValue; | |
| /** The 'query.json' object "requests" member if it exists, else null. */ | |
| Json::Value RequestsValue; | |
| /** Requests extracted from 'query.json'. */ | |
| ClientRequests Requests; | |
| }; | |
| /** Represent content of a client query directory. */ | |
| struct ClientQuery | |
| { | |
| /** The content of the client query directory except 'query.json'. */ | |
| Query DirQuery; | |
| /** True if 'query.json' exists. */ | |
| bool HaveQueryJson = false; | |
| /** The 'query.json' content. */ | |
| ClientQueryJson QueryJson; | |
| }; | |
| /** Whether the top-level query directory exists at all. */ | |
| bool QueryExists = false; | |
| /** The content of the top-level query directory. */ | |
| Query TopQuery; | |
| /** The content of each "client-$client" query directory. */ | |
| std::map<std::string, ClientQuery> ClientQueries; | |
| /** Reply index object generated for object kind/version. | |
| This populates the "objects" field of the reply index. */ | |
| std::map<Object, Json::Value> ReplyIndexObjects; | |
| /** Identify the situation in which WriteReplies was called. */ | |
| IndexFor ReplyIndexFor = IndexFor::Success; | |
| std::unique_ptr<Json::StreamWriter> JsonWriter; | |
| bool ReadJsonFile(std::string const& file, Json::Value& value, | |
| std::string& error); | |
| std::string WriteJsonFile( | |
| Json::Value const& value, std::string const& prefix, | |
| std::string (*computeSuffix)(std::string const&) = ComputeSuffixHash); | |
| static std::string ComputeSuffixHash(std::string const&); | |
| static std::string ComputeSuffixTime(std::string const&); | |
| static bool ReadQuery(std::string const& query, | |
| std::vector<Object>& objects); | |
| void ReadClient(std::string const& client); | |
| void ReadClientQuery(std::string const& client, ClientQueryJson& q); | |
| Json::Value BuildReplyIndex(); | |
| Json::Value BuildCMake(); | |
| Json::Value BuildReply(Query const& q); | |
| Json::Value BuildReplyEntry(Object object); | |
| static Json::Value BuildReplyError(std::string const& error); | |
| Json::Value const& AddReplyIndexObject(Object o); | |
| static char const* ObjectKindName(ObjectKind kind); | |
| static std::string ObjectName(Object o); | |
| Json::Value BuildObject(Object object); | |
| ClientRequests BuildClientRequests(Json::Value const& requests); | |
| ClientRequest BuildClientRequest(Json::Value const& request); | |
| Json::Value BuildClientReply(ClientQuery const& q); | |
| Json::Value BuildClientReplyResponses(ClientRequests const& requests); | |
| Json::Value BuildClientReplyResponse(ClientRequest const& request); | |
| struct RequestVersion | |
| { | |
| unsigned int Major = 0; | |
| unsigned int Minor = 0; | |
| }; | |
| static bool ReadRequestVersions(Json::Value const& version, | |
| std::vector<RequestVersion>& versions, | |
| std::string& error); | |
| static bool ReadRequestVersion(Json::Value const& version, bool inArray, | |
| std::vector<RequestVersion>& result, | |
| std::string& error); | |
| static std::string NoSupportedVersion( | |
| std::vector<RequestVersion> const& versions); | |
| void BuildClientRequestCodeModel( | |
| ClientRequest& r, std::vector<RequestVersion> const& versions); | |
| Json::Value BuildCodeModel(Object object); | |
| void BuildClientRequestConfigureLog( | |
| ClientRequest& r, std::vector<RequestVersion> const& versions); | |
| Json::Value BuildConfigureLog(Object object); | |
| void BuildClientRequestCache(ClientRequest& r, | |
| std::vector<RequestVersion> const& versions); | |
| Json::Value BuildCache(Object object); | |
| void BuildClientRequestCMakeFiles( | |
| ClientRequest& r, std::vector<RequestVersion> const& versions); | |
| Json::Value BuildCMakeFiles(Object object); | |
| void BuildClientRequestToolchains( | |
| ClientRequest& r, std::vector<RequestVersion> const& versions); | |
| Json::Value BuildToolchains(Object object); | |
| void BuildClientRequestInternalTest( | |
| ClientRequest& r, std::vector<RequestVersion> const& versions); | |
| Json::Value BuildInternalTest(Object object); | |
| }; |