فهرست منبع

fileapi: add cache v2

Start with v2 to distinguish it from server-mode v1.

Issue: #18398
Brad King 7 سال پیش
والد
کامیت
7489e95b8e

+ 74 - 0
Help/manual/cmake-file-api.7.rst

@@ -869,3 +869,77 @@ with members:
     with forward slashes.  If the file is inside the top-level source
     directory then the path is specified relative to that directory.
     Otherwise the path is absolute.
+
+Object Kind "cache"
+-------------------
+
+The ``cache`` object kind lists cache entries.  These are the
+:ref:`CMake Language Variables` stored in the persistent cache
+(``CMakeCache.txt``) for the build tree.
+
+There is only one ``cache`` object major version, version 2.
+Version 1 does not exist to avoid confusion with that from
+:manual:`cmake-server(7)` mode.
+
+"cache" version 2
+^^^^^^^^^^^^^^^^^
+
+``cache`` object version 2 is a JSON object:
+
+.. code-block:: json
+
+  {
+    "kind": "cache",
+    "version": { "major": 2, "minor": 0 },
+    "entries": [
+      {
+        "name": "BUILD_SHARED_LIBS",
+        "value": "ON",
+        "type": "BOOL",
+        "properties": [
+          {
+            "name": "HELPSTRING",
+            "value": "Build shared libraries"
+          }
+        ]
+      },
+      {
+        "name": "CMAKE_GENERATOR",
+        "value": "Unix Makefiles",
+        "type": "INTERNAL",
+        "properties": [
+          {
+            "name": "HELPSTRING",
+            "value": "Name of generator."
+          }
+        ]
+      }
+    ]
+  }
+
+The members specific to ``cache`` objects are:
+
+``entries``
+  A JSON array whose entries are each a JSON object specifying a
+  cache entry.  The members of each entry are:
+
+  ``name``
+    A string specifying the name of the entry.
+
+  ``value``
+    A string specifying the value of the entry.
+
+  ``type``
+    A string specifying the type of the entry used by
+    :manual:`cmake-gui(1)` to choose a widget for editing.
+
+  ``properties``
+    A JSON array of entries specifying associated
+    :ref:`cache entry properties <Cache Entry Properties>`.
+    Each entry is a JSON object containing members:
+
+    ``name``
+      A string specifying the name of the cache entry property.
+
+    ``value``
+      A string specifying the value of the cache entry property.

+ 2 - 0
Source/CMakeLists.txt

