couchbase 4.4.3 → 4.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. package/BUILDING.md +182 -0
  2. package/CMakeLists.txt +11 -0
  3. package/CONTRIBUTING.md +1 -1
  4. package/README.md +4 -2
  5. package/deps/couchbase-cxx-cache/boringssl/e31ea00c1ea52052d2d78d44006cc88c80fa24a9/boringssl/src/BUILDING.md +206 -0
  6. package/deps/couchbase-cxx-client/CMakeLists.txt +3 -1
  7. package/deps/couchbase-cxx-client/README.md +2 -2
  8. package/deps/couchbase-cxx-client/cmake/APKBUILD.in +54 -0
  9. package/deps/couchbase-cxx-client/cmake/CompilerWarnings.cmake +0 -5
  10. package/deps/couchbase-cxx-client/cmake/Packaging.cmake +174 -11
  11. package/deps/couchbase-cxx-client/cmake/RPath.cmake +10 -0
  12. package/deps/couchbase-cxx-client/cmake/VersionInfo.cmake +4 -0
  13. package/deps/couchbase-cxx-client/cmake/build_version.hxx.in +1 -0
  14. package/deps/couchbase-cxx-client/cmake/couchbase-cxx-client.spec.in +2 -2
  15. package/deps/couchbase-cxx-client/cmake/couchbase_cxx_client.pc.in +2 -2
  16. package/deps/couchbase-cxx-client/cmake/debian/changelog.in +5 -0
  17. package/deps/couchbase-cxx-client/cmake/debian/compat +1 -0
  18. package/deps/couchbase-cxx-client/cmake/debian/control +40 -0
  19. package/deps/couchbase-cxx-client/cmake/debian/rules +41 -0
  20. package/deps/couchbase-cxx-client/cmake/debian/source/format +1 -0
  21. package/deps/couchbase-cxx-client/core/impl/analytics.cxx +1 -0
  22. package/deps/couchbase-cxx-client/core/impl/collection.cxx +27 -3
  23. package/deps/couchbase-cxx-client/core/impl/error.cxx +24 -3
  24. package/deps/couchbase-cxx-client/core/impl/get_replica.hxx +2 -0
  25. package/deps/couchbase-cxx-client/core/impl/lookup_in_replica.hxx +2 -0
  26. package/deps/couchbase-cxx-client/core/impl/observe_seqno.hxx +2 -0
  27. package/deps/couchbase-cxx-client/core/impl/query.cxx +1 -0
  28. package/deps/couchbase-cxx-client/core/impl/search.cxx +2 -0
  29. package/deps/couchbase-cxx-client/core/io/http_command.hxx +2 -2
  30. package/deps/couchbase-cxx-client/core/io/mcbp_command.hxx +1 -1
  31. package/deps/couchbase-cxx-client/core/meta/features.hxx +11 -0
  32. package/deps/couchbase-cxx-client/core/meta/version.cxx +47 -6
  33. package/deps/couchbase-cxx-client/core/operations/document_analytics.cxx +23 -17
  34. package/deps/couchbase-cxx-client/core/operations/document_analytics.hxx +1 -0
  35. package/deps/couchbase-cxx-client/core/operations/document_append.hxx +2 -0
  36. package/deps/couchbase-cxx-client/core/operations/document_decrement.hxx +2 -0
  37. package/deps/couchbase-cxx-client/core/operations/document_exists.hxx +2 -0
  38. package/deps/couchbase-cxx-client/core/operations/document_get.hxx +2 -0
  39. package/deps/couchbase-cxx-client/core/operations/document_get_all_replicas.hxx +2 -0
  40. package/deps/couchbase-cxx-client/core/operations/document_get_and_lock.hxx +2 -0
  41. package/deps/couchbase-cxx-client/core/operations/document_get_and_touch.hxx +2 -0
  42. package/deps/couchbase-cxx-client/core/operations/document_get_any_replica.hxx +2 -0
  43. package/deps/couchbase-cxx-client/core/operations/document_get_projected.hxx +2 -0
  44. package/deps/couchbase-cxx-client/core/operations/document_increment.hxx +2 -0
  45. package/deps/couchbase-cxx-client/core/operations/document_insert.hxx +2 -0
  46. package/deps/couchbase-cxx-client/core/operations/document_lookup_in.hxx +2 -0
  47. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_all_replicas.hxx +2 -0
  48. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_any_replica.hxx +2 -0
  49. package/deps/couchbase-cxx-client/core/operations/document_mutate_in.hxx +2 -0
  50. package/deps/couchbase-cxx-client/core/operations/document_prepend.hxx +2 -0
  51. package/deps/couchbase-cxx-client/core/operations/document_query.hxx +1 -0
  52. package/deps/couchbase-cxx-client/core/operations/document_remove.hxx +2 -0
  53. package/deps/couchbase-cxx-client/core/operations/document_replace.hxx +2 -0
  54. package/deps/couchbase-cxx-client/core/operations/document_search.hxx +1 -0
  55. package/deps/couchbase-cxx-client/core/operations/document_touch.hxx +2 -0
  56. package/deps/couchbase-cxx-client/core/operations/document_unlock.hxx +2 -0
  57. package/deps/couchbase-cxx-client/core/operations/document_upsert.hxx +2 -0
  58. package/deps/couchbase-cxx-client/core/operations/document_view.hxx +1 -0
  59. package/deps/couchbase-cxx-client/core/operations/http_noop.hxx +2 -0
  60. package/deps/couchbase-cxx-client/core/operations/management/analytics_dataset_create.hxx +1 -0
  61. package/deps/couchbase-cxx-client/core/operations/management/analytics_dataset_drop.hxx +1 -0
  62. package/deps/couchbase-cxx-client/core/operations/management/analytics_dataset_get_all.hxx +1 -0
  63. package/deps/couchbase-cxx-client/core/operations/management/analytics_dataverse_create.hxx +1 -0
  64. package/deps/couchbase-cxx-client/core/operations/management/analytics_dataverse_drop.hxx +1 -0
  65. package/deps/couchbase-cxx-client/core/operations/management/analytics_get_pending_mutations.hxx +2 -0
  66. package/deps/couchbase-cxx-client/core/operations/management/analytics_index_create.hxx +1 -0
  67. package/deps/couchbase-cxx-client/core/operations/management/analytics_index_drop.hxx +1 -0
  68. package/deps/couchbase-cxx-client/core/operations/management/analytics_index_get_all.hxx +1 -0
  69. package/deps/couchbase-cxx-client/core/operations/management/analytics_link_connect.hxx +1 -0
  70. package/deps/couchbase-cxx-client/core/operations/management/analytics_link_create.hxx +1 -0
  71. package/deps/couchbase-cxx-client/core/operations/management/analytics_link_disconnect.hxx +1 -0
  72. package/deps/couchbase-cxx-client/core/operations/management/analytics_link_drop.hxx +1 -0
  73. package/deps/couchbase-cxx-client/core/operations/management/analytics_link_get_all.cxx +23 -15
  74. package/deps/couchbase-cxx-client/core/operations/management/analytics_link_get_all.hxx +4 -3
  75. package/deps/couchbase-cxx-client/core/operations/management/analytics_link_replace.hxx +1 -0
  76. package/deps/couchbase-cxx-client/core/operations/management/bucket_create.hxx +1 -0
  77. package/deps/couchbase-cxx-client/core/operations/management/bucket_describe.hxx +1 -0
  78. package/deps/couchbase-cxx-client/core/operations/management/bucket_drop.hxx +1 -0
  79. package/deps/couchbase-cxx-client/core/operations/management/bucket_flush.hxx +1 -0
  80. package/deps/couchbase-cxx-client/core/operations/management/bucket_get.hxx +1 -0
  81. package/deps/couchbase-cxx-client/core/operations/management/bucket_get_all.hxx +1 -0
  82. package/deps/couchbase-cxx-client/core/operations/management/bucket_update.hxx +1 -0
  83. package/deps/couchbase-cxx-client/core/operations/management/change_password.hxx +1 -0
  84. package/deps/couchbase-cxx-client/core/operations/management/cluster_describe.hxx +1 -0
  85. package/deps/couchbase-cxx-client/core/operations/management/cluster_developer_preview_enable.hxx +1 -0
  86. package/deps/couchbase-cxx-client/core/operations/management/collection_create.hxx +2 -0
  87. package/deps/couchbase-cxx-client/core/operations/management/collection_drop.hxx +1 -0
  88. package/deps/couchbase-cxx-client/core/operations/management/collection_update.hxx +2 -0
  89. package/deps/couchbase-cxx-client/core/operations/management/collections_manifest_get.hxx +2 -0
  90. package/deps/couchbase-cxx-client/core/operations/management/eventing_deploy_function.hxx +3 -2
  91. package/deps/couchbase-cxx-client/core/operations/management/eventing_drop_function.hxx +3 -2
  92. package/deps/couchbase-cxx-client/core/operations/management/eventing_get_all_functions.hxx +3 -2
  93. package/deps/couchbase-cxx-client/core/operations/management/eventing_get_function.hxx +3 -2
  94. package/deps/couchbase-cxx-client/core/operations/management/eventing_get_status.hxx +3 -2
  95. package/deps/couchbase-cxx-client/core/operations/management/eventing_pause_function.hxx +3 -2
  96. package/deps/couchbase-cxx-client/core/operations/management/eventing_resume_function.hxx +3 -2
  97. package/deps/couchbase-cxx-client/core/operations/management/eventing_undeploy_function.hxx +3 -2
  98. package/deps/couchbase-cxx-client/core/operations/management/eventing_upsert_function.hxx +3 -2
  99. package/deps/couchbase-cxx-client/core/operations/management/freeform.hxx +2 -0
  100. package/deps/couchbase-cxx-client/core/operations/management/group_drop.hxx +1 -0
  101. package/deps/couchbase-cxx-client/core/operations/management/group_get.hxx +1 -0
  102. package/deps/couchbase-cxx-client/core/operations/management/group_get_all.hxx +1 -0
  103. package/deps/couchbase-cxx-client/core/operations/management/group_upsert.hxx +1 -0
  104. package/deps/couchbase-cxx-client/core/operations/management/query_index_build.hxx +2 -0
  105. package/deps/couchbase-cxx-client/core/operations/management/query_index_build_deferred.hxx +3 -0
  106. package/deps/couchbase-cxx-client/core/operations/management/query_index_create.hxx +1 -0
  107. package/deps/couchbase-cxx-client/core/operations/management/query_index_drop.hxx +1 -0
  108. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all.hxx +2 -0
  109. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all_deferred.hxx +3 -0
  110. package/deps/couchbase-cxx-client/core/operations/management/role_get_all.hxx +1 -0
  111. package/deps/couchbase-cxx-client/core/operations/management/scope_create.hxx +1 -0
  112. package/deps/couchbase-cxx-client/core/operations/management/scope_drop.hxx +1 -0
  113. package/deps/couchbase-cxx-client/core/operations/management/scope_get_all.hxx +1 -0
  114. package/deps/couchbase-cxx-client/core/operations/management/search_get_stats.hxx +1 -0
  115. package/deps/couchbase-cxx-client/core/operations/management/search_index_analyze_document.hxx +1 -0
  116. package/deps/couchbase-cxx-client/core/operations/management/search_index_control_ingest.hxx +1 -0
  117. package/deps/couchbase-cxx-client/core/operations/management/search_index_control_plan_freeze.hxx +1 -0
  118. package/deps/couchbase-cxx-client/core/operations/management/search_index_control_query.hxx +1 -0
  119. package/deps/couchbase-cxx-client/core/operations/management/search_index_drop.hxx +1 -0
  120. package/deps/couchbase-cxx-client/core/operations/management/search_index_get.hxx +1 -0
  121. package/deps/couchbase-cxx-client/core/operations/management/search_index_get_all.hxx +1 -0
  122. package/deps/couchbase-cxx-client/core/operations/management/search_index_get_documents_count.hxx +2 -0
  123. package/deps/couchbase-cxx-client/core/operations/management/search_index_get_stats.hxx +1 -0
  124. package/deps/couchbase-cxx-client/core/operations/management/search_index_upsert.hxx +1 -0
  125. package/deps/couchbase-cxx-client/core/operations/management/user_drop.hxx +1 -0
  126. package/deps/couchbase-cxx-client/core/operations/management/user_get.hxx +1 -0
  127. package/deps/couchbase-cxx-client/core/operations/management/user_get_all.hxx +1 -0
  128. package/deps/couchbase-cxx-client/core/operations/management/user_upsert.cxx +3 -3
  129. package/deps/couchbase-cxx-client/core/operations/management/user_upsert.hxx +1 -0
  130. package/deps/couchbase-cxx-client/core/operations/management/view_index_drop.hxx +1 -0
  131. package/deps/couchbase-cxx-client/core/operations/management/view_index_get.hxx +1 -0
  132. package/deps/couchbase-cxx-client/core/operations/management/view_index_get_all.hxx +2 -0
  133. package/deps/couchbase-cxx-client/core/operations/management/view_index_upsert.hxx +1 -0
  134. package/deps/couchbase-cxx-client/core/transactions/async_attempt_context.hxx +9 -21
  135. package/deps/couchbase-cxx-client/core/transactions/attempt_context.hxx +6 -33
  136. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.cxx +41 -41
  137. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.hxx +15 -16
  138. package/deps/couchbase-cxx-client/core/transactions/transaction_context.cxx +2 -2
  139. package/deps/couchbase-cxx-client/core/transactions/transaction_get_result.hxx +0 -20
  140. package/deps/couchbase-cxx-client/couchbase/common_options.hxx +16 -1
  141. package/deps/couchbase-cxx-client/couchbase/metrics/otel_meter.hxx +16 -20
  142. package/dist/analyticsindexmanager.d.ts +98 -14
  143. package/dist/analyticsindexmanager.js +452 -411
  144. package/dist/binding.d.ts +53 -4
  145. package/dist/bindingutilities.d.ts +26 -1
  146. package/dist/bindingutilities.js +108 -1
  147. package/dist/couchbase.d.ts +3 -1
  148. package/dist/couchbase.js +2 -0
  149. package/dist/rangeScan.d.ts +1 -1
  150. package/dist/rangeScan.js +1 -1
  151. package/dist/transactions.d.ts +34 -3
  152. package/dist/transactions.js +25 -18
  153. package/dist/transcoders.d.ts +68 -0
  154. package/dist/transcoders.js +194 -1
  155. package/dist/usermanager.d.ts +14 -14
  156. package/dist/usermanager.js +178 -228
  157. package/dist/utilities.js +4 -6
  158. package/dist/utilities_internal.js +1 -2
  159. package/package.json +9 -8
  160. package/src/connection.cpp +22 -0
  161. package/src/connection.hpp +12 -0
  162. package/src/connection_autogen.cpp +100 -0
  163. package/src/jstocbpp_autogen.hpp +315 -8
  164. package/src/jstocbpp_transactions.hpp +1 -2
  165. package/tools/gen-bindings-js.js +38 -3
  166. package/tools/gen-bindings-json.py +575 -328
