couchbase 4.2.1 → 4.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/CMakeLists.txt +1 -0
  2. package/deps/couchbase-cxx-client/.gitmodules +3 -0
  3. package/deps/couchbase-cxx-client/.idea/misc.xml +1 -0
  4. package/deps/couchbase-cxx-client/.idea/vcs.xml +1 -0
  5. package/deps/couchbase-cxx-client/CMakeLists.txt +11 -1
  6. package/deps/couchbase-cxx-client/README.md +3 -3
  7. package/deps/couchbase-cxx-client/cmake/CompilerWarnings.cmake +4 -1
  8. package/deps/couchbase-cxx-client/cmake/VersionInfo.cmake +13 -1
  9. package/deps/couchbase-cxx-client/cmake/build_version.hxx.in +1 -0
  10. package/deps/couchbase-cxx-client/core/cluster.hxx +15 -5
  11. package/deps/couchbase-cxx-client/core/impl/build_deferred_query_indexes.cxx +17 -6
  12. package/deps/couchbase-cxx-client/core/impl/cluster.cxx +1 -1
  13. package/deps/couchbase-cxx-client/core/impl/collection_query_index_manager.cxx +93 -0
  14. package/deps/couchbase-cxx-client/core/impl/configuration_profiles_registry.cxx +11 -0
  15. package/deps/couchbase-cxx-client/core/impl/create_query_index.cxx +119 -0
  16. package/deps/couchbase-cxx-client/core/impl/drop_query_index.cxx +108 -0
  17. package/deps/couchbase-cxx-client/core/impl/get.cxx +1 -1
  18. package/deps/couchbase-cxx-client/core/impl/get_all_query_indexes.cxx +76 -0
  19. package/deps/couchbase-cxx-client/core/impl/query.cxx +5 -7
  20. package/deps/couchbase-cxx-client/core/impl/watch_query_indexes.cxx +168 -0
  21. package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +15 -1
  22. package/deps/couchbase-cxx-client/core/logger/configuration.hxx +3 -0
  23. package/deps/couchbase-cxx-client/core/logger/level.hxx +21 -0
  24. package/deps/couchbase-cxx-client/core/logger/logger.hxx +4 -6
  25. package/deps/couchbase-cxx-client/core/meta/CMakeLists.txt +4 -2
  26. package/deps/couchbase-cxx-client/core/meta/features.hxx +31 -0
  27. package/deps/couchbase-cxx-client/core/meta/version.cxx +67 -5
  28. package/deps/couchbase-cxx-client/core/meta/version.hxx +12 -1
  29. package/deps/couchbase-cxx-client/core/metrics/CMakeLists.txt +4 -1
  30. package/deps/couchbase-cxx-client/core/metrics/logging_meter.cxx +46 -5
  31. package/deps/couchbase-cxx-client/core/metrics/logging_meter.hxx +10 -26
  32. package/deps/couchbase-cxx-client/core/operations/document_get_projected.cxx +3 -2
  33. package/deps/couchbase-cxx-client/core/operations/document_query.cxx +10 -12
  34. package/deps/couchbase-cxx-client/core/operations/document_query.hxx +1 -3
  35. package/deps/couchbase-cxx-client/core/operations/management/query_index_build.cxx +8 -14
  36. package/deps/couchbase-cxx-client/core/operations/management/query_index_build.hxx +2 -1
  37. package/deps/couchbase-cxx-client/core/operations/management/query_index_build_deferred.hxx +15 -8
  38. package/deps/couchbase-cxx-client/core/operations/management/query_index_create.cxx +7 -14
  39. package/deps/couchbase-cxx-client/core/operations/management/query_index_create.hxx +2 -0
  40. package/deps/couchbase-cxx-client/core/operations/management/query_index_drop.cxx +11 -16
  41. package/deps/couchbase-cxx-client/core/operations/management/query_index_drop.hxx +2 -0
  42. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all.cxx +8 -12
  43. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all.hxx +4 -3
  44. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all_deferred.cxx +21 -12
  45. package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all_deferred.hxx +3 -2
  46. package/deps/couchbase-cxx-client/core/origin.hxx +1 -1
  47. package/deps/couchbase-cxx-client/core/platform/uuid.cc +1 -2
  48. package/deps/couchbase-cxx-client/core/protocol/cmd_hello.hxx +5 -1
  49. package/deps/couchbase-cxx-client/core/query_context.hxx +79 -0
  50. package/deps/couchbase-cxx-client/core/tracing/CMakeLists.txt +3 -1
  51. package/deps/couchbase-cxx-client/core/tracing/threshold_logging_tracer.cxx +19 -4
  52. package/deps/couchbase-cxx-client/core/tracing/threshold_logging_tracer.hxx +2 -2
  53. package/deps/couchbase-cxx-client/core/transactions/async_attempt_context.hxx +10 -4
  54. package/deps/couchbase-cxx-client/core/transactions/atr_cleanup_entry.cxx +52 -63
  55. package/deps/couchbase-cxx-client/core/transactions/attempt_context.hxx +8 -3
  56. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.cxx +163 -126
  57. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.hxx +24 -37
  58. package/deps/couchbase-cxx-client/core/transactions/forward_compat.hxx +4 -4
  59. package/deps/couchbase-cxx-client/core/transactions/internal/atr_cleanup_entry.hxx +51 -13
  60. package/deps/couchbase-cxx-client/core/transactions/internal/client_record.hxx +26 -1
  61. package/deps/couchbase-cxx-client/core/transactions/internal/doc_record.hxx +21 -0
  62. package/deps/couchbase-cxx-client/core/transactions/internal/logging.hxx +40 -18
  63. package/deps/couchbase-cxx-client/core/transactions/internal/transaction_context.hxx +5 -0
  64. package/deps/couchbase-cxx-client/core/transactions/result.hxx +26 -0
  65. package/deps/couchbase-cxx-client/core/transactions/staged_mutation.cxx +48 -47
  66. package/deps/couchbase-cxx-client/core/transactions/staged_mutation.hxx +6 -6
  67. package/deps/couchbase-cxx-client/core/transactions/transaction_context.cxx +33 -19
  68. package/deps/couchbase-cxx-client/core/transactions/transaction_get_result.hxx +18 -2
  69. package/deps/couchbase-cxx-client/core/transactions/transaction_links.hxx +25 -2
  70. package/deps/couchbase-cxx-client/core/transactions/transactions.cxx +4 -4
  71. package/deps/couchbase-cxx-client/core/transactions/transactions_cleanup.cxx +49 -56
  72. package/deps/couchbase-cxx-client/core/transactions/waitable_op_list.hxx +7 -7
  73. package/deps/couchbase-cxx-client/core/transactions.hxx +0 -12
  74. package/deps/couchbase-cxx-client/core/utils/binary.hxx +1 -1
  75. package/deps/couchbase-cxx-client/core/utils/keyspace.hxx +55 -0
  76. package/deps/couchbase-cxx-client/couchbase/build_query_index_options.hxx +12 -45
  77. package/deps/couchbase-cxx-client/couchbase/cluster.hxx +1 -1
  78. package/deps/couchbase-cxx-client/couchbase/cluster_options.hxx +6 -7
  79. package/deps/couchbase-cxx-client/couchbase/collection.hxx +8 -0
  80. package/deps/couchbase-cxx-client/couchbase/collection_query_index_manager.hxx +218 -0
  81. package/deps/couchbase-cxx-client/couchbase/configuration_profiles_registry.hxx +3 -0
  82. package/deps/couchbase-cxx-client/couchbase/create_primary_query_index_options.hxx +166 -0
  83. package/deps/couchbase-cxx-client/couchbase/create_query_index_options.hxx +172 -0
  84. package/deps/couchbase-cxx-client/couchbase/drop_primary_query_index_options.hxx +129 -0
  85. package/deps/couchbase-cxx-client/couchbase/drop_query_index_options.hxx +116 -0
  86. package/deps/couchbase-cxx-client/couchbase/fmt/cas.hxx +1 -1
  87. package/deps/couchbase-cxx-client/couchbase/fmt/query_scan_consistency.hxx +46 -0
  88. package/deps/couchbase-cxx-client/couchbase/fmt/query_status.hxx +70 -0
  89. package/deps/couchbase-cxx-client/couchbase/fmt/tls_verify_mode.hxx +46 -0
  90. package/deps/couchbase-cxx-client/couchbase/get_all_query_indexes_options.hxx +100 -0
  91. package/deps/couchbase-cxx-client/{core → couchbase}/management/query_index.hxx +2 -2
  92. package/deps/couchbase-cxx-client/couchbase/metrics/meter.hxx +16 -0
  93. package/deps/couchbase-cxx-client/couchbase/query_index_manager.hxx +178 -6
  94. package/deps/couchbase-cxx-client/couchbase/query_options.hxx +1 -18
  95. package/deps/couchbase-cxx-client/couchbase/scope.hxx +5 -2
  96. package/deps/couchbase-cxx-client/couchbase/tracing/request_tracer.hxx +16 -0
  97. package/deps/couchbase-cxx-client/couchbase/transactions/async_attempt_context.hxx +11 -4
  98. package/deps/couchbase-cxx-client/couchbase/transactions/attempt_context.hxx +5 -3
  99. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_keyspace.hxx +16 -0
  100. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_query_options.hxx +0 -6
  101. package/deps/couchbase-cxx-client/couchbase/watch_query_indexes_options.hxx +115 -0
  102. package/deps/couchbase-cxx-client/examples/minimal.cxx +3 -1
  103. package/deps/couchbase-cxx-client/test/test_integration_crud.cxx +72 -0
  104. package/deps/couchbase-cxx-client/test/test_integration_management.cxx +727 -310
  105. package/deps/couchbase-cxx-client/test/test_integration_query.cxx +4 -8
  106. package/deps/couchbase-cxx-client/test/test_integration_transcoders.cxx +14 -0
  107. package/deps/couchbase-cxx-client/test/test_transaction_transaction_public_blocking_api.cxx +34 -19
  108. package/deps/couchbase-cxx-client/test/test_unit_transaction_logging.cxx +66 -22
  109. package/deps/couchbase-cxx-client/test/test_unit_utils.cxx +51 -0
  110. package/deps/couchbase-cxx-client/test/tools/tool_kv_loader.cxx +2 -2
  111. package/deps/couchbase-cxx-client/test/utils/integration_test_guard.cxx +2 -0
  112. package/deps/couchbase-cxx-client/test/utils/wait_until.cxx +4 -4
  113. package/deps/couchbase-cxx-client/third_party/docopt/.travis.yml +103 -0
  114. package/deps/couchbase-cxx-client/third_party/docopt/CMakeLists.txt +129 -0
  115. package/deps/couchbase-cxx-client/third_party/docopt/LICENSE-Boost-1.0 +23 -0
  116. package/deps/couchbase-cxx-client/third_party/docopt/LICENSE-MIT +23 -0
  117. package/deps/couchbase-cxx-client/third_party/docopt/README.rst +479 -0
  118. package/deps/couchbase-cxx-client/third_party/docopt/docopt-config.cmake +1 -0
  119. package/deps/couchbase-cxx-client/third_party/docopt/docopt.cpp +687 -0
  120. package/deps/couchbase-cxx-client/third_party/docopt/docopt.h +98 -0
  121. package/deps/couchbase-cxx-client/third_party/docopt/docopt.pc.in +9 -0
  122. package/deps/couchbase-cxx-client/third_party/docopt/docopt_private.h +676 -0
  123. package/deps/couchbase-cxx-client/third_party/docopt/docopt_util.h +122 -0
  124. package/deps/couchbase-cxx-client/third_party/docopt/docopt_value.h +341 -0
  125. package/deps/couchbase-cxx-client/third_party/docopt/examples/naval_fate.cpp +36 -0
  126. package/deps/couchbase-cxx-client/third_party/docopt/main.cpp +16 -0
  127. package/deps/couchbase-cxx-client/third_party/docopt/run_testcase.cpp +40 -0
  128. package/deps/couchbase-cxx-client/third_party/docopt/run_tests.py +72 -0
  129. package/deps/couchbase-cxx-client/third_party/docopt/testcases.docopt +957 -0
  130. package/deps/couchbase-cxx-client/tools/CMakeLists.txt +14 -0
  131. package/deps/couchbase-cxx-client/tools/cbc.cxx +65 -0
  132. package/deps/couchbase-cxx-client/tools/command.hxx +31 -0
  133. package/deps/couchbase-cxx-client/tools/command_registry.cxx +43 -0
  134. package/deps/couchbase-cxx-client/tools/command_registry.hxx +39 -0
  135. package/deps/couchbase-cxx-client/tools/get.cxx +267 -0
  136. package/deps/couchbase-cxx-client/tools/get.hxx +26 -0
  137. package/deps/couchbase-cxx-client/tools/query.cxx +441 -0
  138. package/deps/couchbase-cxx-client/tools/query.hxx +26 -0
  139. package/deps/couchbase-cxx-client/tools/utils.cxx +418 -0
  140. package/deps/couchbase-cxx-client/tools/utils.hxx +150 -0
  141. package/deps/couchbase-cxx-client/tools/version.cxx +82 -0
  142. package/deps/couchbase-cxx-client/tools/version.hxx +26 -0
  143. package/dist/authenticators.d.ts +2 -2
  144. package/dist/authenticators.js +1 -2
  145. package/dist/binding.d.ts +32 -16
  146. package/dist/cluster.js +14 -7
  147. package/dist/collection.d.ts +6 -0
  148. package/dist/collection.js +8 -0
  149. package/dist/queryexecutor.js +1 -1
  150. package/dist/queryindexmanager.d.ts +100 -4
  151. package/dist/queryindexmanager.js +344 -118
  152. package/dist/transactions.js +0 -2
  153. package/package.json +1 -1
  154. package/src/connection.cpp +2 -0
  155. package/src/connection.hpp +1 -0
  156. package/src/connection_autogen.cpp +16 -0
  157. package/src/jstocbpp_autogen.hpp +93 -23
  158. package/src/jstocbpp_basic.hpp +24 -0
  159. package/src/jstocbpp_transactions.hpp +0 -8
  160. package/tools/gen-bindings-js.js +1 -0
  161. package/tools/gen-bindings-json.py +4 -2
  162. package/deps/couchbase-cxx-client/core/transactions/logging.cxx +0 -107
