couchbase 4.2.1 → 4.2.2

Sign up to get free protection for your applications and to get access to all the features.
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
+ }