@@ -209,6 +209,8 @@ set(SRCS
   cmExtraSublimeTextGenerator.h
   cmFileAPI.cxx
   cmFileAPI.h
+  cmFileAPICache.cxx
+  cmFileAPICache.h
   cmFileAPICodemodel.cxx
   cmFileAPICodemodel.h
   cmFileLock.cxx

+ 57 - 0
Source/cmFileAPI.cxx

@@ -4,6 +4,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmCryptoHash.h"
+#include "cmFileAPICache.h"
 #include "cmFileAPICodemodel.h"
 #include "cmGlobalGenerator.h"
 #include "cmSystemTools.h"
@@ -236,6 +237,17 @@ bool cmFileAPI::ReadQuery(std::string const& query,
     objects.push_back(o);
     return true;
   }
+  if (kindName == ObjectKindName(ObjectKind::Cache)) {
+    Object o;
+    o.Kind = ObjectKind::Cache;
+    if (verStr == "v2") {
+      o.Version = 2;
+    } else {
+      return false;
+    }
+    objects.push_back(o);
+    return true;
+  }
   if (kindName == ObjectKindName(ObjectKind::InternalTest)) {
     Object o;
     o.Kind = ObjectKind::InternalTest;
@@ -374,6 +386,7 @@ const char* cmFileAPI::ObjectKindName(ObjectKind kind)
   // Keep in sync with ObjectKind enum.
   static const char* objectKindNames[] = {
     "codemodel", //
+    "cache",     //
     "__test"     //
   };
   return objectKindNames[size_t(kind)];
@@ -395,6 +408,9 @@ Json::Value cmFileAPI::BuildObject(Object const& object)
     case ObjectKind::CodeModel:
       value = this->BuildCodeModel(object);
       break;
+    case ObjectKind::Cache:
+      value = this->BuildCache(object);
+      break;
     case ObjectKind::InternalTest:
       value = this->BuildInternalTest(object);
       break;
@@ -447,6 +463,8 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
 
   if (kindName == this->ObjectKindName(ObjectKind::CodeModel)) {
     r.Kind = ObjectKind::CodeModel;
+  } else if (kindName == this->ObjectKindName(ObjectKind::Cache)) {
+    r.Kind = ObjectKind::Cache;
   } else if (kindName == this->ObjectKindName(ObjectKind::InternalTest)) {
     r.Kind = ObjectKind::InternalTest;
   } else {
@@ -468,6 +486,9 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
     case ObjectKind::CodeModel:
       this->BuildClientRequestCodeModel(r, versions);
       break;
+    case ObjectKind::Cache:
+      this->BuildClientRequestCache(r, versions);
+      break;
     case ObjectKind::InternalTest:
       this->BuildClientRequestInternalTest(r, versions);
       break;
@@ -649,6 +670,42 @@ Json::Value cmFileAPI::BuildCodeModel(Object const& object)
   return codemodel;
 }
 
+// The "cache" object kind.
+
+static unsigned int const CacheV2Minor = 0;
+
+void cmFileAPI::BuildClientRequestCache(
+  ClientRequest& r, std::vector<RequestVersion> const& versions)
+{
+  // Select a known version from those requested.
+  for (RequestVersion const& v : versions) {
+    if ((v.Major == 2 && v.Minor <= CacheV2Minor)) {
+      r.Version = v.Major;
+      break;
+    }
+  }
+  if (!r.Version) {
+    r.Error = NoSupportedVersion(versions);
+  }
+}
+
+Json::Value cmFileAPI::BuildCache(Object const& object)
+{
+  using namespace std::placeholders;
+  Json::Value cache = cmFileAPICacheDump(*this, object.Version);
+  cache["kind"] = this->ObjectKindName(object.Kind);
+
+  Json::Value& version = cache["version"] = Json::objectValue;
+  if (object.Version == 2) {
+    version["major"] = 2;
+    version["minor"] = CacheV2Minor;
+  } else {
+    return cache; // should be unreachable
+  }
+
+  return cache;
+}
+
 // The "__test" object kind is for internal testing of CMake.
 
 static unsigned int const InternalTestV1Minor = 3;

+ 5 - 0
Source/cmFileAPI.h

@@ -52,6 +52,7 @@ private:
   enum class ObjectKind
   {
     CodeModel,
+    Cache,
     InternalTest
   };
 
@@ -186,6 +187,10 @@ private:
     ClientRequest& r, std::vector<RequestVersion> const& versions);
   Json::Value BuildCodeModel(Object const& object);
 
+  void BuildClientRequestCache(ClientRequest& r,
+                               std::vector<RequestVersion> const& versions);
+  Json::Value BuildCache(Object const& object);
+
   void BuildClientRequestInternalTest(
     ClientRequest& r, std::vector<RequestVersion> const& versions);
   Json::Value BuildInternalTest(Object const& object);

+ 105 - 0
Source/cmFileAPICache.cxx

@@ -0,0 +1,105 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmFileAPICache.h"
+
+#include "cmFileAPI.h"
+#include "cmState.h"
+#include "cmake.h"
+
+#include "cm_jsoncpp_value.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+namespace {
+
+class Cache
+{
+  cmFileAPI& FileAPI;
+  unsigned long Version;
+  cmState* State;
+
+  Json::Value DumpEntries();
+  Json::Value DumpEntry(std::string const& name);
+  Json::Value DumpEntryProperties(std::string const& name);
+  Json::Value DumpEntryProperty(std::string const& name,
+                                std::string const& prop);
+
+public:
+  Cache(cmFileAPI& fileAPI, unsigned long version);
+  Json::Value Dump();
+};
+
+Cache::Cache(cmFileAPI& fileAPI, unsigned long version)
+  : FileAPI(fileAPI)
+  , Version(version)
+  , State(this->FileAPI.GetCMakeInstance()->GetState())
+{
+  static_cast<void>(this->Version);
+}
+
+Json::Value Cache::Dump()
+{
+  Json::Value cache = Json::objectValue;
+  cache["entries"] = DumpEntries();
+  return cache;
+}
+
+Json::Value Cache::DumpEntries()
+{
+  Json::Value entries = Json::arrayValue;
+
+  std::vector<std::string> names = this->State->GetCacheEntryKeys();
+  std::sort(names.begin(), names.end());
+
+  for (std::string const& name : names) {
+    entries.append(this->DumpEntry(name));
+  }
+
+  return entries;
+}
+
+Json::Value Cache::DumpEntry(std::string const& name)
+{
+  Json::Value entry = Json::objectValue;
+  entry["name"] = name;
+  entry["type"] =
+    cmState::CacheEntryTypeToString(this->State->GetCacheEntryType(name));
+  entry["value"] = this->State->GetCacheEntryValue(name);
+
+  Json::Value properties = this->DumpEntryProperties(name);
+  if (!properties.empty()) {
+    entry["properties"] = std::move(properties);
+  }
+
+  return entry;
+}
+
+Json::Value Cache::DumpEntryProperties(std::string const& name)
+{
+  Json::Value properties = Json::arrayValue;
+  std::vector<std::string> props =
+    this->State->GetCacheEntryPropertyList(name);
+  std::sort(props.begin(), props.end());
+  for (std::string const& prop : props) {
+    properties.append(this->DumpEntryProperty(name, prop));
+  }
+  return properties;
+}
+
+Json::Value Cache::DumpEntryProperty(std::string const& name,
+                                     std::string const& prop)
+{
+  Json::Value property = Json::objectValue;
+  property["name"] = prop;
+  property["value"] = this->State->GetCacheEntryProperty(name, prop);
+  return property;
+}
+}
+
+Json::Value cmFileAPICacheDump(cmFileAPI& fileAPI, unsigned long version)
+{
+  Cache cache(fileAPI, version);
+  return cache.Dump();
+}