@@ -1,21 +1,36 @@
1
- import os
1
+ # Copyright 2016-2024. Couchbase, Inc.
2
+ # All Rights Reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
2
16
  import json
17
+ import os
18
+ import pathlib
3
19
  import re
4
- import clang.cindex
20
+ import subprocess
21
+ import sys
5
22
 
6
23
  from functools import reduce
24
+ from typing import (Dict, List, Optional, Tuple)
25
+
26
+ import clang.cindex
7
27
 
8
- # configurable part
28
+ # START CONFIGURATION
9
29
 
10
- CLANG_VERSION='13.0.1'
11
- # homebrew installs for llvm (brew info llvm gives details):
12
- # x64: /usr/local/opt/llvm/lib
13
- # arm64: /opt/homebrew/opt/llvm/lib
14
- llvmLibPath = "/usr/local/Cellar/llvm/13.0.1_1/lib/"
30
+ CXX_CLIENT_ROOT = os.path.join(pathlib.Path(__file__).parent.parent, 'deps', 'couchbase-cxx-client')
31
+ CXX_CLIENT_CACHE = os.path.join(pathlib.Path(__file__).parent.parent, 'deps', 'couchbase-cxx-cache')
15
32
 
16
- cxx_client_root = "../deps/couchbase-cxx-client"
17
- cxx_client_cache = "../deps/couchbase-cxx-cache"
18
- cxx_deps_include_paths = {
33
+ CXX_DEPS_INCLUDE_PATHS = {
19
34
  'asio': ['-I{0}/asio/{1}/asio/asio/include'],
20
35
  'fmt': ['-I{0}/fmt/{1}/fmt/include'],
21
36
  'gsl': ['-I{0}/gsl/{1}/gsl/include'],
@@ -25,7 +40,7 @@ cxx_deps_include_paths = {
25
40
  'spdlog': ['-I{0}/spdlog/{1}/spdlog/include'],
26
41
  }
27
42
 
28
- fileList = [
43
+ FILE_LIST = [
29
44
  "core/management/analytics_dataset.hxx",
30
45
  "core/management/analytics_index.hxx",
31
46
  "core/management/analytics_link_azure_blob_external.hxx",
@@ -76,7 +91,7 @@ fileList = [
76
91
  "core/vector_query_combination.hxx",
77
92
  ]
78
93
 
79
- typeList = [
94
+ TYPE_LIST = [
80
95
  "couchbase::core::management::analytics::dataset",
81
96
  "couchbase::core::management::analytics::index",
82
97
  "couchbase::core::management::analytics::azure_blob_external_link",
@@ -171,331 +186,563 @@ typeList = [
171
186
  "couchbase::read_preference"
172
187
  ]
173
188
 
174
- # end of configurable part
175
-
176
- clang.cindex.Config.set_library_path(llvmLibPath)
177
-
178
- def set_cxx_deps_include_paths(dep, includes):
179
- cpm_path = os.path.join(cxx_client_cache, dep)
180
- dir_pattern = r'[0-9a-z]{40}'
181
- cpm_hash_dir = next((d for d in os.listdir(cpm_path)
182
- if os.path.isdir(os.path.join(cpm_path, d)) and re.match(dir_pattern, d)),
183
- None)
184
- if not cpm_hash_dir:
185
- raise Exception(f'Unable to find CPM hash directory for path: {cpm_path}.')
186
- return list(map(lambda p: p.format(cxx_client_cache, cpm_hash_dir), includes))
187
-
188
- def list_headers_in_dir(path):
189
- # enumerates a folder but keeps the full pathing for the files returned
190
- # and removes certain files we don't want (like non-hxx, _json.hxx or _fmt.hxx)
191
-
192
- # list all the files in the folder
193
- files = os.listdir(path)
194
- # only include .hxx files
195
- files = list(filter(lambda x: x.endswith('.hxx'), files))
196
- # add the folder path back on
197
- files = list(map(lambda x: path + x, files))
198
- return files
199
-
200
-
201
- # parse through the list of files specified and expand wildcards
202
- fullFileList = []
203
- for filePath in fileList:
204
- if "*" in filePath:
205
- # wildcard path
206
- basePath = filePath[:-1]
207
- if "*" in basePath:
208
- # if there is still a wildcard, we have an issue...
209
- raise NotImplementedError(
210
- "wildcard only supported at end of file path")
211
- files = list_headers_in_dir(os.path.join(cxx_client_root, basePath))
212
- fullFileList = fullFileList + files
213
- else:
214
- # normal path
215
- fullFileList.append(os.path.join(cxx_client_root, filePath))
216
-
217
- # exclude _json.hxx files
218
- fullFileList = list(
219
- filter(lambda x: not x.endswith('_json.hxx'), fullFileList))
220
- # exclude _fmt.hxx files
221
- fullFileList = list(
222
- filter(lambda x: not x.endswith('_fmt.hxx'), fullFileList))
223
-
224
-
225
- # generate a list of regexps from the type list (for handling wildcards)
226
- typeListRe = list(map(lambda x: x.replace("*", "(.*)") + "(.*)", typeList))
227
-
228
-
229
- def is_included_type(name, with_durability=False):
230
-
231
- # TODO(brett19): This should be generalized somehow...
232
- if "is_compound_operation" in name:
233
- return False
234
-
235
- if "replica_context" in name:
236
- return False
237
-
238
- if with_durability is True and '_with_legacy_durability' not in name:
239
- return False
240
-
241
- for x in typeListRe:
242
- if re.fullmatch(x, name):
243
- return True
244
- return False
245
-
189
+ STD_COMPARATOR_TEMPLATES = ["std::less<{0}>", "std::greater<{0}>", "std::less_equal<{0}>", "std::greater_equal<{0}>"]
190
+ # flatten the list of lists
191
+ STD_COMPARATORS = list(reduce(lambda a, b: a + b,
192
+ list(map(lambda c: [c.format(s) for s in ['', 'void']], STD_COMPARATOR_TEMPLATES)),
193
+ []))
246
194
 
247
- opTypes = []
248
- opEnums = []
195
+ INTERNAL_STRUCTS = []
196
+ UNNAMED_STRUCT_DELIM = '::(unnamed struct'
249
197
 
198
+ # IMPORTANT: the templates must exist in the TYPE_LIST
199
+ TEMPLATED_REQUESTS = {
200
+ 'analytics_link_create_request': {
201
+ 'template_name': 'analytics_link_type',
202
+ 'templates': ['couchbase::core::management::analytics::azure_blob_external_link',
203
+ 'couchbase::core::management::analytics::couchbase_remote_link',
204
+ 'couchbase::core::management::analytics::s3_external_link']
205
+ },
206
+ 'analytics_link_replace_request': {
207
+ 'template_name': 'analytics_link_type',
208
+ 'templates': ['couchbase::core::management::analytics::azure_blob_external_link',
209
+ 'couchbase::core::management::analytics::couchbase_remote_link',
210
+ 'couchbase::core::management::analytics::s3_external_link']
211
+ },
212
+ }
250
213
 
251
- def parse_type(type):
252
- typeStr = type.get_canonical().spelling
253
- return parse_type_str(typeStr)
214
+ # END - CONFIGURATION
215
+
216
+
217
+ class BindingsGenerator:
218
+
219
+ def __init__(self,
220
+ llvm_clang_version: Optional[str] = None,
221
+ llvm_libdir: Optional[str] = None,
222
+ llvm_includedir: Optional[str] = None,
223
+ system_headers: Optional[str] = None,
224
+ verbose: Optional[bool] = False) -> None:
225
+ self._op_types = []
226
+ self._op_enums = []
227
+ self._full_file_list = []
228
+ # generate a list of regexps from the type list (for handling wildcards)
229
+ self._type_list_re = list(map(lambda x: x.replace("*", "(.*)") + "(.*)", TYPE_LIST))
230
+ self._verbose = verbose
231
+ self.configure_generator(llvm_clang_version, llvm_libdir, llvm_includedir, system_headers)
232
+
233
+ def configure_generator(self,
234
+ version: Optional[str] = None,
235
+ libdir: Optional[str] = None,
236
+ includedir: Optional[str] = None,
237
+ system_headers: Optional[str] = None) -> None:
238
+ if version is None:
239
+ version = os.environ.get('CN_LLVM_VERSION')
240
+ if version is None:
241
+ BindingsGenerator.find_llvm()
242
+ version = BindingsGenerator.get_llvm_version()
243
+ if version is None:
244
+ raise ValueError('Missing LLVM version.')
245
+
246
+ if includedir is None:
247
+ includedir = os.environ.get('CN_LLVM_INCLUDE')
248
+ if includedir is None:
249
+ includedir = BindingsGenerator.get_llvm_includedir()
250
+ if includedir is None:
251
+ raise ValueError('Missing LLVM include directory.')
252
+
253
+ if libdir is None:
254
+ libdir = os.environ.get('CN_LLVM_LIB')
255
+ if libdir is None:
256
+ libdir = BindingsGenerator.get_llvm_libdir()
257
+ if libdir is None:
258
+ raise ValueError('Missing LLVM lib directory.')
259
+
260
+ if system_headers is None:
261
+ system_headers = os.environ.get('CN_SYS_HEADERS')
262
+ if system_headers is None:
263
+ system_headers = BindingsGenerator.get_system_headers()
264
+ if system_headers is None:
265
+ raise ValueError('Missing system headers path.')
266
+
267
+ if self._verbose:
268
+ print(f'Using libdir={libdir}')
269
+ clang.cindex.Config.set_library_path(libdir)
270
+
271
+ self._include_paths = [
272
+ '-I/opt/homebrew/opt/llvm/include/c++/v1',
273
+ f'-I{CXX_CLIENT_ROOT}/',
274
+ f'-I/opt/homebrew/Cellar/llvm/{version}/lib/clang/{version[:2]}/include',
275
+ f'-I{system_headers}/usr/include'
276
+ ]
277
+
278
+ for dep, inc in CXX_DEPS_INCLUDE_PATHS.items():
279
+ self._include_paths.extend(BindingsGenerator.set_cxx_deps_include_paths(dep, inc))
280
+
281
+ if self._verbose:
282
+ print(f'Include paths={self._include_paths}')
283
+
284
+ self.set_file_list()
285
+
286
+ def gen_bindings(self) -> None:
287
+
288
+ for headerPath in self._full_file_list:
289
+ print("processing " + headerPath)
290
+ index = clang.cindex.Index.create()
291
+ if self._verbose is True:
292
+ args = ['-std=c++17', '-v', f'-isysroot{os.getcwd()}'] + self._include_paths
293
+ else:
294
+ args = ['-std=c++17', f'-isysroot{os.getcwd()}'] + self._include_paths
295
+ translation_unit = index.parse(headerPath, args=args)
296
+
297
+ # output clang compiler diagnostics information (for debugging)
298
+ if 1:
299
+ for diagnostic in translation_unit.diagnostics:
300
+ diagnosticMsg = diagnostic.format()
301
+ print(diagnostic)
302
+
303
+ self.traverse(translation_unit.cursor, [], headerPath)
304
+
305
+ jsonData = json.dumps({
306
+ 'op_structs': self._op_types,
307
+ 'op_enums': self._op_enums
308
+ })
309
+
310
+ f = open("bindings.json", "w")
311
+ f.write(jsonData)
312
+ f.close()
313
+
314
+ def set_file_list(self) -> None:
315
+ for file_path in FILE_LIST:
316
+ if "*" in file_path:
317
+ # wildcard path
318
+ basePath = file_path[:-1]
319
+ if "*" in basePath:
320
+ # if there is still a wildcard, we have an issue...
321
+ raise NotImplementedError(
322
+ "wildcard only supported at end of file path")
323
+ if basePath[-1] != os.path.sep:
324
+ tokens = basePath.split(os.path.sep)
325
+ # filter = tokens[-1]
326
+ files = BindingsGenerator.list_headers_in_dir(os.path.join(CXX_CLIENT_ROOT, *tokens[:-1]),
327
+ tokens[-1])
328
+ else:
329
+ files = BindingsGenerator.list_headers_in_dir(os.path.join(CXX_CLIENT_ROOT, basePath))
330
+ self._full_file_list = self._full_file_list + files
331
+ else:
332
+ # normal path
333
+ self._full_file_list.append(os.path.join(CXX_CLIENT_ROOT, file_path))
334
+
335
+ # exclude _json.hxx files
336
+ self._full_file_list = list(filter(lambda x: not x.endswith('_json.hxx'), self._full_file_list))
337
+ # exclude _fmt.hxx files
338
+ self._full_file_list = list(filter(lambda x: not x.endswith('_fmt.hxx'), self._full_file_list))
339
+
340
+ def traverse(self, node, namespace, main_file) -> None:
341
+ # only scan the elements of the file we parsed
342
+ if node.location.file is not None and node.location.file.name != main_file:
343
+ return
344
+
345
+ if node.kind == clang.cindex.CursorKind.STRUCT_DECL or node.kind == clang.cindex.CursorKind.CLASS_DECL:
346
+ full_struct_name = "::".join([*namespace, node.displayname])
347
+ if full_struct_name.endswith('::') or UNNAMED_STRUCT_DELIM in full_struct_name:
348
+ if full_struct_name.endswith('::'):
349
+ struct_name = full_struct_name
350
+ else:
351
+ struct_name = full_struct_name.split(UNNAMED_STRUCT_DELIM)[0]
352
+ match = next((s for s in INTERNAL_STRUCTS if struct_name in s), None)
353
+ if match:
354
+ full_struct_name = match
355
+
356
+ if (BindingsGenerator.is_included_type(full_struct_name, self._type_list_re)
357
+ or full_struct_name in INTERNAL_STRUCTS):
358
+ struct_fields = []
359
+ parents = []
360
+ for child in node.get_children():
361
+ if child.kind == clang.cindex.CursorKind.FIELD_DECL:
362
+ struct_type = BindingsGenerator.parse_type(child.type)
363
+ type_str = child.type.get_canonical().spelling
364
+ if 'unnamed' in type_str:
365
+ name_tokens = type_str.split('::')
366
+ name_override = '::'.join(name_tokens[:-1] + [child.displayname])
367
+ struct_type['name'] = name_override
368
+ INTERNAL_STRUCTS.append(name_override)
369
+
370
+ struct_fields.append({
371
+ "name": child.displayname,
372
+ "type": struct_type,
373
+ })
374
+ elif child.kind == clang.cindex.CursorKind.CXX_BASE_SPECIFIER:
375
+ parents.append("::".join([*namespace, child.displayname]))
376
+
377
+ if len(parents) > 0:
378
+ part_op_types = [ot for ot in self._op_types if ot['name'] in parents]
379
+ print(f'{part_op_types=}')
380
+ for sot in part_op_types:
381
+ struct_fields.extend(sot['fields'])
382
+
383
+ # replica read changes introduced duplicate get requests
384
+ if any(map(lambda op: op['name'] == full_struct_name, self._op_types)):
385
+ return
386
+
387
+ self._op_types.append({
388
+ "name": full_struct_name,
389
+ "fields": struct_fields,
390
+ })
391
+ if node.kind == clang.cindex.CursorKind.TYPE_ALIAS_DECL:
392
+ full_struct_name = "::".join([*namespace, node.displayname])
393
+ if BindingsGenerator.is_included_type(full_struct_name, self._type_list_re, with_durability=True):
394
+ type_ref = next((c for c in node.get_children() if c.kind == clang.cindex.CursorKind.TYPE_REF), None)
395
+ if type_ref:
396
+ base_request_name = type_ref.displayname.replace('struct', '').strip()
397
+ base_request = next((op for op in self._op_types if op['name'] == base_request_name), None)
398
+ if base_request:
399
+ new_fields = [f for f in base_request['fields'] if f['name'] != 'durability_level']
400
+ new_fields.extend([
401
+ {"name": "persist_to", "type": {"name": "couchbase::persist_to"}},
402
+ {"name": "replicate_to", "type": {"name": "couchbase::replicate_to"}}
403
+ ])
254
404
 
255
- std_comparator_templates = ["std::less<{0}>", "std::greater<{0}>", "std::less_equal<{0}>", "std::greater_equal<{0}>"]
256
- # flatten the list of lists
257
- std_comparators = list(reduce(lambda a, b: a + b,
258
- list(map(lambda c: [c.format(s) for s in ['', 'void']], std_comparator_templates)),
259
- []))
405
+ self._op_types.append({
406
+ "name": full_struct_name,
407
+ "fields": new_fields
408
+ })
409
+ if node.kind == clang.cindex.CursorKind.ENUM_DECL:
410
+ full_enum_name = "::".join([*namespace, node.displayname])
411
+ if BindingsGenerator.is_included_type(full_enum_name, self._type_list_re):
412
+ enumValues = []
413
+
414
+ for child in node.get_children():
415
+ if child.kind == clang.cindex.CursorKind.ENUM_CONSTANT_DECL:
416
+ enumValues.append({
417
+ "name": child.displayname,
418
+ "value": child.enum_value,
419
+ })
420
+ self._op_enums.append({
421
+ "name": full_enum_name,
422
+ "type": BindingsGenerator.parse_type(node.enum_type),
423
+ "values": enumValues,
424
+ })
425
+
426
+ if node.kind == clang.cindex.CursorKind.NAMESPACE:
427
+ namespace = [*namespace, node.displayname]
428
+ if node.kind == clang.cindex.CursorKind.CLASS_DECL:
429
+ namespace = [*namespace, node.displayname]
430
+ if node.kind == clang.cindex.CursorKind.STRUCT_DECL:
431
+ namespace = [*namespace, node.displayname]
432
+ if node.kind == clang.cindex.CursorKind.CLASS_TEMPLATE:
433
+ name_tokens = node.displayname.split('<')
434
+ if len(name_tokens) == 2 and name_tokens[0] in TEMPLATED_REQUESTS:
435
+ req = TEMPLATED_REQUESTS.get(name_tokens[0])
436
+ full_struct_name = "::".join([*namespace, node.displayname])
437
+ for template in req['templates']:
438
+ struct_fields = []
439
+ for child in node.get_children():
440
+ if child.kind == clang.cindex.CursorKind.FIELD_DECL:
441
+ type_str = child.type.get_canonical().spelling
442
+ if 'type-parameter' in type_str:
443
+ struct_type = {
444
+ 'name': 'template',
445
+ 'of': {'name': template}}
446
+ else:
447
+ struct_type = BindingsGenerator.parse_type(child.type)
448
+ # print(f'struct_type={child.type}; type.kind={child.type.kind}; {type_str=}, displayname={child.displayname}')
449
+ struct_fields.append({
450
+ "name": child.displayname,
451
+ "type": struct_type,
452
+ })
453
+ self._op_types.append({
454
+ "name": full_struct_name.replace(req['template_name'], template),
455
+ "fields": struct_fields,
456
+ })
457
+ # return
458
+
459
+ for child in node.get_children():
460
+ self.traverse(child, namespace, main_file)
461
+
462
+ @staticmethod
463
+ def set_cxx_deps_include_paths(dep, includes):
464
+ cpm_path = os.path.join(CXX_CLIENT_CACHE, dep)
465
+ dir_pattern = r'[0-9a-z]{40}'
466
+ cpm_hash_dir = next((d for d in os.listdir(cpm_path)
467
+ if os.path.isdir(os.path.join(cpm_path, d)) and re.match(dir_pattern, d)),
468
+ None)
469
+ if not cpm_hash_dir:
470
+ raise Exception(f'Unable to find CPM hash directory for path: {cpm_path}.')
471
+ return list(map(lambda p: p.format(CXX_CLIENT_CACHE, cpm_hash_dir), includes))
472
+
473
+ @staticmethod
474
+ def list_headers_in_dir(path: str, file_startswith: Optional[str] = None) -> List[str]:
475
+ # enumerates a folder but keeps the full pathing for the files returned
476
+ # and removes certain files we don't want (like non-hxx, _json.hxx or _fmt.hxx)
477
+
478
+ # list all the files in the folder
479
+ files = os.listdir(path)
480
+
481
+ if file_startswith is not None:
482
+ files = list(filter(lambda f: f.endswith('.hxx') and f.startswith(file_startswith), files))
483
+ # add the folder path back on
484
+ files = list(map(lambda f: os.path.join(path, f), files))
485
+ else:
486
+ # only include .hxx files
487
+ files = list(filter(lambda f: f.endswith('.hxx'), files))
488
+ # add the folder path back on
489
+ files = list(map(lambda f: path + f, files))
490
+ return files
491
+
492
+ @staticmethod
493
+ def is_included_type(name: str, type_list_re: List[str], with_durability: Optional[bool] = False) -> bool:
494
+
495
+ # TODO(brett19): This should be generalized somehow...
496
+ if "is_compound_operation" in name:
497
+ return False
498
+
499
+ if "replica_context" in name:
500
+ return False
501
+
502
+ if with_durability is True and '_with_legacy_durability' not in name:
503
+ return False
504
+
505
+ for x in type_list_re:
506
+ if re.fullmatch(x, name):
507
+ return True
508
+ return False
260
509
 
261
- def parse_type_str(typeStr):
262
- if typeStr == "std::mutex":
263
- return {"name": "std::mutex"}
264
- if typeStr == "std::string":
265
- return {"name": "std::string"}
266
- if typeStr == "std::chrono::duration<long long>":
267
- return {"name": "std::chrono::seconds"}
268
- if typeStr == "std::chrono::duration<long long, std::ratio<1, 1000>>":
269
- return {"name": "std::chrono::milliseconds"}
270
- if typeStr == "std::chrono::duration<long long, std::ratio<1, 1000000>>":
271
- return {"name": "std::chrono::microseconds"}
272
- if typeStr == "std::chrono::duration<long long, std::ratio<1, 1000000000>>":
273
- return {"name": "std::chrono::nanoseconds"}
274
- if typeStr == "std::error_code":
275
- return {"name": "std::error_code"}
276
- if typeStr == "std::monostate":
277
- return {"name": "std::monostate"}
278
- if typeStr == "std::byte":
279
- return {"name": "std::byte"}
280
- if typeStr == "unsigned long":
281
- return {"name": "std::size_t"}
282
- if typeStr == "char":
283
- return {"name": "std::int8_t"}
284
- if typeStr == "unsigned char":
285
- return {"name": "std::uint8_t"}
286
- if typeStr == "short":
287
- return {"name": "std::int16_t"}
288
- if typeStr == "unsigned short":
289
- return {"name": "std::uint16_t"}
290
- if typeStr == "int":
291
- return {"name": "std::int32_t"}
292
- if typeStr == "unsigned int":
293
- return {"name": "std::uint32_t"}
294
- if typeStr == "long long":
295
- return {"name": "std::int64_t"}
296
- if typeStr == "unsigned long long":
297
- return {"name": "std::uint64_t"}
298
- if typeStr == "bool":
299
- return {"name": "std::bool"}
300
- if typeStr == "float":
301
- return {"name": "std::float"}
302
- if typeStr == "double":
303
- return {"name": "std::double"}
304
- if typeStr == "std::nullptr_t":
305
- return {"name": "std::nullptr_t"}
306
- if typeStr in std_comparators:
307
- if 'void' in typeStr:
308
- return {"name": typeStr.replace("void", "")}
309
- return {"name": typeStr}
310
-
311
- tplParts = typeStr.split("<", 1)
312
- if len(tplParts) > 1:
313
- tplClassName = tplParts[0]
314
- tplParams = tplParts[1][:-1]
315
- if tplClassName == "std::function":
316
- return {
317
- "name": "std::function"
318
- }
319
- if tplClassName == "std::optional":
320
- return {
321
- "name": "std::optional",
322
- "of": parse_type_str(tplParams)
323
- }
324
- if tplClassName == "std::vector":
325
- return {
326
- "name": "std::vector",
327
- "of": parse_type_str(tplParams)
328
- }
329
- if tplClassName == "std::set":
330
- return {
331
- "name": "std::set",
332
- "of": parse_type_str(tplParams)
333
- }
334
- if tplClassName == "std::variant":
335
- variantParts = tplParams.split(", ")
336
- variantTypes = []
337
- for variantPart in variantParts:
338
- variantTypes.append(parse_type_str(variantPart))
339
- return {
340
- "name": "std::variant",
341
- "of": variantTypes
342
- }
343
- if tplClassName == "std::array":
344
- variantParts = tplParams.split(", ")
345
- if len(variantParts) != 2:
346
- print("FAILED TO PARSE ARRAY TYPES: " + typeStr)
347
- return {"name": "unknown", "str": typeStr}
348
- return {
349
- "name": "std::array",
350
- "of": parse_type_str(variantParts[0]),
351
- "size": int(variantParts[1])
352
- }
353
- if tplClassName == "std::map":
354
- variantParts = tplParams.split(", ")
355
- if len(variantParts) < 2 or len(variantParts) > 3:
356
- print("FAILED TO PARSE MAP TYPES: " + typeStr)
357
- return {"name": "unknown", "str": typeStr}
358
-
359
- if len(variantParts) == 2:
510
+ @staticmethod
511
+ def parse_type(type_: str) -> Dict[str, str]:
512
+ type_str = type_.get_canonical().spelling
513
+ return BindingsGenerator.parse_type_str(type_str)
514
+
515
+ @staticmethod
516
+ def parse_type_str(type_str: str) -> Dict[str, str]:
517
+ if type_str == "std::mutex":
518
+ return {"name": "std::mutex"}
519
+ if type_str == "std::string":
520
+ return {"name": "std::string"}
521
+ if type_str == "std::chrono::duration<long long>":
522
+ return {"name": "std::chrono::seconds"}
523
+ if type_str == "std::chrono::duration<long long, std::ratio<1, 1000>>":
524
+ return {"name": "std::chrono::milliseconds"}
525
+ if type_str == "std::chrono::duration<long long, std::ratio<1, 1000000>>":
526
+ return {"name": "std::chrono::microseconds"}
527
+ if type_str == "std::chrono::duration<long long, std::ratio<1, 1000000000>>":
528
+ return {"name": "std::chrono::nanoseconds"}
529
+ if type_str == "std::error_code":
530
+ return {"name": "std::error_code"}
531
+ if type_str == "std::monostate":
532
+ return {"name": "std::monostate"}
533
+ if type_str == "std::byte":
534
+ return {"name": "std::byte"}
535
+ if type_str == "unsigned long":
536
+ return {"name": "std::size_t"}
537
+ if type_str == "char":
538
+ return {"name": "std::int8_t"}
539
+ if type_str == "unsigned char":
540
+ return {"name": "std::uint8_t"}
541
+ if type_str == "short":
542
+ return {"name": "std::int16_t"}
543
+ if type_str == "unsigned short":
544
+ return {"name": "std::uint16_t"}
545
+ if type_str == "int":
546
+ return {"name": "std::int32_t"}
547
+ if type_str == "unsigned int":
548
+ return {"name": "std::uint32_t"}
549
+ if type_str == "long long":
550
+ return {"name": "std::int64_t"}
551
+ if type_str == "unsigned long long":
552
+ return {"name": "std::uint64_t"}
553
+ if type_str == "bool":
554
+ return {"name": "std::bool"}
555
+ if type_str == "float":
556
+ return {"name": "std::float"}
557
+ if type_str == "double":
558
+ return {"name": "std::double"}
559
+ if type_str == "std::nullptr_t":
560
+ return {"name": "std::nullptr_t"}
561
+ if type_str in STD_COMPARATORS:
562
+ if 'void' in type_str:
563
+ return {"name": type_str.replace("void", "")}
564
+ return {"name": type_str}
565
+
566
+ tplParts = type_str.split("<", 1)
567
+ if len(tplParts) > 1:
568
+ tplClassName = tplParts[0]
569
+ tplParams = tplParts[1][:-1]
570
+ if tplClassName == "std::function":
360
571
  return {
361
- "name": "std::map",
362
- "of": parse_type_str(variantParts[0]),
363
- "to": parse_type_str(variantParts[1])
572
+ "name": "std::function"
364
573
  }
365
- else:
574
+ if tplClassName == "std::optional":
366
575
  return {
367
- "name": "std::map",
368
- "of": parse_type_str(variantParts[0]),
369
- "to": parse_type_str(variantParts[1]),
370
- "comparator": parse_type_str(variantParts[2])
576
+ "name": "std::optional",
577
+ "of": BindingsGenerator.parse_type_str(tplParams)
578
+ }
579
+ if tplClassName == "std::vector":
580
+ return {
581
+ "name": "std::vector",
582
+ "of": BindingsGenerator.parse_type_str(tplParams)
583
+ }
584
+ if tplClassName == "std::set":
585
+ return {
586
+ "name": "std::set",
587
+ "of": BindingsGenerator. parse_type_str(tplParams)
588
+ }
589
+ if tplClassName == "std::variant":
590
+ variantParts = tplParams.split(", ")
591
+ variantTypes = []
592
+ for variantPart in variantParts:
593
+ variantTypes.append(BindingsGenerator.parse_type_str(variantPart))
594
+ return {
595
+ "name": "std::variant",
596
+ "of": variantTypes
597
+ }
598
+ if tplClassName == "std::array":
599
+ variantParts = tplParams.split(", ")
600
+ if len(variantParts) != 2:
601
+ print("FAILED TO PARSE ARRAY TYPES: " + type_str)
602
+ return {"name": "unknown", "str": type_str}
603
+ return {
604
+ "name": "std::array",
605
+ "of": BindingsGenerator.parse_type_str(variantParts[0]),
606
+ "size": int(variantParts[1])
607
+ }
608
+ if tplClassName == "std::map":
609
+ variantParts = tplParams.split(", ")
610
+ if len(variantParts) < 2 or len(variantParts) > 3:
611
+ print("FAILED TO PARSE MAP TYPES: " + type_str)
612
+ return {"name": "unknown", "str": type_str}
613
+
614
+ if len(variantParts) == 2:
615
+ return {
616
+ "name": "std::map",
617
+ "of": BindingsGenerator.parse_type_str(variantParts[0]),
618
+ "to": BindingsGenerator.parse_type_str(variantParts[1])
619
+ }
620
+ else:
621
+ return {
622
+ "name": "std::map",
623
+ "of": BindingsGenerator.parse_type_str(variantParts[0]),
624
+ "to": BindingsGenerator.parse_type_str(variantParts[1]),
625
+ "comparator": BindingsGenerator.parse_type_str(variantParts[2])
626
+ }
627
+
628
+ if tplClassName == "std::shared_ptr":
629
+ return {
630
+ "name": "std::shared_ptr",
631
+ "of": BindingsGenerator.parse_type_str(tplParams)
371
632
  }
372
633
 
373
- if tplClassName == "std::shared_ptr":
374
- return {
375
- "name": "std::shared_ptr",
376
- "of": parse_type_str(tplParams)
377
- }
378
-
379
- if not typeStr.startswith("couchbase::"):
380
- print("FAILED TO PARSE STRING TYPE: " + typeStr)
381
- return {"name": "unknown", "str": typeStr}
382
-
383
- if 'unnamed struct' in typeStr:
384
- print("WARNING: Found unnamed struct: " + typeStr)
385
-
386
- return {"name": typeStr}
634
+ if not type_str.startswith("couchbase::"):
635
+ print("FAILED TO PARSE STRING TYPE: " + type_str)
636
+ return {"name": "unknown", "str": type_str}
387
637
 
388
- internal_structs = []
389
- UNNAMED_STRUCT_DELIM = '::(unnamed struct'
638
+ if 'unnamed struct' in type_str:
639
+ print("WARNING: Found unnamed struct: " + type_str)
390
640
 
391
- def traverse(node, namespace, main_file):
392
- # only scan the elements of the file we parsed
393
- if node.location.file != None and node.location.file.name != main_file:
394
- return
395
-
396
- if node.kind == clang.cindex.CursorKind.STRUCT_DECL or node.kind == clang.cindex.CursorKind.CLASS_DECL:
397
- fullStructName = "::".join([*namespace, node.displayname])
398
- if fullStructName.endswith('::') or UNNAMED_STRUCT_DELIM in fullStructName:
399
- struct_name = fullStructName if fullStructName.endswith('::') else fullStructName.split(UNNAMED_STRUCT_DELIM)[0]
400
- match = next((s for s in internal_structs if struct_name in s), None)
401
- if match:
402
- fullStructName = match
403
-
404
- if is_included_type(fullStructName) or fullStructName in internal_structs:
405
- structFields = []
406
- for child in node.get_children():
407
- if child.kind == clang.cindex.CursorKind.FIELD_DECL:
408
- struct_type = parse_type(child.type)
409
- type_str = child.type.get_canonical().spelling
410
- if 'unnamed' in type_str:
411
- name_tokens = type_str.split('::')
412
- name_override = '::'.join(name_tokens[:-1] + [child.displayname])
413
- struct_type['name'] = name_override
414
- internal_structs.append(name_override)
415
-
416
- structFields.append({
417
- "name": child.displayname,
418
- "type": struct_type,
419
- })
420
- # replica read changes introduced duplicate get requests
421
- if any(map(lambda op: op['name'] == fullStructName, opTypes)):
422
- return
423
-
424
- opTypes.append({
425
- "name": fullStructName,
426
- "fields": structFields,
427
- })
428
- if node.kind == clang.cindex.CursorKind.TYPE_ALIAS_DECL:
429
- fullStructName = "::".join([*namespace, node.displayname])
430
- if is_included_type(fullStructName, with_durability=True):
431
- type_ref = next((c for c in node.get_children() if c.kind == clang.cindex.CursorKind.TYPE_REF), None)
432
- if type_ref:
433
- base_request_name = type_ref.displayname.replace('struct', '').strip()
434
- base_request = next((op for op in opTypes if op['name'] == base_request_name), None)
435
- if base_request:
436
- new_fields = [f for f in base_request['fields'] if f['name'] != 'durability_level']
437
- new_fields.extend([
438
- {"name":"persist_to", "type":{"name":"couchbase::persist_to"}},
439
- {"name":"replicate_to", "type":{"name":"couchbase::replicate_to"}}
440
- ])
641
+ return {"name": type_str}
441
642
 
442
- opTypes.append({
443
- "name": fullStructName,
444
- "fields": new_fields
445
- })
446
- if node.kind == clang.cindex.CursorKind.ENUM_DECL:
447
- fullEnumName = "::".join([*namespace, node.displayname])
448
- if is_included_type(fullEnumName):
449
- enumValues = []
450
-
451
- for child in node.get_children():
452
- if child.kind == clang.cindex.CursorKind.ENUM_CONSTANT_DECL:
453
- enumValues.append({
454
- "name": child.displayname,
455
- "value": child.enum_value,
456
- })
457
- opEnums.append({
458
- "name": fullEnumName,
459
- "type": parse_type(node.enum_type),
460
- "values": enumValues,
461
- })
462
-
463
- if node.kind == clang.cindex.CursorKind.NAMESPACE:
464
- namespace = [*namespace, node.displayname]
465
- if node.kind == clang.cindex.CursorKind.CLASS_DECL:
466
- namespace = [*namespace, node.displayname]
467
- if node.kind == clang.cindex.CursorKind.STRUCT_DECL:
468
- namespace = [*namespace, node.displayname]
469
-
470
- for child in node.get_children():
471
- traverse(child, namespace, main_file)
472
-
473
- include_paths = [
474
- f'-I{cxx_client_root}/',
475
- f'-I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/{CLANG_VERSION}/include',
476
- ]
477
- for dep, inc in cxx_deps_include_paths.items():
478
- include_paths.extend(set_cxx_deps_include_paths(dep, inc))
479
-
480
- for headerPath in fullFileList:
481
- print("processing " + headerPath)
482
- index = clang.cindex.Index.create()
483
- args = ['-std=c++17'] + include_paths
484
- translation_unit = index.parse(headerPath, args=args)
485
-
486
- # output clang compiler diagnostics information (for debugging)
487
- if 1:
488
- for diagnostic in translation_unit.diagnostics:
489
- diagnosticMsg = diagnostic.format()
490
- print(diagnostic)
491
-
492
- traverse(translation_unit.cursor, [], headerPath)
493
-
494
- jsonData = json.dumps({
495
- 'op_structs': opTypes,
496
- 'op_enums': opEnums
497
- })
498
-
499
- f = open("bindings.json", "w")
500
- f.write(jsonData)
501
- f.close()
643
+ @staticmethod
644
+ def sh(command: str, piped: Optional[bool] = False) -> Tuple[str, int]:
645
+ try:
646
+ if piped is True:
647
+ proc = subprocess.Popen(command,
648
+ stdin=subprocess.PIPE,
649
+ stdout=subprocess.PIPE,
650
+ stderr=subprocess.PIPE,
651
+ shell=True)
652
+ else:
653
+ proc = subprocess.Popen(command,
654
+ stdout=subprocess.PIPE,
655
+ stderr=subprocess.PIPE,
656
+ shell=True)
657
+ stdout, stderr = proc.communicate()
658
+ stderr = stderr.decode('utf-8')
659
+ if stderr != '':
660
+ return stderr, 1
661
+ return stdout.decode('utf-8'), 0
662
+ except FileNotFoundError:
663
+ return "Error: Command not found.", 1
664
+
665
+ @staticmethod
666
+ def find_llvm() -> None:
667
+ if sys.platform == 'darwin':
668
+ output, err = BindingsGenerator.sh('which clang')
669
+ if err:
670
+ raise Exception(f'Unable to determine clang binary. Error code: {err}.')
671
+ if 'llvm' not in output.strip():
672
+ # TODO: aarch64 v. x86_64
673
+ os_path = os.environ.get('PATH').split(':')
674
+ os_path = ['/opt/homebrew/opt/llvm/bin'] + os_path
675
+ os.environ.update(**{'PATH': ':'.join(os_path)})
676
+ output, err = BindingsGenerator.sh('which clang')
677
+ if err:
678
+ raise Exception(f'Unable to determine clang binary. Error code: {err}.')
679
+ if 'llvm' not in output.strip():
680
+ raise Exception('Unable to set LLVM as default.')
681
+ elif sys.platform == 'linux':
682
+ print('Under construction')
683
+ else:
684
+ raise ValueError('Unsupported platform')
685
+
686
+ @staticmethod
687
+ def get_llvm_version() -> str:
688
+ output, err = BindingsGenerator.sh('llvm-config --version')
689
+ if err:
690
+ raise Exception(f'Unable to determine LLVM version. Error code: {err}')
691
+ return output.strip()
692
+
693
+ @staticmethod
694
+ def get_llvm_includedir() -> str:
695
+ output, err = BindingsGenerator.sh('llvm-config --includedir')
696
+ if err:
697
+ raise Exception(f'Unable to determine LLVM includedir. Error code: {err}')
698
+ return output.strip()
699
+
700
+ @staticmethod
701
+ def get_llvm_libdir() -> str:
702
+ output, err = BindingsGenerator.sh('llvm-config --libdir')
703
+ if err:
704
+ raise Exception(f'Unable to determine LLVM libdir. Error code: {err}')
705
+ return output.strip()
706
+
707
+ @staticmethod
708
+ def get_system_headers() -> str:
709
+ if sys.platform == 'darwin':
710
+ output, err = BindingsGenerator.sh('xcrun --show-sdk-path')
711
+ if err:
712
+ raise Exception(f'Unable to determine system header path. Error code: {err}.')
713
+ return output.strip()
714
+ elif sys.platform == 'linux':
715
+ print('Under construction')
716
+ else:
717
+ raise ValueError('Unsupported platform')
718
+
719
+
720
+ if __name__ == '__main__':
721
+ from argparse import ArgumentParser
722
+ ap = ArgumentParser(description='Parse git version to PEP-440 version')
723
+ ap.add_argument('-v',
724
+ '--version',
725
+ help='Set CN_LLVM_VERSION, or use command: llvm-config --version')
726
+ ap.add_argument('-i',
727
+ '--includedir',
728
+ help='Set CN_LLVM_INCLUDE, or use command: llvm-config --includedir')
729
+ ap.add_argument('-l',
730
+ '--libdir',
731
+ help='Set CN_LLVM_LIB, or use command: llvm-config --libdir')
732
+ ap.add_argument('-s',
733
+ '--system-headers',
734
+ help='SET CN_SYS_HEADERS, or use command: xcrun --show-sdk-path')
735
+ options = ap.parse_args()
736
+
737
+ generator = BindingsGenerator(options.version,
738
+ options.libdir,
739
+ options.includedir,
740
+ options.system_headers)
741
+ generator.gen_bindings()
742
+
743
+
744
+ """
745
+
746
+ https://github.com/llvm/llvm-project/issues/86009
747
+
748
+ """