@@ -0,0 +1,687 @@
1
+ //
2
+ // docopt.cpp
3
+ // docopt
4
+ //
5
+ // Created by Jared Grubb on 2013-11-03.
6
+ // Copyright (c) 2013 Jared Grubb. All rights reserved.
7
+ //
8
+
9
+ #include "docopt.h"
10
+ #include "docopt_util.h"
11
+ #include "docopt_private.h"
12
+
13
+ #include "docopt_value.h"
14
+
15
+ #include <vector>
16
+ #include <unordered_set>
17
+ #include <unordered_map>
18
+ #include <map>
19
+ #include <string>
20
+ #include <iostream>
21
+ #include <cassert>
22
+ #include <cstddef>
23
+
24
+ using namespace docopt;
25
+
26
+ DOCOPT_INLINE
27
+ std::ostream& docopt::operator<<(std::ostream& os, value const& val)
28
+ {
29
+ if (val.isBool()) {
30
+ bool b = val.asBool();
31
+ os << (b ? "true" : "false");
32
+ } else if (val.isLong()) {
33
+ long v = val.asLong();
34
+ os << v;
35
+ } else if (val.isString()) {
36
+ std::string const& str = val.asString();
37
+ os << '"' << str << '"';
38
+ } else if (val.isStringList()) {
39
+ auto const& list = val.asStringList();
40
+ os << "[";
41
+ bool first = true;
42
+ for(auto const& el : list) {
43
+ if (first) {
44
+ first = false;
45
+ } else {
46
+ os << ", ";
47
+ }
48
+ os << '"' << el << '"';
49
+ }
50
+ os << "]";
51
+ } else {
52
+ os << "null";
53
+ }
54
+ return os;
55
+ }
56
+
57
+ #if 0
58
+ #pragma mark -
59
+ #pragma mark Parsing stuff
60
+ #endif
61
+
62
+ class Tokens {
63
+ public:
64
+ Tokens(std::vector<std::string> tokens, bool isParsingArgv = true)
65
+ : fTokens(std::move(tokens)),
66
+ fIsParsingArgv(isParsingArgv)
67
+ {}
68
+
69
+ explicit operator bool() const {
70
+ return fIndex < fTokens.size();
71
+ }
72
+
73
+ static Tokens from_pattern(std::string const& source) {
74
+ static const std::regex re_separators {
75
+ "(?:\\s*)" // any spaces (non-matching subgroup)
76
+ "("
77
+ "[\\[\\]\\(\\)\\|]" // one character of brackets or parens or pipe character
78
+ "|"
79
+ "\\.\\.\\." // elipsis
80
+ ")" };
81
+
82
+ static const std::regex re_strings {
83
+ "(?:\\s*)" // any spaces (non-matching subgroup)
84
+ "("
85
+ "\\S*<.*?>" // strings, but make sure to keep "< >" strings together
86
+ "|"
87
+ "[^<>\\s]+" // string without <>
88
+ ")" };
89
+
90
+ // We do two stages of regex matching. The '[]()' and '...' are strong delimeters
91
+ // and need to be split out anywhere they occur (even at the end of a token). We
92
+ // first split on those, and then parse the stuff between them to find the string
93
+ // tokens. This is a little harder than the python version, since they have regex.split
94
+ // and we dont have anything like that.
95
+
96
+ std::vector<std::string> tokens;
97
+ std::for_each(std::sregex_iterator{ source.begin(), source.end(), re_separators },
98
+ std::sregex_iterator{},
99
+ [&](std::smatch const& match)
100
+ {
101
+ // handle anything before the separator (this is the "stuff" between the delimeters)
102
+ if (match.prefix().matched) {
103
+ std::for_each(std::sregex_iterator{match.prefix().first, match.prefix().second, re_strings},
104
+ std::sregex_iterator{},
105
+ [&](std::smatch const& m)
106
+ {
107
+ tokens.push_back(m[1].str());
108
+ });
109
+ }
110
+
111
+ // handle the delimter token itself
112
+ if (match[1].matched) {
113
+ tokens.push_back(match[1].str());
114
+ }
115
+ });
116
+
117
+ return Tokens(tokens, false);
118
+ }
119
+
120
+ std::string const& current() const {
121
+ if (*this)
122
+ return fTokens[fIndex];
123
+
124
+ static std::string const empty;
125
+ return empty;
126
+ }
127
+
128
+ std::string the_rest() const {
129
+ if (!*this)
130
+ return {};
131
+ return join(fTokens.begin()+static_cast<std::ptrdiff_t>(fIndex),
132
+ fTokens.end(),
133
+ " ");
134
+ }
135
+
136
+ std::string pop() {
137
+ return std::move(fTokens.at(fIndex++));
138
+ }
139
+
140
+ bool isParsingArgv() const { return fIsParsingArgv; }
141
+
142
+ struct OptionError : std::runtime_error { using runtime_error::runtime_error; };
143
+
144
+ private:
145
+ std::vector<std::string> fTokens;
146
+ size_t fIndex = 0;
147
+ bool fIsParsingArgv;
148
+ };
149
+
150
+ // Get all instances of 'T' from the pattern
151
+ template <typename T>
152
+ std::vector<T*> flat_filter(Pattern& pattern) {
153
+ std::vector<Pattern*> flattened = pattern.flat([](Pattern const* p) -> bool {
154
+ return dynamic_cast<T const*>(p) != nullptr;
155
+ });
156
+
157
+ // now, we're guaranteed to have T*'s, so just use static_cast
158
+ std::vector<T*> ret;
159
+ std::transform(flattened.begin(), flattened.end(), std::back_inserter(ret), [](Pattern* p) {
160
+ return static_cast<T*>(p);
161
+ });
162
+ return ret;
163
+ }
164
+
165
+ static std::vector<std::string> parse_section(std::string const& name, std::string const& source) {
166
+ // ECMAScript regex only has "?=" for a non-matching lookahead. In order to make sure we always have
167
+ // a newline to anchor our matching, we have to avoid matching the final newline of each grouping.
168
+ // Therefore, our regex is adjusted from the docopt Python one to use ?= to match the newlines before
169
+ // the following lines, rather than after.
170
+ std::regex const re_section_pattern {
171
+ "(?:^|\\n)" // anchored at a linebreak (or start of string)
172
+ "("
173
+ "[^\\n]*" + name + "[^\\n]*(?=\\n?)" // a line that contains the name
174
+ "(?:\\n[ \\t].*?(?=\\n|$))*" // followed by any number of lines that are indented
175
+ ")",
176
+ std::regex::icase
177
+ };
178
+
179
+ std::vector<std::string> ret;
180
+ std::for_each(std::sregex_iterator(source.begin(), source.end(), re_section_pattern),
181
+ std::sregex_iterator(),
182
+ [&](std::smatch const& match)
183
+ {
184
+ ret.push_back(trim(match[1].str()));
185
+ });
186
+
187
+ return ret;
188
+ }
189
+
190
+ static bool is_argument_spec(std::string const& token) {
191
+ if (token.empty())
192
+ return false;
193
+
194
+ if (token[0]=='<' && token[token.size()-1]=='>')
195
+ return true;
196
+
197
+ if (std::all_of(token.begin(), token.end(), &::isupper))
198
+ return true;
199
+
200
+ return false;
201
+ }
202
+
203
+ template <typename I>
204
+ std::vector<std::string> longOptions(I iter, I end) {
205
+ std::vector<std::string> ret;
206
+ std::transform(iter, end,
207
+ std::back_inserter(ret),
208
+ [](typename I::reference opt) { return opt->longOption(); });
209
+ return ret;
210
+ }
211
+
212
+ static PatternList parse_long(Tokens& tokens, std::vector<Option>& options)
213
+ {
214
+ // long ::= '--' chars [ ( ' ' | '=' ) chars ] ;
215
+ std::string longOpt, equal;
216
+ value val;
217
+ std::tie(longOpt, equal, val) = partition(tokens.pop(), "=");
218
+
219
+ assert(starts_with(longOpt, "--"));
220
+
221
+ if (equal.empty()) {
222
+ val = value{};
223
+ }
224
+
225
+ // detect with options match this long option
226
+ std::vector<Option const*> similar;
227
+ for(auto const& option : options) {
228
+ if (option.longOption()==longOpt)
229
+ similar.push_back(&option);
230
+ }
231
+
232
+ // maybe allow similar options that match by prefix
233
+ if (tokens.isParsingArgv() && similar.empty()) {
234
+ for(auto const& option : options) {
235
+ if (option.longOption().empty())
236
+ continue;
237
+ if (starts_with(option.longOption(), longOpt))
238
+ similar.push_back(&option);
239
+ }
240
+ }
241
+
242
+ PatternList ret;
243
+
244
+ if (similar.size() > 1) { // might be simply specified ambiguously 2+ times?
245
+ std::vector<std::string> prefixes = longOptions(similar.begin(), similar.end());
246
+ std::string error = "'" + longOpt + "' is not a unique prefix: ";
247
+ error.append(join(prefixes.begin(), prefixes.end(), ", "));
248
+ throw Tokens::OptionError(std::move(error));
249
+ } else if (similar.empty()) {
250
+ int argcount = equal.empty() ? 0 : 1;
251
+ options.emplace_back("", longOpt, argcount);
252
+
253
+ auto o = std::make_shared<Option>(options.back());
254
+ if (tokens.isParsingArgv()) {
255
+ o->setValue(argcount ? value{val} : value{true});
256
+ }
257
+ ret.push_back(o);
258
+ } else {
259
+ auto o = std::make_shared<Option>(*similar[0]);
260
+ if (o->argCount() == 0) {
261
+ if (val) {
262
+ std::string error = o->longOption() + " must not have an argument";
263
+ throw Tokens::OptionError(std::move(error));
264
+ }
265
+ } else {
266
+ if (!val) {
267
+ auto const& token = tokens.current();
268
+ if (token.empty() || token=="--") {
269
+ std::string error = o->longOption() + " requires an argument";
270
+ throw Tokens::OptionError(std::move(error));
271
+ }
272
+ val = tokens.pop();
273
+ }
274
+ }
275
+ if (tokens.isParsingArgv()) {
276
+ o->setValue(val ? std::move(val) : value{true});
277
+ }
278
+ ret.push_back(o);
279
+ }
280
+
281
+ return ret;
282
+ }
283
+
284
+ static PatternList parse_short(Tokens& tokens, std::vector<Option>& options)
285
+ {
286
+ // shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;
287
+
288
+ auto token = tokens.pop();
289
+
290
+ assert(starts_with(token, "-"));
291
+ assert(!starts_with(token, "--"));
292
+
293
+ auto i = token.begin();
294
+ ++i; // skip the leading '-'
295
+
296
+ PatternList ret;
297
+ while (i != token.end()) {
298
+ std::string shortOpt = { '-', *i };
299
+ ++i;
300
+
301
+ std::vector<Option const*> similar;
302
+ for(auto const& option : options) {
303
+ if (option.shortOption()==shortOpt)
304
+ similar.push_back(&option);
305
+ }
306
+
307
+ if (similar.size() > 1) {
308
+ std::string error = shortOpt + " is specified ambiguously "
309
+ + std::to_string(similar.size()) + " times";
310
+ throw Tokens::OptionError(std::move(error));
311
+ } else if (similar.empty()) {
312
+ options.emplace_back(shortOpt, "", 0);
313
+
314
+ auto o = std::make_shared<Option>(options.back());
315
+ if (tokens.isParsingArgv()) {
316
+ o->setValue(value{true});
317
+ }
318
+ ret.push_back(o);
319
+ } else {
320
+ auto o = std::make_shared<Option>(*similar[0]);
321
+ value val;
322
+ if (o->argCount()) {
323
+ if (i == token.end()) {
324
+ // consume the next token
325
+ auto const& ttoken = tokens.current();
326
+ if (ttoken.empty() || ttoken=="--") {
327
+ std::string error = shortOpt + " requires an argument";
328
+ throw Tokens::OptionError(std::move(error));
329
+ }
330
+ val = tokens.pop();
331
+ } else {
332
+ // consume all the rest
333
+ val = std::string{i, token.end()};
334
+ i = token.end();
335
+ }
336
+ }
337
+
338
+ if (tokens.isParsingArgv()) {
339
+ o->setValue(val ? std::move(val) : value{true});
340
+ }
341
+ ret.push_back(o);
342
+ }
343
+ }
344
+
345
+ return ret;
346
+ }
347
+
348
+ static PatternList parse_expr(Tokens& tokens, std::vector<Option>& options);
349
+
350
+ static PatternList parse_atom(Tokens& tokens, std::vector<Option>& options)
351
+ {
352
+ // atom ::= '(' expr ')' | '[' expr ']' | 'options'
353
+ // | long | shorts | argument | command ;
354
+
355
+ std::string const& token = tokens.current();
356
+
357
+ PatternList ret;
358
+
359
+ if (token == "[") {
360
+ tokens.pop();
361
+
362
+ auto expr = parse_expr(tokens, options);
363
+
364
+ auto trailing = tokens.pop();
365
+ if (trailing != "]") {
366
+ throw DocoptLanguageError("Mismatched '['");
367
+ }
368
+
369
+ ret.emplace_back(std::make_shared<Optional>(std::move(expr)));
370
+ } else if (token=="(") {
371
+ tokens.pop();
372
+
373
+ auto expr = parse_expr(tokens, options);
374
+
375
+ auto trailing = tokens.pop();
376
+ if (trailing != ")") {
377
+ throw DocoptLanguageError("Mismatched '('");
378
+ }
379
+
380
+ ret.emplace_back(std::make_shared<Required>(std::move(expr)));
381
+ } else if (token == "options") {
382
+ tokens.pop();
383
+ ret.emplace_back(std::make_shared<OptionsShortcut>());
384
+ } else if (starts_with(token, "--") && token != "--") {
385
+ ret = parse_long(tokens, options);
386
+ } else if (starts_with(token, "-") && token != "-" && token != "--") {
387
+ ret = parse_short(tokens, options);
388
+ } else if (is_argument_spec(token)) {
389
+ ret.emplace_back(std::make_shared<Argument>(tokens.pop()));
390
+ } else {
391
+ ret.emplace_back(std::make_shared<Command>(tokens.pop()));
392
+ }
393
+
394
+ return ret;
395
+ }
396
+
397
+ static PatternList parse_seq(Tokens& tokens, std::vector<Option>& options)
398
+ {
399
+ // seq ::= ( atom [ '...' ] )* ;"""
400
+
401
+ PatternList ret;
402
+
403
+ while (tokens) {
404
+ auto const& token = tokens.current();
405
+
406
+ if (token=="]" || token==")" || token=="|")
407
+ break;
408
+
409
+ auto atom = parse_atom(tokens, options);
410
+ if (tokens.current() == "...") {
411
+ ret.emplace_back(std::make_shared<OneOrMore>(std::move(atom)));
412
+ tokens.pop();
413
+ } else {
414
+ std::move(atom.begin(), atom.end(), std::back_inserter(ret));
415
+ }
416
+ }
417
+
418
+ return ret;
419
+ }
420
+
421
+ static std::shared_ptr<Pattern> maybe_collapse_to_required(PatternList&& seq)
422
+ {
423
+ if (seq.size()==1) {
424
+ return std::move(seq[0]);
425
+ }
426
+ return std::make_shared<Required>(std::move(seq));
427
+ }
428
+
429
+ static std::shared_ptr<Pattern> maybe_collapse_to_either(PatternList&& seq)
430
+ {
431
+ if (seq.size()==1) {
432
+ return std::move(seq[0]);
433
+ }
434
+ return std::make_shared<Either>(std::move(seq));
435
+ }
436
+
437
+ PatternList parse_expr(Tokens& tokens, std::vector<Option>& options)
438
+ {
439
+ // expr ::= seq ( '|' seq )* ;
440
+
441
+ auto seq = parse_seq(tokens, options);
442
+
443
+ if (tokens.current() != "|")
444
+ return seq;
445
+
446
+ PatternList ret;
447
+ ret.emplace_back(maybe_collapse_to_required(std::move(seq)));
448
+
449
+ while (tokens.current() == "|") {
450
+ tokens.pop();
451
+ seq = parse_seq(tokens, options);
452
+ ret.emplace_back(maybe_collapse_to_required(std::move(seq)));
453
+ }
454
+
455
+ return { maybe_collapse_to_either(std::move(ret)) };
456
+ }
457
+
458
+ static Required parse_pattern(std::string const& source, std::vector<Option>& options)
459
+ {
460
+ auto tokens = Tokens::from_pattern(source);
461
+ auto result = parse_expr(tokens, options);
462
+
463
+ if (tokens)
464
+ throw DocoptLanguageError("Unexpected ending: '" + tokens.the_rest() + "'");
465
+
466
+ assert(result.size() == 1 && "top level is always one big");
467
+ return Required{ std::move(result) };
468
+ }
469
+
470
+
471
+ static std::string formal_usage(std::string const& section) {
472
+ std::string ret = "(";
473
+
474
+ auto i = section.find(':')+1; // skip past "usage:"
475
+ auto parts = split(section, i);
476
+ for(size_t ii = 1; ii < parts.size(); ++ii) {
477
+ if (parts[ii] == parts[0]) {
478
+ ret += " ) | (";
479
+ } else {
480
+ ret.push_back(' ');
481
+ ret += parts[ii];
482
+ }
483
+ }
484
+
485
+ ret += " )";
486
+ return ret;
487
+ }
488
+
489
+ static PatternList parse_argv(Tokens tokens, std::vector<Option>& options, bool options_first)
490
+ {
491
+ // Parse command-line argument vector.
492
+ //
493
+ // If options_first:
494
+ // argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
495
+ // else:
496
+ // argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
497
+
498
+ PatternList ret;
499
+ while (tokens) {
500
+ auto const& token = tokens.current();
501
+
502
+ if (token=="--") {
503
+ // option list is done; convert all the rest to arguments
504
+ while (tokens) {
505
+ ret.emplace_back(std::make_shared<Argument>("", tokens.pop()));
506
+ }
507
+ } else if (starts_with(token, "--")) {
508
+ auto&& parsed = parse_long(tokens, options);
509
+ std::move(parsed.begin(), parsed.end(), std::back_inserter(ret));
510
+ } else if (token[0]=='-' && token != "-") {
511
+ auto&& parsed = parse_short(tokens, options);
512
+ std::move(parsed.begin(), parsed.end(), std::back_inserter(ret));
513
+ } else if (options_first) {
514
+ // option list is done; convert all the rest to arguments
515
+ while (tokens) {
516
+ ret.emplace_back(std::make_shared<Argument>("", tokens.pop()));
517
+ }
518
+ } else {
519
+ ret.emplace_back(std::make_shared<Argument>("", tokens.pop()));
520
+ }
521
+ }
522
+
523
+ return ret;
524
+ }
525
+
526
+ static std::vector<Option> parse_defaults(std::string const& doc) {
527
+ // This pattern is a delimiter by which we split the options.
528
+ // The delimiter is a new line followed by a whitespace(s) followed by one or two hyphens.
529
+ static std::regex const re_delimiter{
530
+ "(?:^|\\n)[ \\t]*" // a new line with leading whitespace
531
+ "(?=-{1,2})" // [split happens here] (positive lookahead) ... and followed by one or two hyphes
532
+ };
533
+
534
+ std::vector<Option> defaults;
535
+ for (auto s : parse_section("options:", doc)) {
536
+ s.erase(s.begin(), s.begin() + static_cast<std::ptrdiff_t>(s.find(':')) + 1); // get rid of "options:"
537
+
538
+ for (const auto& opt : regex_split(s, re_delimiter)) {
539
+ if (starts_with(opt, "-")) {
540
+ defaults.emplace_back(Option::parse(opt));
541
+ }
542
+ }
543
+ }
544
+
545
+ return defaults;
546
+ }
547
+
548
+ static bool isOptionSet(PatternList const& options, std::string const& opt1, std::string const& opt2 = "") {
549
+ return std::any_of(options.begin(), options.end(), [&](std::shared_ptr<Pattern const> const& opt) -> bool {
550
+ auto const& name = opt->name();
551
+ if (name==opt1 || (!opt2.empty() && name==opt2)) {
552
+ return opt->hasValue();
553
+ }
554
+ return false;
555
+ });
556
+ }
557
+
558
+ static void extras(bool help, bool version, PatternList const& options) {
559
+ if (help && isOptionSet(options, "-h", "--help")) {
560
+ throw DocoptExitHelp();
561
+ }
562
+
563
+ if (version && isOptionSet(options, "--version")) {
564
+ throw DocoptExitVersion();
565
+ }
566
+ }
567
+
568
+ // Parse the doc string and generate the Pattern tree
569
+ static std::pair<Required, std::vector<Option>> create_pattern_tree(std::string const& doc)
570
+ {
571
+ auto usage_sections = parse_section("usage:", doc);
572
+ if (usage_sections.empty()) {
573
+ throw DocoptLanguageError("'usage:' (case-insensitive) not found.");
574
+ }
575
+ if (usage_sections.size() > 1) {
576
+ throw DocoptLanguageError("More than one 'usage:' (case-insensitive).");
577
+ }
578
+
579
+ std::vector<Option> options = parse_defaults(doc);
580
+ Required pattern = parse_pattern(formal_usage(usage_sections[0]), options);
581
+
582
+ std::vector<Option const*> pattern_options = flat_filter<Option const>(pattern);
583
+
584
+ using UniqueOptions = std::unordered_set<Option const*, PatternHasher, PatternPointerEquality>;
585
+ UniqueOptions const uniq_pattern_options { pattern_options.begin(), pattern_options.end() };
586
+
587
+ // Fix up any "[options]" shortcuts with the actual option tree
588
+ for(auto& options_shortcut : flat_filter<OptionsShortcut>(pattern)) {
589
+ std::vector<Option> doc_options = parse_defaults(doc);
590
+
591
+ // set(doc_options) - set(pattern_options)
592
+ UniqueOptions uniq_doc_options;
593
+ for(auto const& opt : doc_options) {
594
+ if (uniq_pattern_options.count(&opt))
595
+ continue;
596
+ uniq_doc_options.insert(&opt);
597
+ }
598
+
599
+ // turn into shared_ptr's and set as children
600
+ PatternList children;
601
+ std::transform(uniq_doc_options.begin(), uniq_doc_options.end(),
602
+ std::back_inserter(children), [](Option const* opt) {
603
+ return std::make_shared<Option>(*opt);
604
+ });
605
+ options_shortcut->setChildren(std::move(children));
606
+ }
607
+
608
+ return { std::move(pattern), std::move(options) };
609
+ }
610
+
611
+ DOCOPT_INLINE
612
+ docopt::Options
613
+ docopt::docopt_parse(std::string const& doc,
614
+ std::vector<std::string> const& argv,
615
+ bool help,
616
+ bool version,
617
+ bool options_first)
618
+ {
619
+ Required pattern;
620
+ std::vector<Option> options;
621
+ try {
622
+ std::tie(pattern, options) = create_pattern_tree(doc);
623
+ } catch (Tokens::OptionError const& error) {
624
+ throw DocoptLanguageError(error.what());
625
+ }
626
+
627
+ PatternList argv_patterns;
628
+ try {
629
+ argv_patterns = parse_argv(Tokens(argv), options, options_first);
630
+ } catch (Tokens::OptionError const& error) {
631
+ throw DocoptArgumentError(error.what());
632
+ }
633
+
634
+ extras(help, version, argv_patterns);
635
+
636
+ std::vector<std::shared_ptr<LeafPattern>> collected;
637
+ bool matched = pattern.fix().match(argv_patterns, collected);
638
+ if (matched && argv_patterns.empty()) {
639
+ docopt::Options ret;
640
+
641
+ // (a.name, a.value) for a in (pattern.flat() + collected)
642
+ for (auto* p : pattern.leaves()) {
643
+ ret[p->name()] = p->getValue();
644
+ }
645
+
646
+ for (auto const& p : collected) {
647
+ ret[p->name()] = p->getValue();
648
+ }
649
+
650
+ return ret;
651
+ }
652
+
653
+ if (matched) {
654
+ std::string leftover = join(argv.begin(), argv.end(), ", ");
655
+ throw DocoptArgumentError("Unexpected argument: " + leftover);
656
+ }
657
+
658
+ throw DocoptArgumentError("Arguments did not match expected patterns"); // BLEH. Bad error.
659
+ }
660
+
661
+ DOCOPT_INLINE
662
+ docopt::Options
663
+ docopt::docopt(std::string const& doc,
664
+ std::vector<std::string> const& argv,
665
+ bool help,
666
+ std::string const& version,
667
+ bool options_first) noexcept
668
+ {
669
+ try {
670
+ return docopt_parse(doc, argv, help, !version.empty(), options_first);
671
+ } catch (DocoptExitHelp const&) {
672
+ std::cout << doc << std::endl;
673
+ std::exit(0);
674
+ } catch (DocoptExitVersion const&) {
675
+ std::cout << version << std::endl;
676
+ std::exit(0);
677
+ } catch (DocoptLanguageError const& error) {
678
+ std::cerr << "Docopt usage string could not be parsed" << std::endl;
679
+ std::cerr << error.what() << std::endl;
680
+ std::exit(-1);
681
+ } catch (DocoptArgumentError const& error) {
682
+ std::cerr << error.what();
683
+ std::cout << std::endl;
684
+ std::cout << doc << std::endl;
685
+ std::exit(-1);
686
+ } /* Any other exception is unexpected: let std::terminate grab it */
687
+ }