+ 15 - 0
Source/cmFileAPICache.h

@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmFileAPICache_h
+#define cmFileAPICache_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cm_jsoncpp_value.h"
+
+class cmFileAPI;
+
+extern Json::Value cmFileAPICacheDump(cmFileAPI& fileAPI,
+                                      unsigned long version);
+
+#endif

+ 1 - 0
Tests/RunCMake/FileAPI/RunCMakeTest.cmake

@@ -54,3 +54,4 @@ function(run_object object)
 endfunction()
 
 run_object(codemodel-v2)
+run_object(cache-v2)

+ 11 - 0
Tests/RunCMake/FileAPI/cache-v2-ClientStateful-check.cmake

@@ -0,0 +1,11 @@
+set(expect
+  query
+  query/client-foo
+  query/client-foo/query.json
+  reply
+  reply/cache-v2-[0-9a-f]+.json
+  reply/index-[0-9.T-]+.json
+  )
+check_api("^${expect}$")
+
+check_python(cache-v2)

+ 4 - 0
Tests/RunCMake/FileAPI/cache-v2-ClientStateful-prep.cmake

@@ -0,0 +1,4 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/query.json" [[
+{ "requests": [ { "kind": "cache", "version" : 2 } ] }
+]])

+ 11 - 0
Tests/RunCMake/FileAPI/cache-v2-ClientStateless-check.cmake

@@ -0,0 +1,11 @@
+set(expect
+  query
+  query/client-foo
+  query/client-foo/cache-v2
+  reply
+  reply/cache-v2-[0-9a-f]+.json
+  reply/index-[0-9.T-]+.json
+  )
+check_api("^${expect}$")
+
+check_python(cache-v2)

+ 2 - 0
Tests/RunCMake/FileAPI/cache-v2-ClientStateless-prep.cmake

@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/cache-v2" "")

+ 10 - 0
Tests/RunCMake/FileAPI/cache-v2-SharedStateless-check.cmake

@@ -0,0 +1,10 @@
+set(expect
+  query
+  query/cache-v2
+  reply
+  reply/cache-v2-[0-9a-f]+.json
+  reply/index-[0-9.T-]+.json
+  )
+check_api("^${expect}$")
+
+check_python(cache-v2)

+ 2 - 0
Tests/RunCMake/FileAPI/cache-v2-SharedStateless-prep.cmake

@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/cache-v2" "")

+ 15 - 0
Tests/RunCMake/FileAPI/cache-v2-check.py

@@ -0,0 +1,15 @@
+from check_index import *
+
+def check_objects(o):
+    assert is_list(o)
+    assert len(o) == 1
+    check_index_object(o[0], "cache", 2, 0, check_object_cache)
+
+def check_object_cache(o):
+    assert sorted(o.keys()) == ["entries", "kind", "version"]
+    # The "kind" and "version" members are handled by check_index_object.
+    # FIXME: Check "entries" member
+
+assert is_dict(index)
+assert sorted(index.keys()) == ["cmake", "objects", "reply"]
+check_objects(index["objects"])

+ 1 - 0
Tests/RunCMake/FileAPI/cache-v2.cmake

@@ -0,0 +1 @@
+# FIXME: add some specific cache entries to cover in test, with properties