couchbase 4.2.1 → 4.2.2
Sign up to get free protection for your applications and to get access to all the features.
- package/CMakeLists.txt +1 -0
- package/deps/couchbase-cxx-client/.gitmodules +3 -0
- package/deps/couchbase-cxx-client/.idea/misc.xml +1 -0
- package/deps/couchbase-cxx-client/.idea/vcs.xml +1 -0
- package/deps/couchbase-cxx-client/CMakeLists.txt +11 -1
- package/deps/couchbase-cxx-client/README.md +3 -3
- package/deps/couchbase-cxx-client/cmake/CompilerWarnings.cmake +4 -1
- package/deps/couchbase-cxx-client/cmake/VersionInfo.cmake +13 -1
- package/deps/couchbase-cxx-client/cmake/build_version.hxx.in +1 -0
- package/deps/couchbase-cxx-client/core/cluster.hxx +15 -5
- package/deps/couchbase-cxx-client/core/impl/build_deferred_query_indexes.cxx +17 -6
- package/deps/couchbase-cxx-client/core/impl/cluster.cxx +1 -1
- package/deps/couchbase-cxx-client/core/impl/collection_query_index_manager.cxx +93 -0
- package/deps/couchbase-cxx-client/core/impl/configuration_profiles_registry.cxx +11 -0
- package/deps/couchbase-cxx-client/core/impl/create_query_index.cxx +119 -0
- package/deps/couchbase-cxx-client/core/impl/drop_query_index.cxx +108 -0
- package/deps/couchbase-cxx-client/core/impl/get.cxx +1 -1
- package/deps/couchbase-cxx-client/core/impl/get_all_query_indexes.cxx +76 -0
- package/deps/couchbase-cxx-client/core/impl/query.cxx +5 -7
- package/deps/couchbase-cxx-client/core/impl/watch_query_indexes.cxx +168 -0
- package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +15 -1
- package/deps/couchbase-cxx-client/core/logger/configuration.hxx +3 -0
- package/deps/couchbase-cxx-client/core/logger/level.hxx +21 -0
- package/deps/couchbase-cxx-client/core/logger/logger.hxx +4 -6
- package/deps/couchbase-cxx-client/core/meta/CMakeLists.txt +4 -2
- package/deps/couchbase-cxx-client/core/meta/features.hxx +31 -0
- package/deps/couchbase-cxx-client/core/meta/version.cxx +67 -5
- package/deps/couchbase-cxx-client/core/meta/version.hxx +12 -1
- package/deps/couchbase-cxx-client/core/metrics/CMakeLists.txt +4 -1
- package/deps/couchbase-cxx-client/core/metrics/logging_meter.cxx +46 -5
- package/deps/couchbase-cxx-client/core/metrics/logging_meter.hxx +10 -26
- package/deps/couchbase-cxx-client/core/operations/document_get_projected.cxx +3 -2
- package/deps/couchbase-cxx-client/core/operations/document_query.cxx +10 -12
- package/deps/couchbase-cxx-client/core/operations/document_query.hxx +1 -3
- package/deps/couchbase-cxx-client/core/operations/management/query_index_build.cxx +8 -14
- package/deps/couchbase-cxx-client/core/operations/management/query_index_build.hxx +2 -1
- package/deps/couchbase-cxx-client/core/operations/management/query_index_build_deferred.hxx +15 -8
- package/deps/couchbase-cxx-client/core/operations/management/query_index_create.cxx +7 -14
- package/deps/couchbase-cxx-client/core/operations/management/query_index_create.hxx +2 -0
- package/deps/couchbase-cxx-client/core/operations/management/query_index_drop.cxx +11 -16
- package/deps/couchbase-cxx-client/core/operations/management/query_index_drop.hxx +2 -0
- package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all.cxx +8 -12
- package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all.hxx +4 -3
- package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all_deferred.cxx +21 -12
- package/deps/couchbase-cxx-client/core/operations/management/query_index_get_all_deferred.hxx +3 -2
- package/deps/couchbase-cxx-client/core/origin.hxx +1 -1
- package/deps/couchbase-cxx-client/core/platform/uuid.cc +1 -2
- package/deps/couchbase-cxx-client/core/protocol/cmd_hello.hxx +5 -1
- package/deps/couchbase-cxx-client/core/query_context.hxx +79 -0
- package/deps/couchbase-cxx-client/core/tracing/CMakeLists.txt +3 -1
- package/deps/couchbase-cxx-client/core/tracing/threshold_logging_tracer.cxx +19 -4
- package/deps/couchbase-cxx-client/core/tracing/threshold_logging_tracer.hxx +2 -2
- package/deps/couchbase-cxx-client/core/transactions/async_attempt_context.hxx +10 -4
- package/deps/couchbase-cxx-client/core/transactions/atr_cleanup_entry.cxx +52 -63
- package/deps/couchbase-cxx-client/core/transactions/attempt_context.hxx +8 -3
- package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.cxx +163 -126
- package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.hxx +24 -37
- package/deps/couchbase-cxx-client/core/transactions/forward_compat.hxx +4 -4
- package/deps/couchbase-cxx-client/core/transactions/internal/atr_cleanup_entry.hxx +51 -13
- package/deps/couchbase-cxx-client/core/transactions/internal/client_record.hxx +26 -1
- package/deps/couchbase-cxx-client/core/transactions/internal/doc_record.hxx +21 -0
- package/deps/couchbase-cxx-client/core/transactions/internal/logging.hxx +40 -18
- package/deps/couchbase-cxx-client/core/transactions/internal/transaction_context.hxx +5 -0
- package/deps/couchbase-cxx-client/core/transactions/result.hxx +26 -0
- package/deps/couchbase-cxx-client/core/transactions/staged_mutation.cxx +48 -47
- package/deps/couchbase-cxx-client/core/transactions/staged_mutation.hxx +6 -6
- package/deps/couchbase-cxx-client/core/transactions/transaction_context.cxx +33 -19
- package/deps/couchbase-cxx-client/core/transactions/transaction_get_result.hxx +18 -2
- package/deps/couchbase-cxx-client/core/transactions/transaction_links.hxx +25 -2
- package/deps/couchbase-cxx-client/core/transactions/transactions.cxx +4 -4
- package/deps/couchbase-cxx-client/core/transactions/transactions_cleanup.cxx +49 -56
- package/deps/couchbase-cxx-client/core/transactions/waitable_op_list.hxx +7 -7
- package/deps/couchbase-cxx-client/core/transactions.hxx +0 -12
- package/deps/couchbase-cxx-client/core/utils/binary.hxx +1 -1
- package/deps/couchbase-cxx-client/core/utils/keyspace.hxx +55 -0
- package/deps/couchbase-cxx-client/couchbase/build_query_index_options.hxx +12 -45
- package/deps/couchbase-cxx-client/couchbase/cluster.hxx +1 -1
- package/deps/couchbase-cxx-client/couchbase/cluster_options.hxx +6 -7
- package/deps/couchbase-cxx-client/couchbase/collection.hxx +8 -0
- package/deps/couchbase-cxx-client/couchbase/collection_query_index_manager.hxx +218 -0
- package/deps/couchbase-cxx-client/couchbase/configuration_profiles_registry.hxx +3 -0
- package/deps/couchbase-cxx-client/couchbase/create_primary_query_index_options.hxx +166 -0
- package/deps/couchbase-cxx-client/couchbase/create_query_index_options.hxx +172 -0
- package/deps/couchbase-cxx-client/couchbase/drop_primary_query_index_options.hxx +129 -0
- package/deps/couchbase-cxx-client/couchbase/drop_query_index_options.hxx +116 -0
- package/deps/couchbase-cxx-client/couchbase/fmt/cas.hxx +1 -1
- package/deps/couchbase-cxx-client/couchbase/fmt/query_scan_consistency.hxx +46 -0
- package/deps/couchbase-cxx-client/couchbase/fmt/query_status.hxx +70 -0
- package/deps/couchbase-cxx-client/couchbase/fmt/tls_verify_mode.hxx +46 -0
- package/deps/couchbase-cxx-client/couchbase/get_all_query_indexes_options.hxx +100 -0
- package/deps/couchbase-cxx-client/{core → couchbase}/management/query_index.hxx +2 -2
- package/deps/couchbase-cxx-client/couchbase/metrics/meter.hxx +16 -0
- package/deps/couchbase-cxx-client/couchbase/query_index_manager.hxx +178 -6
- package/deps/couchbase-cxx-client/couchbase/query_options.hxx +1 -18
- package/deps/couchbase-cxx-client/couchbase/scope.hxx +5 -2
- package/deps/couchbase-cxx-client/couchbase/tracing/request_tracer.hxx +16 -0
- package/deps/couchbase-cxx-client/couchbase/transactions/async_attempt_context.hxx +11 -4
- package/deps/couchbase-cxx-client/couchbase/transactions/attempt_context.hxx +5 -3
- package/deps/couchbase-cxx-client/couchbase/transactions/transaction_keyspace.hxx +16 -0
- package/deps/couchbase-cxx-client/couchbase/transactions/transaction_query_options.hxx +0 -6
- package/deps/couchbase-cxx-client/couchbase/watch_query_indexes_options.hxx +115 -0
- package/deps/couchbase-cxx-client/examples/minimal.cxx +3 -1
- package/deps/couchbase-cxx-client/test/test_integration_crud.cxx +72 -0
- package/deps/couchbase-cxx-client/test/test_integration_management.cxx +727 -310
- package/deps/couchbase-cxx-client/test/test_integration_query.cxx +4 -8
- package/deps/couchbase-cxx-client/test/test_integration_transcoders.cxx +14 -0
- package/deps/couchbase-cxx-client/test/test_transaction_transaction_public_blocking_api.cxx +34 -19
- package/deps/couchbase-cxx-client/test/test_unit_transaction_logging.cxx +66 -22
- package/deps/couchbase-cxx-client/test/test_unit_utils.cxx +51 -0
- package/deps/couchbase-cxx-client/test/tools/tool_kv_loader.cxx +2 -2
- package/deps/couchbase-cxx-client/test/utils/integration_test_guard.cxx +2 -0
- package/deps/couchbase-cxx-client/test/utils/wait_until.cxx +4 -4
- package/deps/couchbase-cxx-client/third_party/docopt/.travis.yml +103 -0
- package/deps/couchbase-cxx-client/third_party/docopt/CMakeLists.txt +129 -0
- package/deps/couchbase-cxx-client/third_party/docopt/LICENSE-Boost-1.0 +23 -0
- package/deps/couchbase-cxx-client/third_party/docopt/LICENSE-MIT +23 -0
- package/deps/couchbase-cxx-client/third_party/docopt/README.rst +479 -0
- package/deps/couchbase-cxx-client/third_party/docopt/docopt-config.cmake +1 -0
- package/deps/couchbase-cxx-client/third_party/docopt/docopt.cpp +687 -0
- package/deps/couchbase-cxx-client/third_party/docopt/docopt.h +98 -0
- package/deps/couchbase-cxx-client/third_party/docopt/docopt.pc.in +9 -0
- package/deps/couchbase-cxx-client/third_party/docopt/docopt_private.h +676 -0
- package/deps/couchbase-cxx-client/third_party/docopt/docopt_util.h +122 -0
- package/deps/couchbase-cxx-client/third_party/docopt/docopt_value.h +341 -0
- package/deps/couchbase-cxx-client/third_party/docopt/examples/naval_fate.cpp +36 -0
- package/deps/couchbase-cxx-client/third_party/docopt/main.cpp +16 -0
- package/deps/couchbase-cxx-client/third_party/docopt/run_testcase.cpp +40 -0
- package/deps/couchbase-cxx-client/third_party/docopt/run_tests.py +72 -0
- package/deps/couchbase-cxx-client/third_party/docopt/testcases.docopt +957 -0
- package/deps/couchbase-cxx-client/tools/CMakeLists.txt +14 -0
- package/deps/couchbase-cxx-client/tools/cbc.cxx +65 -0
- package/deps/couchbase-cxx-client/tools/command.hxx +31 -0
- package/deps/couchbase-cxx-client/tools/command_registry.cxx +43 -0
- package/deps/couchbase-cxx-client/tools/command_registry.hxx +39 -0
- package/deps/couchbase-cxx-client/tools/get.cxx +267 -0
- package/deps/couchbase-cxx-client/tools/get.hxx +26 -0
- package/deps/couchbase-cxx-client/tools/query.cxx +441 -0
- package/deps/couchbase-cxx-client/tools/query.hxx +26 -0
- package/deps/couchbase-cxx-client/tools/utils.cxx +418 -0
- package/deps/couchbase-cxx-client/tools/utils.hxx +150 -0
- package/deps/couchbase-cxx-client/tools/version.cxx +82 -0
- package/deps/couchbase-cxx-client/tools/version.hxx +26 -0
- package/dist/authenticators.d.ts +2 -2
- package/dist/authenticators.js +1 -2
- package/dist/binding.d.ts +32 -16
- package/dist/cluster.js +14 -7
- package/dist/collection.d.ts +6 -0
- package/dist/collection.js +8 -0
- package/dist/queryexecutor.js +1 -1
- package/dist/queryindexmanager.d.ts +100 -4
- package/dist/queryindexmanager.js +344 -118
- package/dist/transactions.js +0 -2
- package/package.json +1 -1
- package/src/connection.cpp +2 -0
- package/src/connection.hpp +1 -0
- package/src/connection_autogen.cpp +16 -0
- package/src/jstocbpp_autogen.hpp +93 -23
- package/src/jstocbpp_basic.hpp +24 -0
- package/src/jstocbpp_transactions.hpp +0 -8
- package/tools/gen-bindings-js.js +1 -0
- package/tools/gen-bindings-json.py +4 -2
- 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
|
+
}
|