mirror of https://gitee.com/bigwinds/arangodb
move parts from ProgramOptions from headers into cpp files
This commit is contained in:
parent
6c065cd889
commit
53fa66e60d
|
@ -44,7 +44,7 @@ class BindParameters {
|
||||||
: _builder(nullptr), _parameters(), _processed(false) {}
|
: _builder(nullptr), _parameters(), _processed(false) {}
|
||||||
|
|
||||||
/// @brief create the parameters
|
/// @brief create the parameters
|
||||||
explicit BindParameters(std::shared_ptr<arangodb::velocypack::Builder> builder)
|
explicit BindParameters(std::shared_ptr<arangodb::velocypack::Builder> const& builder)
|
||||||
: _builder(builder), _parameters(), _processed(false) {}
|
: _builder(builder), _parameters(), _processed(false) {}
|
||||||
|
|
||||||
/// @brief destroy the parameters
|
/// @brief destroy the parameters
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "Query.h"
|
#include "Query.h"
|
||||||
|
|
||||||
|
#include "ApplicationFeatures/ApplicationServer.h"
|
||||||
#include "Aql/AqlItemBlock.h"
|
#include "Aql/AqlItemBlock.h"
|
||||||
#include "Aql/AqlTransaction.h"
|
#include "Aql/AqlTransaction.h"
|
||||||
#include "Aql/ExecutionBlock.h"
|
#include "Aql/ExecutionBlock.h"
|
||||||
|
@ -42,6 +43,7 @@
|
||||||
#include "Cluster/ServerState.h"
|
#include "Cluster/ServerState.h"
|
||||||
#include "Logger/Logger.h"
|
#include "Logger/Logger.h"
|
||||||
#include "RestServer/AqlFeature.h"
|
#include "RestServer/AqlFeature.h"
|
||||||
|
#include "RestServer/QueryRegistryFeature.h"
|
||||||
#include "StorageEngine/TransactionState.h"
|
#include "StorageEngine/TransactionState.h"
|
||||||
#include "Transaction/Methods.h"
|
#include "Transaction/Methods.h"
|
||||||
#include "Transaction/StandaloneContext.h"
|
#include "Transaction/StandaloneContext.h"
|
||||||
|
@ -69,23 +71,11 @@ static std::atomic<TRI_voc_tick_t> NextQueryId(1);
|
||||||
constexpr uint64_t DontCache = 0;
|
constexpr uint64_t DontCache = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief global memory limit for AQL queries
|
|
||||||
uint64_t Query::MemoryLimitValue = 0;
|
|
||||||
|
|
||||||
/// @brief global threshold value for slow queries
|
|
||||||
double Query::SlowQueryThresholdValue = 10.0;
|
|
||||||
|
|
||||||
/// @brief whether or not query tracking is disabled globally
|
|
||||||
bool Query::DoDisableQueryTracking = false;
|
|
||||||
|
|
||||||
/// @brief whether a warning in an AQL query should raise an error
|
|
||||||
bool Query::DoFailOnWarning = false;
|
|
||||||
|
|
||||||
/// @brief creates a query
|
/// @brief creates a query
|
||||||
Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
|
Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
|
||||||
char const* queryString, size_t queryLength,
|
char const* queryString, size_t queryLength,
|
||||||
std::shared_ptr<VPackBuilder> bindParameters,
|
std::shared_ptr<VPackBuilder> const& bindParameters,
|
||||||
std::shared_ptr<VPackBuilder> options, QueryPart part)
|
std::shared_ptr<VPackBuilder> const& options, QueryPart part)
|
||||||
: _id(0),
|
: _id(0),
|
||||||
_resourceMonitor(),
|
_resourceMonitor(),
|
||||||
_resources(&_resourceMonitor),
|
_resources(&_resourceMonitor),
|
||||||
|
@ -102,6 +92,7 @@ Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
|
||||||
_maxWarningCount(10),
|
_maxWarningCount(10),
|
||||||
_warnings(),
|
_warnings(),
|
||||||
_startTime(TRI_microtime()),
|
_startTime(TRI_microtime()),
|
||||||
|
_queryRegistry(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")),
|
||||||
_part(part),
|
_part(part),
|
||||||
_contextOwnedByExterior(contextOwnedByExterior),
|
_contextOwnedByExterior(contextOwnedByExterior),
|
||||||
_killed(false),
|
_killed(false),
|
||||||
|
@ -152,8 +143,8 @@ Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
|
||||||
|
|
||||||
/// @brief creates a query from VelocyPack
|
/// @brief creates a query from VelocyPack
|
||||||
Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
|
Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
|
||||||
std::shared_ptr<VPackBuilder> const queryStruct,
|
std::shared_ptr<VPackBuilder> const& queryStruct,
|
||||||
std::shared_ptr<VPackBuilder> options, QueryPart part)
|
std::shared_ptr<VPackBuilder> const& options, QueryPart part)
|
||||||
: _id(0),
|
: _id(0),
|
||||||
_resourceMonitor(),
|
_resourceMonitor(),
|
||||||
_resources(&_resourceMonitor),
|
_resources(&_resourceMonitor),
|
||||||
|
@ -169,6 +160,7 @@ Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
|
||||||
_maxWarningCount(10),
|
_maxWarningCount(10),
|
||||||
_warnings(),
|
_warnings(),
|
||||||
_startTime(TRI_microtime()),
|
_startTime(TRI_microtime()),
|
||||||
|
_queryRegistry(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")),
|
||||||
_part(part),
|
_part(part),
|
||||||
_contextOwnedByExterior(contextOwnedByExterior),
|
_contextOwnedByExterior(contextOwnedByExterior),
|
||||||
_killed(false),
|
_killed(false),
|
||||||
|
@ -211,21 +203,7 @@ Query::~Query() {
|
||||||
|
|
||||||
_executor.reset();
|
_executor.reset();
|
||||||
|
|
||||||
if (_context != nullptr) {
|
exitContext();
|
||||||
TRI_ASSERT(!_contextOwnedByExterior);
|
|
||||||
|
|
||||||
// unregister transaction and resolver in context
|
|
||||||
ISOLATE;
|
|
||||||
TRI_GET_GLOBALS();
|
|
||||||
auto ctx =
|
|
||||||
static_cast<arangodb::transaction::V8Context*>(v8g->_transactionContext);
|
|
||||||
if (ctx != nullptr) {
|
|
||||||
ctx->unregisterTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
V8DealerFeature::DEALER->exitContext(_context);
|
|
||||||
_context = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ast.reset();
|
_ast.reset();
|
||||||
|
|
||||||
|
@ -376,7 +354,7 @@ void Query::registerErrorCustom(int code, char const* details) {
|
||||||
void Query::registerWarning(int code, char const* details) {
|
void Query::registerWarning(int code, char const* details) {
|
||||||
TRI_ASSERT(code != TRI_ERROR_NO_ERROR);
|
TRI_ASSERT(code != TRI_ERROR_NO_ERROR);
|
||||||
|
|
||||||
if (DoFailOnWarning) {
|
if (_queryRegistry->failOnWarning()) {
|
||||||
// make an error from each warning if requested
|
// make an error from each warning if requested
|
||||||
if (details == nullptr) {
|
if (details == nullptr) {
|
||||||
THROW_ARANGO_EXCEPTION(code);
|
THROW_ARANGO_EXCEPTION(code);
|
||||||
|
@ -1139,7 +1117,6 @@ void Query::exitContext() {
|
||||||
V8DealerFeature::DEALER->exitContext(_context);
|
V8DealerFeature::DEALER->exitContext(_context);
|
||||||
_context = nullptr;
|
_context = nullptr;
|
||||||
}
|
}
|
||||||
TRI_ASSERT(_context == nullptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1473,8 +1450,18 @@ Graph const* Query::lookupGraphByName(std::string const& name) {
|
||||||
|
|
||||||
return g.release();
|
return g.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Query::memoryLimit() const {
|
||||||
|
uint64_t globalLimit = _queryRegistry->queryMemoryLimit();
|
||||||
|
uint64_t value = getNumericOption<uint64_t>("memoryLimit", globalLimit);
|
||||||
|
if (value > 0) {
|
||||||
|
return static_cast<size_t>(value);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief returns the next query id
|
/// @brief returns the next query id
|
||||||
TRI_voc_tick_t Query::NextId() {
|
TRI_voc_tick_t Query::NextId() {
|
||||||
return NextQueryId.fetch_add(1, std::memory_order_seq_cst);
|
return NextQueryId.fetch_add(1, std::memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@ namespace velocypack {
|
||||||
class Builder;
|
class Builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class QueryRegistryFeature;
|
||||||
|
|
||||||
namespace aql {
|
namespace aql {
|
||||||
|
|
||||||
struct AstNode;
|
struct AstNode;
|
||||||
|
@ -75,12 +77,12 @@ class Query {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Query(bool, TRI_vocbase_t*, char const*, size_t,
|
Query(bool, TRI_vocbase_t*, char const*, size_t,
|
||||||
std::shared_ptr<arangodb::velocypack::Builder>,
|
std::shared_ptr<arangodb::velocypack::Builder> const& bindParameters,
|
||||||
std::shared_ptr<arangodb::velocypack::Builder>, QueryPart);
|
std::shared_ptr<arangodb::velocypack::Builder> const& options, QueryPart);
|
||||||
|
|
||||||
Query(bool, TRI_vocbase_t*,
|
Query(bool contextOwnedByExterior, TRI_vocbase_t*,
|
||||||
std::shared_ptr<arangodb::velocypack::Builder> const,
|
std::shared_ptr<arangodb::velocypack::Builder> const& queryStruct,
|
||||||
std::shared_ptr<arangodb::velocypack::Builder>, QueryPart);
|
std::shared_ptr<arangodb::velocypack::Builder> const& options, QueryPart);
|
||||||
|
|
||||||
~Query();
|
~Query();
|
||||||
|
|
||||||
|
@ -185,13 +187,7 @@ class Query {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief memory limit for query
|
/// @brief memory limit for query
|
||||||
size_t memoryLimit() const {
|
size_t memoryLimit() const;
|
||||||
uint64_t value = getNumericOption<decltype(MemoryLimitValue)>("memoryLimit", MemoryLimitValue);
|
|
||||||
if (value > 0) {
|
|
||||||
return static_cast<size_t>(value);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief maximum number of plans to produce
|
/// @brief maximum number of plans to produce
|
||||||
int64_t literalSizeThreshold() const {
|
int64_t literalSizeThreshold() const {
|
||||||
|
@ -274,37 +270,6 @@ class Query {
|
||||||
/// NOTE: returns nullptr if there are no warnings.
|
/// NOTE: returns nullptr if there are no warnings.
|
||||||
std::shared_ptr<arangodb::velocypack::Builder> warningsToVelocyPack() const;
|
std::shared_ptr<arangodb::velocypack::Builder> warningsToVelocyPack() const;
|
||||||
|
|
||||||
/// @brief fetch the query memory limit
|
|
||||||
static uint64_t MemoryLimit() { return MemoryLimitValue; }
|
|
||||||
|
|
||||||
/// @brief set the query memory limit
|
|
||||||
static void MemoryLimit(uint64_t value) {
|
|
||||||
MemoryLimitValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief fetch the global query tracking value
|
|
||||||
static bool DisableQueryTracking() { return DoDisableQueryTracking; }
|
|
||||||
|
|
||||||
/// @brief turn off tracking globally
|
|
||||||
static void DisableQueryTracking(bool value) {
|
|
||||||
DoDisableQueryTracking = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief whether a warning in an AQL query should raise an error
|
|
||||||
static bool FailOnWarning() { return DoFailOnWarning; }
|
|
||||||
|
|
||||||
static void FailOnWarning(bool value) {
|
|
||||||
DoFailOnWarning = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief fetch the global slow query threshold value
|
|
||||||
static double SlowQueryThreshold() { return SlowQueryThresholdValue; }
|
|
||||||
|
|
||||||
/// @brief set global slow query threshold value
|
|
||||||
static void SlowQueryThreshold(double value) {
|
|
||||||
SlowQueryThresholdValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief get a description of the query's current state
|
/// @brief get a description of the query's current state
|
||||||
std::string getStateString() const;
|
std::string getStateString() const;
|
||||||
|
|
||||||
|
@ -400,7 +365,7 @@ class Query {
|
||||||
/// @brief the currently used V8 context
|
/// @brief the currently used V8 context
|
||||||
V8Context* _context;
|
V8Context* _context;
|
||||||
|
|
||||||
/// @brief warnings collected during execution
|
/// @brief graphs used in query, identified by name
|
||||||
std::unordered_map<std::string, Graph*> _graphs;
|
std::unordered_map<std::string, Graph*> _graphs;
|
||||||
|
|
||||||
/// @brief the actual query string
|
/// @brief the actual query string
|
||||||
|
@ -452,6 +417,8 @@ class Query {
|
||||||
/// @brief query start time
|
/// @brief query start time
|
||||||
double _startTime;
|
double _startTime;
|
||||||
|
|
||||||
|
QueryRegistryFeature const* _queryRegistry;
|
||||||
|
|
||||||
/// @brief the query part
|
/// @brief the query part
|
||||||
QueryPart const _part;
|
QueryPart const _part;
|
||||||
|
|
||||||
|
@ -463,18 +430,6 @@ class Query {
|
||||||
|
|
||||||
/// @brief whether or not the query is a data modification query
|
/// @brief whether or not the query is a data modification query
|
||||||
bool _isModificationQuery;
|
bool _isModificationQuery;
|
||||||
|
|
||||||
/// @brief global memory limit for AQL queries
|
|
||||||
static uint64_t MemoryLimitValue;
|
|
||||||
|
|
||||||
/// @brief global threshold value for slow queries
|
|
||||||
static double SlowQueryThresholdValue;
|
|
||||||
|
|
||||||
/// @brief whether or not query tracking is disabled globally
|
|
||||||
static bool DoDisableQueryTracking;
|
|
||||||
|
|
||||||
/// @brief whether a warning in an AQL query should raise an error
|
|
||||||
static bool DoFailOnWarning;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
/// @author Jan Steemann
|
/// @author Jan Steemann
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "Aql/QueryList.h"
|
#include "QueryList.h"
|
||||||
|
#include "ApplicationFeatures/ApplicationServer.h"
|
||||||
#include "Aql/Query.h"
|
#include "Aql/Query.h"
|
||||||
#include "Aql/QueryProfile.h"
|
#include "Aql/QueryProfile.h"
|
||||||
#include "Basics/ReadLocker.h"
|
#include "Basics/ReadLocker.h"
|
||||||
|
@ -29,8 +30,10 @@
|
||||||
#include "Basics/WriteLocker.h"
|
#include "Basics/WriteLocker.h"
|
||||||
#include "Basics/Exceptions.h"
|
#include "Basics/Exceptions.h"
|
||||||
#include "Logger/Logger.h"
|
#include "Logger/Logger.h"
|
||||||
|
#include "RestServer/QueryRegistryFeature.h"
|
||||||
#include "VocBase/vocbase.h"
|
#include "VocBase/vocbase.h"
|
||||||
|
|
||||||
|
using namespace arangodb;
|
||||||
using namespace arangodb::aql;
|
using namespace arangodb::aql;
|
||||||
|
|
||||||
QueryEntryCopy::QueryEntryCopy(TRI_voc_tick_t id,
|
QueryEntryCopy::QueryEntryCopy(TRI_voc_tick_t id,
|
||||||
|
@ -41,21 +44,17 @@ QueryEntryCopy::QueryEntryCopy(TRI_voc_tick_t id,
|
||||||
: id(id), queryString(std::move(queryString)), bindParameters(bindParameters),
|
: id(id), queryString(std::move(queryString)), bindParameters(bindParameters),
|
||||||
started(started), runTime(runTime), state(state) {}
|
started(started), runTime(runTime), state(state) {}
|
||||||
|
|
||||||
double const QueryList::DefaultSlowQueryThreshold = 10.0;
|
|
||||||
size_t const QueryList::DefaultMaxSlowQueries = 64;
|
|
||||||
size_t const QueryList::DefaultMaxQueryStringLength = 4096;
|
|
||||||
|
|
||||||
/// @brief create a query list
|
/// @brief create a query list
|
||||||
QueryList::QueryList(TRI_vocbase_t*)
|
QueryList::QueryList(TRI_vocbase_t*)
|
||||||
: _lock(),
|
: _lock(),
|
||||||
_current(),
|
_current(),
|
||||||
_slow(),
|
_slow(),
|
||||||
_slowCount(0),
|
_slowCount(0),
|
||||||
_enabled(!Query::DisableQueryTracking()),
|
_enabled(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")->queryTracking()),
|
||||||
_trackSlowQueries(!Query::DisableQueryTracking()),
|
_trackSlowQueries(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")->queryTracking()),
|
||||||
_slowQueryThreshold(Query::SlowQueryThreshold()),
|
_slowQueryThreshold(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")->slowThreshold()),
|
||||||
_maxSlowQueries(QueryList::DefaultMaxSlowQueries),
|
_maxSlowQueries(defaultMaxSlowQueries),
|
||||||
_maxQueryStringLength(QueryList::DefaultMaxQueryStringLength) {
|
_maxQueryStringLength(defaultMaxQueryStringLength) {
|
||||||
_current.reserve(64);
|
_current.reserve(64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,12 @@ class QueryList {
|
||||||
private:
|
private:
|
||||||
std::string extractQueryString(Query const* query, size_t maxLength) const;
|
std::string extractQueryString(Query const* query, size_t maxLength) const;
|
||||||
|
|
||||||
|
/// @brief default maximum number of slow queries to keep in list
|
||||||
|
static constexpr size_t defaultMaxSlowQueries = 64;
|
||||||
|
|
||||||
|
/// @brief default max length of a query when returning it
|
||||||
|
static constexpr size_t defaultMaxQueryStringLength = 4096;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// @brief r/w lock for the list
|
/// @brief r/w lock for the list
|
||||||
arangodb::basics::ReadWriteLock _lock;
|
arangodb::basics::ReadWriteLock _lock;
|
||||||
|
@ -189,15 +195,6 @@ class QueryList {
|
||||||
|
|
||||||
/// @brief max length of query strings to return
|
/// @brief max length of query strings to return
|
||||||
size_t _maxQueryStringLength;
|
size_t _maxQueryStringLength;
|
||||||
|
|
||||||
/// @brief default threshold for slow queries
|
|
||||||
static double const DefaultSlowQueryThreshold;
|
|
||||||
|
|
||||||
/// @brief default maximum number of slow queries to keep in list
|
|
||||||
static size_t const DefaultMaxSlowQueries;
|
|
||||||
|
|
||||||
/// @brief default max length of a query when returning it
|
|
||||||
static size_t const DefaultMaxQueryStringLength;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#include "RestServer/DatabaseFeature.h"
|
#include "RestServer/DatabaseFeature.h"
|
||||||
#include "RestServer/ServerFeature.h"
|
#include "RestServer/ServerFeature.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::application_features;
|
using namespace arangodb::application_features;
|
||||||
using namespace arangodb::options;
|
using namespace arangodb::options;
|
||||||
|
|
|
@ -23,12 +23,15 @@
|
||||||
#include "InitDatabaseFeature.h"
|
#include "InitDatabaseFeature.h"
|
||||||
|
|
||||||
#include "Basics/FileUtils.h"
|
#include "Basics/FileUtils.h"
|
||||||
|
#include "Basics/terminal-utils.h"
|
||||||
#include "Logger/Logger.h"
|
#include "Logger/Logger.h"
|
||||||
#include "Logger/LoggerFeature.h"
|
#include "Logger/LoggerFeature.h"
|
||||||
#include "ProgramOptions/ProgramOptions.h"
|
#include "ProgramOptions/ProgramOptions.h"
|
||||||
#include "ProgramOptions/Section.h"
|
#include "ProgramOptions/Section.h"
|
||||||
#include "RestServer/DatabasePathFeature.h"
|
#include "RestServer/DatabasePathFeature.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::application_features;
|
using namespace arangodb::application_features;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
|
|
|
@ -80,22 +80,7 @@ void QueryRegistryFeature::collectOptions(
|
||||||
new UInt64Parameter(&_queryCacheEntries));
|
new UInt64Parameter(&_queryCacheEntries));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryRegistryFeature::validateOptions(
|
|
||||||
std::shared_ptr<ProgramOptions> options) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void QueryRegistryFeature::prepare() {
|
void QueryRegistryFeature::prepare() {
|
||||||
// set query memory limit
|
|
||||||
arangodb::aql::Query::MemoryLimit(_queryMemoryLimit);
|
|
||||||
|
|
||||||
// set global query tracking flag
|
|
||||||
arangodb::aql::Query::DisableQueryTracking(!_queryTracking);
|
|
||||||
|
|
||||||
arangodb::aql::Query::FailOnWarning(_failOnWarning);
|
|
||||||
|
|
||||||
// set global threshold value for slow queries
|
|
||||||
arangodb::aql::Query::SlowQueryThreshold(_slowThreshold);
|
|
||||||
|
|
||||||
// configure the query cache
|
// configure the query cache
|
||||||
std::pair<std::string, size_t> cacheProperties{_queryCacheMode,
|
std::pair<std::string, size_t> cacheProperties{_queryCacheMode,
|
||||||
_queryCacheEntries};
|
_queryCacheEntries};
|
||||||
|
@ -106,8 +91,7 @@ void QueryRegistryFeature::prepare() {
|
||||||
QUERY_REGISTRY = _queryRegistry.get();
|
QUERY_REGISTRY = _queryRegistry.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryRegistryFeature::start() {
|
void QueryRegistryFeature::start() {}
|
||||||
}
|
|
||||||
|
|
||||||
void QueryRegistryFeature::unprepare() {
|
void QueryRegistryFeature::unprepare() {
|
||||||
// clear the query registery
|
// clear the query registery
|
||||||
|
|
|
@ -39,11 +39,15 @@ class QueryRegistryFeature final : public application_features::ApplicationFeatu
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void collectOptions(std::shared_ptr<options::ProgramOptions>) override final;
|
void collectOptions(std::shared_ptr<options::ProgramOptions>) override final;
|
||||||
void validateOptions(std::shared_ptr<options::ProgramOptions>) override final;
|
|
||||||
void prepare() override final;
|
void prepare() override final;
|
||||||
void start() override final;
|
void start() override final;
|
||||||
void unprepare() override final;
|
void unprepare() override final;
|
||||||
|
|
||||||
|
bool queryTracking() const { return _queryTracking; }
|
||||||
|
bool failOnWarning() const { return _failOnWarning; }
|
||||||
|
uint64_t queryMemoryLimit() const { return _queryMemoryLimit; }
|
||||||
|
double slowThreshold() const { return _slowThreshold; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _queryTracking;
|
bool _queryTracking;
|
||||||
bool _failOnWarning;
|
bool _failOnWarning;
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include "V8Server/V8Context.h"
|
#include "V8Server/V8Context.h"
|
||||||
#include "V8Server/V8DealerFeature.h"
|
#include "V8Server/V8DealerFeature.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::application_features;
|
using namespace arangodb::application_features;
|
||||||
using namespace arangodb::options;
|
using namespace arangodb::options;
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/property_tree/detail/xml_parser_utils.hpp>
|
#include <boost/property_tree/detail/xml_parser_utils.hpp>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "SimpleHttpClient/SimpleHttpClient.h"
|
#include "SimpleHttpClient/SimpleHttpClient.h"
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include "SimpleHttpClient/SimpleHttpClient.h"
|
#include "SimpleHttpClient/SimpleHttpClient.h"
|
||||||
#include "Ssl/ssl-helper.h"
|
#include "Ssl/ssl-helper.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::application_features;
|
using namespace arangodb::application_features;
|
||||||
using namespace arangodb::httpclient;
|
using namespace arangodb::httpclient;
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#include "ProgramOptions/Section.h"
|
#include "ProgramOptions/Section.h"
|
||||||
#include "Shell/ClientFeature.h"
|
#include "Shell/ClientFeature.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
using namespace arangodb::options;
|
using namespace arangodb::options;
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#include "Logger/Logger.h"
|
#include "Logger/Logger.h"
|
||||||
#include "ProgramOptions/ArgumentParser.h"
|
#include "ProgramOptions/ArgumentParser.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace arangodb::application_features;
|
using namespace arangodb::application_features;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
using namespace arangodb::options;
|
using namespace arangodb::options;
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "ProgramOptions/IniFileParser.h"
|
#include "ProgramOptions/IniFileParser.h"
|
||||||
#include "ProgramOptions/ProgramOptions.h"
|
#include "ProgramOptions/ProgramOptions.h"
|
||||||
#include "ProgramOptions/Section.h"
|
#include "ProgramOptions/Section.h"
|
||||||
|
#include "ProgramOptions/Translator.h"
|
||||||
|
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::basics;
|
using namespace arangodb::basics;
|
||||||
|
@ -71,7 +72,7 @@ void ConfigFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
|
||||||
void ConfigFeature::loadOptions(std::shared_ptr<ProgramOptions> options,
|
void ConfigFeature::loadOptions(std::shared_ptr<ProgramOptions> options,
|
||||||
char const* binaryPath) {
|
char const* binaryPath) {
|
||||||
for (auto const& def : _defines) {
|
for (auto const& def : _defines) {
|
||||||
DefineEnvironment(def);
|
arangodb::options::DefineEnvironment(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadConfigFile(options, _progname, binaryPath);
|
loadConfigFile(options, _progname, binaryPath);
|
||||||
|
|
|
@ -188,6 +188,9 @@ add_library(${LIB_ARANGO} STATIC
|
||||||
Logger/LoggerBufferFeature.cpp
|
Logger/LoggerBufferFeature.cpp
|
||||||
Logger/LoggerFeature.cpp
|
Logger/LoggerFeature.cpp
|
||||||
Logger/LoggerStream.cpp
|
Logger/LoggerStream.cpp
|
||||||
|
ProgramOptions/Option.cpp
|
||||||
|
ProgramOptions/ProgramOptions.cpp
|
||||||
|
ProgramOptions/Section.cpp
|
||||||
ProgramOptions/Translator.cpp
|
ProgramOptions/Translator.cpp
|
||||||
Random/RandomFeature.cpp
|
Random/RandomFeature.cpp
|
||||||
Random/RandomGenerator.cpp
|
Random/RandomGenerator.cpp
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include "Basics/FileUtils.h"
|
#include "Basics/FileUtils.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
#include "ProgramOptions/ProgramOptions.h"
|
#include "ProgramOptions/ProgramOptions.h"
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// DISCLAIMER
|
||||||
|
///
|
||||||
|
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// @author Jan Steemann
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "Option.h"
|
||||||
|
|
||||||
|
#include "ProgramOptions/Parameters.h"
|
||||||
|
|
||||||
|
#include <velocypack/Builder.h>
|
||||||
|
#include <velocypack/velocypack-aliases.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace arangodb::options;
|
||||||
|
|
||||||
|
// create an option, consisting of single string
|
||||||
|
Option::Option(std::string const& value, std::string const& description,
|
||||||
|
Parameter* parameter, bool hidden, bool obsolete)
|
||||||
|
: section(),
|
||||||
|
name(),
|
||||||
|
description(description),
|
||||||
|
shorthand(),
|
||||||
|
parameter(parameter),
|
||||||
|
hidden(hidden),
|
||||||
|
obsolete(obsolete) {
|
||||||
|
auto parts = splitName(value);
|
||||||
|
section = parts.first;
|
||||||
|
name = parts.second;
|
||||||
|
|
||||||
|
size_t const pos = name.find(',');
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
shorthand = stripShorthand(name.substr(pos + 1));
|
||||||
|
name = name.substr(0, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Option::toVPack(VPackBuilder& builder) const {
|
||||||
|
parameter->toVPack(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// print help for an option
|
||||||
|
// the special search string "." will show help for all sections, even if hidden
|
||||||
|
void Option::printHelp(std::string const& search, size_t tw, size_t ow, bool) const {
|
||||||
|
if (search == "." || !hidden) {
|
||||||
|
std::cout << " " << pad(nameWithType(), ow) << " ";
|
||||||
|
|
||||||
|
std::string value = description;
|
||||||
|
if (obsolete) {
|
||||||
|
value += " (obsolete option)";
|
||||||
|
} else {
|
||||||
|
std::string description = parameter->description();
|
||||||
|
if (!description.empty()) {
|
||||||
|
value.append(". ");
|
||||||
|
value.append(description);
|
||||||
|
}
|
||||||
|
value += " (default: " + parameter->valueString() + ")";
|
||||||
|
}
|
||||||
|
auto parts = wordwrap(value, tw - ow - 6);
|
||||||
|
size_t const n = parts.size();
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
std::cout << trim(parts[i]) << std::endl;
|
||||||
|
if (i < n - 1) {
|
||||||
|
std::cout << " " << pad("", ow) << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the width of an option help string
|
||||||
|
size_t Option::optionsWidth() const {
|
||||||
|
if (hidden) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nameWithType().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip the "--" from a string
|
||||||
|
std::string Option::stripPrefix(std::string const& name) {
|
||||||
|
size_t pos = name.find("--");
|
||||||
|
if (pos == 0) {
|
||||||
|
// strip initial "--"
|
||||||
|
return name.substr(2);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip the "-" from a string
|
||||||
|
std::string Option::stripShorthand(std::string const& name) {
|
||||||
|
size_t pos = name.find("-");
|
||||||
|
if (pos == 0) {
|
||||||
|
// strip initial "-"
|
||||||
|
return name.substr(1);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// split an option name at the ".", if it exists
|
||||||
|
std::pair<std::string, std::string> Option::splitName(std::string name) {
|
||||||
|
std::string section;
|
||||||
|
name = stripPrefix(name);
|
||||||
|
// split at "."
|
||||||
|
size_t pos = name.find(".");
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
// global option
|
||||||
|
section = "";
|
||||||
|
} else {
|
||||||
|
// section-specific option
|
||||||
|
section = name.substr(0, pos);
|
||||||
|
name = name.substr(pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(section, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> Option::wordwrap(std::string const& value,
|
||||||
|
size_t size) {
|
||||||
|
std::vector<std::string> result;
|
||||||
|
std::string next = value;
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
while (next.size() > size) {
|
||||||
|
size_t m = next.find_last_of("., ", size - 1);
|
||||||
|
|
||||||
|
if (m == std::string::npos || m < size / 2) {
|
||||||
|
m = size;
|
||||||
|
} else {
|
||||||
|
m += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.emplace_back(next.substr(0, m));
|
||||||
|
next = next.substr(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.emplace_back(next);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// right-pad a string
|
||||||
|
std::string Option::pad(std::string const& value, size_t length) {
|
||||||
|
size_t const valueLength = value.size();
|
||||||
|
if (valueLength > length) {
|
||||||
|
return value.substr(0, length);
|
||||||
|
}
|
||||||
|
if (valueLength == length) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return value + std::string(length - valueLength, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Option::trim(std::string const& value) {
|
||||||
|
size_t const pos = value.find_first_not_of(" \t\n\r");
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return value.substr(pos);
|
||||||
|
}
|
|
@ -27,41 +27,21 @@
|
||||||
#include "ProgramOptions/Parameters.h"
|
#include "ProgramOptions/Parameters.h"
|
||||||
|
|
||||||
#include <velocypack/Builder.h>
|
#include <velocypack/Builder.h>
|
||||||
#include <velocypack/velocypack-aliases.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
namespace options {
|
namespace options {
|
||||||
|
|
||||||
|
struct Parameter;
|
||||||
|
|
||||||
// a single program option container
|
// a single program option container
|
||||||
struct Option {
|
struct Option {
|
||||||
// options are default copy-constructible and default movable
|
// options are default copy-constructible and default movable
|
||||||
|
|
||||||
// create an option, consisting of single string
|
// create an option, consisting of single string
|
||||||
Option(std::string const& value, std::string const& description,
|
Option(std::string const& value, std::string const& description,
|
||||||
Parameter* parameter, bool hidden, bool obsolete)
|
Parameter* parameter, bool hidden, bool obsolete);
|
||||||
: section(),
|
|
||||||
name(),
|
|
||||||
description(description),
|
|
||||||
shorthand(),
|
|
||||||
parameter(parameter),
|
|
||||||
hidden(hidden),
|
|
||||||
obsolete(obsolete) {
|
|
||||||
auto parts = splitName(value);
|
|
||||||
section = parts.first;
|
|
||||||
name = parts.second;
|
|
||||||
|
|
||||||
size_t const pos = name.find(',');
|
void toVPack(arangodb::velocypack::Builder& builder) const;
|
||||||
if (pos != std::string::npos) {
|
|
||||||
shorthand = stripShorthand(name.substr(pos + 1));
|
|
||||||
name = name.substr(0, pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void toVPack(VPackBuilder& builder) const {
|
|
||||||
parameter->toVPack(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get display name for the option
|
// get display name for the option
|
||||||
std::string displayName() const { return "--" + fullName(); }
|
std::string displayName() const { return "--" + fullName(); }
|
||||||
|
@ -76,127 +56,31 @@ struct Option {
|
||||||
|
|
||||||
// print help for an option
|
// print help for an option
|
||||||
// the special search string "." will show help for all sections, even if hidden
|
// the special search string "." will show help for all sections, even if hidden
|
||||||
void printHelp(std::string const& search, size_t tw, size_t ow, bool) const {
|
void printHelp(std::string const& search, size_t tw, size_t ow, bool) const;
|
||||||
if (search == "." || !hidden) {
|
|
||||||
std::cout << " " << pad(nameWithType(), ow) << " ";
|
|
||||||
|
|
||||||
std::string value = description;
|
|
||||||
if (obsolete) {
|
|
||||||
value += " (obsolete option)";
|
|
||||||
} else {
|
|
||||||
std::string description = parameter->description();
|
|
||||||
if (!description.empty()) {
|
|
||||||
value.append(". ");
|
|
||||||
value.append(description);
|
|
||||||
}
|
|
||||||
value += " (default: " + parameter->valueString() + ")";
|
|
||||||
}
|
|
||||||
auto parts = wordwrap(value, tw - ow - 6);
|
|
||||||
size_t const n = parts.size();
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
std::cout << trim(parts[i]) << std::endl;
|
|
||||||
if (i < n - 1) {
|
|
||||||
std::cout << " " << pad("", ow) << " ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string nameWithType() const {
|
std::string nameWithType() const {
|
||||||
return displayName() + " " + parameter->typeDescription();
|
return displayName() + " " + parameter->typeDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine the width of an option help string
|
// determine the width of an option help string
|
||||||
size_t optionsWidth() const {
|
size_t optionsWidth() const;
|
||||||
if (hidden) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nameWithType().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// strip the "--" from a string
|
// strip the "--" from a string
|
||||||
static std::string stripPrefix(std::string const& name) {
|
static std::string stripPrefix(std::string const& name);
|
||||||
size_t pos = name.find("--");
|
|
||||||
if (pos == 0) {
|
|
||||||
// strip initial "--"
|
|
||||||
return name.substr(2);
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// strip the "-" from a string
|
// strip the "-" from a string
|
||||||
static std::string stripShorthand(std::string const& name) {
|
static std::string stripShorthand(std::string const& name);
|
||||||
size_t pos = name.find("-");
|
|
||||||
if (pos == 0) {
|
|
||||||
// strip initial "-"
|
|
||||||
return name.substr(1);
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// split an option name at the ".", if it exists
|
// split an option name at the ".", if it exists
|
||||||
static std::pair<std::string, std::string> splitName(std::string name) {
|
static std::pair<std::string, std::string> splitName(std::string name);
|
||||||
std::string section;
|
|
||||||
name = stripPrefix(name);
|
|
||||||
// split at "."
|
|
||||||
size_t pos = name.find(".");
|
|
||||||
if (pos == std::string::npos) {
|
|
||||||
// global option
|
|
||||||
section = "";
|
|
||||||
} else {
|
|
||||||
// section-specific option
|
|
||||||
section = name.substr(0, pos);
|
|
||||||
name = name.substr(pos + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(section, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<std::string> wordwrap(std::string const& value,
|
static std::vector<std::string> wordwrap(std::string const& value,
|
||||||
size_t size) {
|
size_t size);
|
||||||
std::vector<std::string> result;
|
|
||||||
std::string next = value;
|
|
||||||
|
|
||||||
if (size > 0) {
|
|
||||||
while (next.size() > size) {
|
|
||||||
size_t m = next.find_last_of("., ", size - 1);
|
|
||||||
|
|
||||||
if (m == std::string::npos || m < size / 2) {
|
|
||||||
m = size;
|
|
||||||
} else {
|
|
||||||
m += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.emplace_back(next.substr(0, m));
|
|
||||||
next = next.substr(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.emplace_back(next);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// right-pad a string
|
// right-pad a string
|
||||||
static std::string pad(std::string const& value, size_t length) {
|
static std::string pad(std::string const& value, size_t length);
|
||||||
size_t const valueLength = value.size();
|
|
||||||
if (valueLength > length) {
|
|
||||||
return value.substr(0, length);
|
|
||||||
}
|
|
||||||
if (valueLength == length) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return value + std::string(length - valueLength, ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string trim(std::string const& value) {
|
static std::string trim(std::string const& value);
|
||||||
size_t const pos = value.find_first_not_of(" \t\n\r");
|
|
||||||
if (pos == std::string::npos) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return value.substr(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string section;
|
std::string section;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
|
@ -0,0 +1,444 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// DISCLAIMER
|
||||||
|
///
|
||||||
|
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// @author Jan Steemann
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "ProgramOptions.h"
|
||||||
|
#include "Basics/levenshtein.h"
|
||||||
|
#include "Basics/shell-colors.h"
|
||||||
|
#include "Basics/terminal-utils.h"
|
||||||
|
#include "ProgramOptions/Option.h"
|
||||||
|
#include "ProgramOptions/Section.h"
|
||||||
|
#include "ProgramOptions/Translator.h"
|
||||||
|
|
||||||
|
#include <velocypack/Builder.h>
|
||||||
|
#include <velocypack/velocypack-aliases.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define ARANGODB_PROGRAM_OPTIONS_PROGNAME "#progname#"
|
||||||
|
|
||||||
|
using namespace arangodb::options;
|
||||||
|
|
||||||
|
ProgramOptions::ProgramOptions(char const* progname, std::string const& usage,
|
||||||
|
std::string const& more,
|
||||||
|
char const* binaryPath)
|
||||||
|
: _progname(progname),
|
||||||
|
_usage(usage),
|
||||||
|
_more(more),
|
||||||
|
_terminalWidth(TRI_ColumnsWidth),
|
||||||
|
_similarity(TRI_Levenshtein),
|
||||||
|
_processingResult(),
|
||||||
|
_sealed(false),
|
||||||
|
_overrideOptions(false),
|
||||||
|
_binaryPath(binaryPath){
|
||||||
|
// find progname wildcard in string
|
||||||
|
size_t const pos = _usage.find(ARANGODB_PROGRAM_OPTIONS_PROGNAME);
|
||||||
|
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
// and replace it with actual program name
|
||||||
|
_usage = usage.substr(0, pos) + _progname +
|
||||||
|
_usage.substr(pos + strlen(ARANGODB_PROGRAM_OPTIONS_PROGNAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
_translator = EnvironmentTranslator;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets a value translator
|
||||||
|
void ProgramOptions::setTranslator(
|
||||||
|
std::function<std::string(std::string const&, char const*)> translator) {
|
||||||
|
_translator = translator;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prints usage information
|
||||||
|
void ProgramOptions::printUsage() const { std::cout << _usage << std::endl << std::endl; }
|
||||||
|
|
||||||
|
// prints a help for all options, or the options of a section
|
||||||
|
// the special search string "*" will show help for all sections
|
||||||
|
// the special search string "." will show help for all sections, even if
|
||||||
|
// hidden
|
||||||
|
void ProgramOptions::printHelp(std::string const& search) const {
|
||||||
|
bool const colors = (isatty(STDOUT_FILENO) != 0);
|
||||||
|
printUsage();
|
||||||
|
|
||||||
|
size_t const tw = _terminalWidth();
|
||||||
|
size_t const ow = optionsWidth();
|
||||||
|
|
||||||
|
for (auto const& it : _sections) {
|
||||||
|
if (search == "*" || search == "." || search == it.second.name) {
|
||||||
|
it.second.printHelp(search, tw, ow, colors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (search == "*") {
|
||||||
|
printSectionsHelp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prints the names for all section help options
|
||||||
|
void ProgramOptions::printSectionsHelp() const {
|
||||||
|
char const* colorStart;
|
||||||
|
char const* colorEnd;
|
||||||
|
|
||||||
|
if (isatty(STDOUT_FILENO)) {
|
||||||
|
colorStart = TRI_SHELL_COLOR_BRIGHT;
|
||||||
|
colorEnd = TRI_SHELL_COLOR_RESET;
|
||||||
|
} else {
|
||||||
|
colorStart = colorEnd = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// print names of sections
|
||||||
|
std::cout << _more;
|
||||||
|
for (auto const& it : _sections) {
|
||||||
|
if (!it.second.name.empty() && it.second.hasOptions()) {
|
||||||
|
std::cout << " " << colorStart << "--help-" << it.second.name
|
||||||
|
<< colorEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a VPack representation of the option values
|
||||||
|
VPackBuilder ProgramOptions::toVPack(bool onlyTouched,
|
||||||
|
std::unordered_set<std::string> const& exclude) const {
|
||||||
|
VPackBuilder builder;
|
||||||
|
builder.openObject();
|
||||||
|
|
||||||
|
walk(
|
||||||
|
[&builder, &exclude](Section const&, Option const& option) {
|
||||||
|
std::string full(option.fullName());
|
||||||
|
if (exclude.find(full) != exclude.end()) {
|
||||||
|
// excluded option
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add key
|
||||||
|
builder.add(VPackValue(full));
|
||||||
|
|
||||||
|
// add value
|
||||||
|
option.toVPack(builder);
|
||||||
|
},
|
||||||
|
onlyTouched);
|
||||||
|
|
||||||
|
builder.close();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate a shorthand option
|
||||||
|
std::string ProgramOptions::translateShorthand(std::string const& name) const {
|
||||||
|
auto it = _shorthands.find(name);
|
||||||
|
|
||||||
|
if (it == _shorthands.end()) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
return (*it).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgramOptions::walk(std::function<void(Section const&, Option const&)> const& callback,
|
||||||
|
bool onlyTouched) const {
|
||||||
|
for (auto const& it : _sections) {
|
||||||
|
if (it.second.obsolete) {
|
||||||
|
// obsolete section. ignore it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (auto const& it2 : it.second.options) {
|
||||||
|
if (it2.second.obsolete) {
|
||||||
|
// obsolete option. ignore it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (onlyTouched && !_processingResult.touched(it2.second.fullName())) {
|
||||||
|
// option not touched. skip over it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
callback(it.second, it2.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks whether a specific option exists
|
||||||
|
// if the option does not exist, this will flag an error
|
||||||
|
bool ProgramOptions::require(std::string const& name) {
|
||||||
|
auto parts = Option::splitName(name);
|
||||||
|
auto it = _sections.find(parts.first);
|
||||||
|
|
||||||
|
if (it == _sections.end()) {
|
||||||
|
return unknownOption(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it2 = (*it).second.options.find(parts.second);
|
||||||
|
|
||||||
|
if (it2 == (*it).second.options.end()) {
|
||||||
|
return unknownOption(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets a value for an option
|
||||||
|
bool ProgramOptions::setValue(std::string const& name, std::string const& value) {
|
||||||
|
if (!_overrideOptions && _processingResult.frozen(name)) {
|
||||||
|
// option already frozen. don't override it
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parts = Option::splitName(name);
|
||||||
|
auto it = _sections.find(parts.first);
|
||||||
|
|
||||||
|
if (it == _sections.end()) {
|
||||||
|
return unknownOption(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*it).second.obsolete) {
|
||||||
|
// section is obsolete. ignore it
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it2 = (*it).second.options.find(parts.second);
|
||||||
|
|
||||||
|
if (it2 == (*it).second.options.end()) {
|
||||||
|
return unknownOption(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& option = (*it2).second;
|
||||||
|
if (option.obsolete) {
|
||||||
|
// option is obsolete. ignore it
|
||||||
|
_processingResult.touch(name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string result = option.parameter->set(_translator(value, _binaryPath));
|
||||||
|
|
||||||
|
if (!result.empty()) {
|
||||||
|
// parameter validation failed
|
||||||
|
return fail("error setting value for option '--" + name + "': " + result);
|
||||||
|
}
|
||||||
|
|
||||||
|
_processingResult.touch(name);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// finalizes a pass, copying touched into frozen
|
||||||
|
void ProgramOptions::endPass() {
|
||||||
|
if (_overrideOptions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto const& it : _processingResult._touched) {
|
||||||
|
_processingResult.freeze(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether or not an option requires a value
|
||||||
|
bool ProgramOptions::requiresValue(std::string const& name) const {
|
||||||
|
auto parts = Option::splitName(name);
|
||||||
|
auto it = _sections.find(parts.first);
|
||||||
|
|
||||||
|
if (it == _sections.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it2 = (*it).second.options.find(parts.second);
|
||||||
|
|
||||||
|
if (it2 == (*it).second.options.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (*it2).second.parameter->requiresValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns an option description
|
||||||
|
std::string ProgramOptions::getDescription(std::string const& name) {
|
||||||
|
auto parts = Option::splitName(name);
|
||||||
|
auto it = _sections.find(parts.first);
|
||||||
|
|
||||||
|
if (it == _sections.end()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it2 = (*it).second.options.find(parts.second);
|
||||||
|
|
||||||
|
if (it2 == (*it).second.options.end()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return (*it2).second.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle an unknown option
|
||||||
|
bool ProgramOptions::unknownOption(std::string const& name) {
|
||||||
|
char const* colorStart;
|
||||||
|
char const* colorEnd;
|
||||||
|
|
||||||
|
if (isatty(STDERR_FILENO)) {
|
||||||
|
colorStart = TRI_SHELL_COLOR_BRIGHT;
|
||||||
|
colorEnd = TRI_SHELL_COLOR_RESET;
|
||||||
|
} else {
|
||||||
|
colorStart = colorEnd = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
fail(std::string("unknown option '") + colorStart + "--" + name + colorEnd +
|
||||||
|
"'");
|
||||||
|
|
||||||
|
auto similarOptions = similar(name, 8, 4);
|
||||||
|
if (!similarOptions.empty()) {
|
||||||
|
if (similarOptions.size() == 1) {
|
||||||
|
std::cerr << "Did you mean this?" << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cerr << "Did you mean one of these?" << std::endl;
|
||||||
|
}
|
||||||
|
// determine maximum width
|
||||||
|
size_t maxWidth = 0;
|
||||||
|
for (auto const& it : similarOptions) {
|
||||||
|
maxWidth = (std::max)(maxWidth, it.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& it : similarOptions) {
|
||||||
|
std::cerr << " " << colorStart << Option::pad(it, maxWidth) << colorEnd
|
||||||
|
<< " " << getDescription(it) << std::endl;
|
||||||
|
}
|
||||||
|
std::cerr << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = _oldOptions.find(name);
|
||||||
|
if (it != _oldOptions.end()) {
|
||||||
|
// a now removed or renamed option was specified...
|
||||||
|
auto& now = (*it).second;
|
||||||
|
if (now.empty()) {
|
||||||
|
std::cerr << "Please note that the specified option '" << colorStart
|
||||||
|
<< "--" << name << colorEnd
|
||||||
|
<< "' has been removed in this ArangoDB version";
|
||||||
|
} else {
|
||||||
|
std::cerr << "Please note that the specified option '" << colorStart
|
||||||
|
<< "--" << name << colorEnd << "' has been renamed to '--"
|
||||||
|
<< colorStart << now << colorEnd
|
||||||
|
<< "' in this ArangoDB version";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr
|
||||||
|
<< std::endl
|
||||||
|
<< "Please be sure to read the manual section about changed options"
|
||||||
|
<< std::endl
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Use " << colorStart << "--help" << colorEnd << " or "
|
||||||
|
<< colorStart << "--help-all" << colorEnd
|
||||||
|
<< " to get an overview of available options" << std::endl
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// report an error (callback from parser)
|
||||||
|
bool ProgramOptions::fail(std::string const& message) {
|
||||||
|
_processingResult.failed(true);
|
||||||
|
std::cerr << "Error while processing " << _context << ":" << std::endl;
|
||||||
|
failNotice(message);
|
||||||
|
std::cerr << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgramOptions::failNotice(std::string const& message) {
|
||||||
|
_processingResult.failed(true);
|
||||||
|
std::cerr << " " << message << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a positional argument (callback from parser)
|
||||||
|
void ProgramOptions::addPositional(std::string const& value) {
|
||||||
|
_processingResult._positionals.emplace_back(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// adds an option to the list of options
|
||||||
|
void ProgramOptions::addOption(Option const& option) {
|
||||||
|
checkIfSealed();
|
||||||
|
auto it = _sections.find(option.section);
|
||||||
|
|
||||||
|
if (it == _sections.end()) {
|
||||||
|
throw std::logic_error(
|
||||||
|
std::string("no section defined for program option ") +
|
||||||
|
option.displayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!option.shorthand.empty()) {
|
||||||
|
if (!_shorthands.emplace(option.shorthand, option.fullName()).second) {
|
||||||
|
throw std::logic_error(
|
||||||
|
std::string("shorthand option already defined for option ") +
|
||||||
|
option.displayName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(*it).second.options.emplace(option.name, option);
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine maximum width of all options labels
|
||||||
|
size_t ProgramOptions::optionsWidth() const {
|
||||||
|
size_t width = 0;
|
||||||
|
for (auto const& it : _sections) {
|
||||||
|
width = (std::max)(width, it.second.optionsWidth());
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the options are already sealed and throw if yes
|
||||||
|
void ProgramOptions::checkIfSealed() const {
|
||||||
|
if (_sealed) {
|
||||||
|
throw std::logic_error("program options are already sealed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a list of similar options
|
||||||
|
std::vector<std::string> ProgramOptions::similar(std::string const& value, int cutOff,
|
||||||
|
size_t maxResults) {
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
if (_similarity != nullptr) {
|
||||||
|
// build a sorted map of similar values first
|
||||||
|
std::multimap<int, std::string> distances;
|
||||||
|
// walk over all options
|
||||||
|
walk(
|
||||||
|
[this, &value, &distances](Section const&, Option const& option) {
|
||||||
|
if (option.fullName() != value) {
|
||||||
|
distances.emplace(_similarity(value, option.fullName()),
|
||||||
|
option.displayName());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false);
|
||||||
|
|
||||||
|
// now return the ones that have an edit distance not higher than the
|
||||||
|
// cutOff value
|
||||||
|
int last = 0;
|
||||||
|
for (auto const& it : distances) {
|
||||||
|
if (last > 1 && it.first > 2 * last) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (it.first > cutOff) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.emplace_back(it.second);
|
||||||
|
if (result.size() >= maxResults) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last = it.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -25,16 +25,10 @@
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
|
|
||||||
#include <velocypack/Builder.h>
|
|
||||||
#include <velocypack/velocypack-aliases.h>
|
|
||||||
|
|
||||||
#include "Basics/levenshtein.h"
|
|
||||||
#include "Basics/terminal-utils.h"
|
|
||||||
#include "ProgramOptions/Option.h"
|
#include "ProgramOptions/Option.h"
|
||||||
#include "ProgramOptions/Section.h"
|
#include "ProgramOptions/Section.h"
|
||||||
#include "ProgramOptions/Translator.h"
|
|
||||||
|
|
||||||
#define ARANGODB_PROGRAM_OPTIONS_PROGNAME "#progname#"
|
#include <velocypack/Builder.h>
|
||||||
|
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
namespace options {
|
namespace options {
|
||||||
|
@ -102,35 +96,11 @@ class ProgramOptions {
|
||||||
|
|
||||||
ProgramOptions(char const* progname, std::string const& usage,
|
ProgramOptions(char const* progname, std::string const& usage,
|
||||||
std::string const& more,
|
std::string const& more,
|
||||||
const char *binaryPath,
|
char const* binaryPath);
|
||||||
TerminalWidthFuncType const& terminalWidth = TRI_ColumnsWidth,
|
|
||||||
SimilarityFuncType const& similarity = TRI_Levenshtein)
|
|
||||||
: _progname(progname),
|
|
||||||
_usage(usage),
|
|
||||||
_more(more),
|
|
||||||
_terminalWidth(terminalWidth),
|
|
||||||
_similarity(similarity),
|
|
||||||
_processingResult(),
|
|
||||||
_sealed(false),
|
|
||||||
_overrideOptions(false),
|
|
||||||
_binaryPath(binaryPath){
|
|
||||||
// find progname wildcard in string
|
|
||||||
size_t const pos = _usage.find(ARANGODB_PROGRAM_OPTIONS_PROGNAME);
|
|
||||||
|
|
||||||
if (pos != std::string::npos) {
|
|
||||||
// and replace it with actual program name
|
|
||||||
_usage = usage.substr(0, pos) + _progname +
|
|
||||||
_usage.substr(pos + strlen(ARANGODB_PROGRAM_OPTIONS_PROGNAME));
|
|
||||||
}
|
|
||||||
|
|
||||||
_translator = EnvironmentTranslator;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets a value translator
|
// sets a value translator
|
||||||
void setTranslator(
|
void setTranslator(
|
||||||
std::function<std::string(std::string const&, char const*)> translator) {
|
std::function<std::string(std::string const&, char const*)> translator);
|
||||||
_translator = translator;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return a const reference to the processing result
|
// return a const reference to the processing result
|
||||||
ProcessingResult const& processingResult() const { return _processingResult; }
|
ProcessingResult const& processingResult() const { return _processingResult; }
|
||||||
|
@ -205,201 +175,40 @@ class ProgramOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
// prints usage information
|
// prints usage information
|
||||||
void printUsage() const { std::cout << _usage << std::endl << std::endl; }
|
void printUsage() const;
|
||||||
|
|
||||||
// prints a help for all options, or the options of a section
|
// prints a help for all options, or the options of a section
|
||||||
// the special search string "*" will show help for all sections
|
// the special search string "*" will show help for all sections
|
||||||
// the special search string "." will show help for all sections, even if
|
// the special search string "." will show help for all sections, even if
|
||||||
// hidden
|
// hidden
|
||||||
void printHelp(std::string const& search) const {
|
void printHelp(std::string const& search) const;
|
||||||
bool const colors = (isatty(STDOUT_FILENO) != 0);
|
|
||||||
printUsage();
|
|
||||||
|
|
||||||
size_t const tw = _terminalWidth();
|
|
||||||
size_t const ow = optionsWidth();
|
|
||||||
|
|
||||||
for (auto const& it : _sections) {
|
|
||||||
if (search == "*" || search == "." || search == it.second.name) {
|
|
||||||
it.second.printHelp(search, tw, ow, colors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (search == "*") {
|
|
||||||
printSectionsHelp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// prints the names for all section help options
|
// prints the names for all section help options
|
||||||
void printSectionsHelp() const {
|
void printSectionsHelp() const;
|
||||||
char const* colorStart;
|
|
||||||
char const* colorEnd;
|
|
||||||
|
|
||||||
if (isatty(STDOUT_FILENO)) {
|
|
||||||
colorStart = TRI_SHELL_COLOR_BRIGHT;
|
|
||||||
colorEnd = TRI_SHELL_COLOR_RESET;
|
|
||||||
} else {
|
|
||||||
colorStart = colorEnd = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// print names of sections
|
|
||||||
std::cout << _more;
|
|
||||||
for (auto const& it : _sections) {
|
|
||||||
if (!it.second.name.empty() && it.second.hasOptions()) {
|
|
||||||
std::cout << " " << colorStart << "--help-" << it.second.name
|
|
||||||
<< colorEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns a VPack representation of the option values
|
// returns a VPack representation of the option values
|
||||||
VPackBuilder toVPack(bool onlyTouched,
|
arangodb::velocypack::Builder toVPack(bool onlyTouched,
|
||||||
std::unordered_set<std::string> const& exclude) const {
|
std::unordered_set<std::string> const& exclude) const;
|
||||||
VPackBuilder builder;
|
|
||||||
builder.openObject();
|
|
||||||
|
|
||||||
walk(
|
|
||||||
[&builder, &exclude](Section const&, Option const& option) {
|
|
||||||
std::string full(option.fullName());
|
|
||||||
if (exclude.find(full) != exclude.end()) {
|
|
||||||
// excluded option
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add key
|
|
||||||
builder.add(VPackValue(full));
|
|
||||||
|
|
||||||
// add value
|
|
||||||
option.toVPack(builder);
|
|
||||||
},
|
|
||||||
onlyTouched);
|
|
||||||
|
|
||||||
builder.close();
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
// translate a shorthand option
|
// translate a shorthand option
|
||||||
std::string translateShorthand(std::string const& name) const {
|
std::string translateShorthand(std::string const& name) const;
|
||||||
auto it = _shorthands.find(name);
|
|
||||||
|
|
||||||
if (it == _shorthands.end()) {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
return (*it).second;
|
|
||||||
}
|
|
||||||
|
|
||||||
void walk(std::function<void(Section const&, Option const&)> const& callback,
|
void walk(std::function<void(Section const&, Option const&)> const& callback,
|
||||||
bool onlyTouched) const {
|
bool onlyTouched) const;
|
||||||
for (auto const& it : _sections) {
|
|
||||||
if (it.second.obsolete) {
|
|
||||||
// obsolete section. ignore it
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (auto const& it2 : it.second.options) {
|
|
||||||
if (it2.second.obsolete) {
|
|
||||||
// obsolete option. ignore it
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (onlyTouched && !_processingResult.touched(it2.second.fullName())) {
|
|
||||||
// option not touched. skip over it
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
callback(it.second, it2.second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks whether a specific option exists
|
// checks whether a specific option exists
|
||||||
// if the option does not exist, this will flag an error
|
// if the option does not exist, this will flag an error
|
||||||
bool require(std::string const& name) {
|
bool require(std::string const& name);
|
||||||
auto parts = Option::splitName(name);
|
|
||||||
auto it = _sections.find(parts.first);
|
|
||||||
|
|
||||||
if (it == _sections.end()) {
|
|
||||||
return unknownOption(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it2 = (*it).second.options.find(parts.second);
|
|
||||||
|
|
||||||
if (it2 == (*it).second.options.end()) {
|
|
||||||
return unknownOption(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets a value for an option
|
// sets a value for an option
|
||||||
bool setValue(std::string const& name, std::string const& value) {
|
bool setValue(std::string const& name, std::string const& value);
|
||||||
if (!_overrideOptions && _processingResult.frozen(name)) {
|
|
||||||
// option already frozen. don't override it
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto parts = Option::splitName(name);
|
|
||||||
auto it = _sections.find(parts.first);
|
|
||||||
|
|
||||||
if (it == _sections.end()) {
|
|
||||||
return unknownOption(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((*it).second.obsolete) {
|
|
||||||
// section is obsolete. ignore it
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it2 = (*it).second.options.find(parts.second);
|
|
||||||
|
|
||||||
if (it2 == (*it).second.options.end()) {
|
|
||||||
return unknownOption(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& option = (*it2).second;
|
|
||||||
if (option.obsolete) {
|
|
||||||
// option is obsolete. ignore it
|
|
||||||
_processingResult.touch(name);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string result = option.parameter->set(_translator(value, _binaryPath));
|
|
||||||
|
|
||||||
if (!result.empty()) {
|
|
||||||
// parameter validation failed
|
|
||||||
return fail("error setting value for option '--" + name + "': " + result);
|
|
||||||
}
|
|
||||||
|
|
||||||
_processingResult.touch(name);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// finalizes a pass, copying touched into frozen
|
// finalizes a pass, copying touched into frozen
|
||||||
void endPass() {
|
void endPass();
|
||||||
if (_overrideOptions) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (auto const& it : _processingResult._touched) {
|
|
||||||
_processingResult.freeze(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check whether or not an option requires a value
|
// check whether or not an option requires a value
|
||||||
bool requiresValue(std::string const& name) const {
|
bool requiresValue(std::string const& name) const;
|
||||||
auto parts = Option::splitName(name);
|
|
||||||
auto it = _sections.find(parts.first);
|
|
||||||
|
|
||||||
if (it == _sections.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it2 = (*it).second.options.find(parts.second);
|
|
||||||
|
|
||||||
if (it2 == (*it).second.options.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (*it2).second.parameter->requiresValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns a pointer to an option value, specified by option name
|
// returns a pointer to an option value, specified by option name
|
||||||
// returns a nullptr if the option is unknown
|
// returns a nullptr if the option is unknown
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -423,184 +232,32 @@ class ProgramOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns an option description
|
// returns an option description
|
||||||
std::string getDescription(std::string const& name) {
|
std::string getDescription(std::string const& name);
|
||||||
auto parts = Option::splitName(name);
|
|
||||||
auto it = _sections.find(parts.first);
|
|
||||||
|
|
||||||
if (it == _sections.end()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it2 = (*it).second.options.find(parts.second);
|
|
||||||
|
|
||||||
if (it2 == (*it).second.options.end()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return (*it2).second.description;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle an unknown option
|
// handle an unknown option
|
||||||
bool unknownOption(std::string const& name) {
|
bool unknownOption(std::string const& name);
|
||||||
char const* colorStart;
|
|
||||||
char const* colorEnd;
|
|
||||||
|
|
||||||
if (isatty(STDERR_FILENO)) {
|
|
||||||
colorStart = TRI_SHELL_COLOR_BRIGHT;
|
|
||||||
colorEnd = TRI_SHELL_COLOR_RESET;
|
|
||||||
} else {
|
|
||||||
colorStart = colorEnd = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
fail(std::string("unknown option '") + colorStart + "--" + name + colorEnd +
|
|
||||||
"'");
|
|
||||||
|
|
||||||
auto similarOptions = similar(name, 8, 4);
|
|
||||||
if (!similarOptions.empty()) {
|
|
||||||
if (similarOptions.size() == 1) {
|
|
||||||
std::cerr << "Did you mean this?" << std::endl;
|
|
||||||
} else {
|
|
||||||
std::cerr << "Did you mean one of these?" << std::endl;
|
|
||||||
}
|
|
||||||
// determine maximum width
|
|
||||||
size_t maxWidth = 0;
|
|
||||||
for (auto const& it : similarOptions) {
|
|
||||||
maxWidth = (std::max)(maxWidth, it.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const& it : similarOptions) {
|
|
||||||
std::cerr << " " << colorStart << Option::pad(it, maxWidth) << colorEnd
|
|
||||||
<< " " << getDescription(it) << std::endl;
|
|
||||||
}
|
|
||||||
std::cerr << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it = _oldOptions.find(name);
|
|
||||||
if (it != _oldOptions.end()) {
|
|
||||||
// a now removed or renamed option was specified...
|
|
||||||
auto& now = (*it).second;
|
|
||||||
if (now.empty()) {
|
|
||||||
std::cerr << "Please note that the specified option '" << colorStart
|
|
||||||
<< "--" << name << colorEnd
|
|
||||||
<< "' has been removed in this ArangoDB version";
|
|
||||||
} else {
|
|
||||||
std::cerr << "Please note that the specified option '" << colorStart
|
|
||||||
<< "--" << name << colorEnd << "' has been renamed to '--"
|
|
||||||
<< colorStart << now << colorEnd
|
|
||||||
<< "' in this ArangoDB version";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr
|
|
||||||
<< std::endl
|
|
||||||
<< "Please be sure to read the manual section about changed options"
|
|
||||||
<< std::endl
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << "Use " << colorStart << "--help" << colorEnd << " or "
|
|
||||||
<< colorStart << "--help-all" << colorEnd
|
|
||||||
<< " to get an overview of available options" << std::endl
|
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// report an error (callback from parser)
|
// report an error (callback from parser)
|
||||||
bool fail(std::string const& message) {
|
bool fail(std::string const& message);
|
||||||
_processingResult.failed(true);
|
|
||||||
std::cerr << "Error while processing " << _context << ":" << std::endl;
|
|
||||||
failNotice(message);
|
|
||||||
std::cerr << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void failNotice(std::string const& message) {
|
void failNotice(std::string const& message);
|
||||||
_processingResult.failed(true);
|
|
||||||
std::cerr << " " << message << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add a positional argument (callback from parser)
|
// add a positional argument (callback from parser)
|
||||||
void addPositional(std::string const& value) {
|
void addPositional(std::string const& value);
|
||||||
_processingResult._positionals.emplace_back(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// adds an option to the list of options
|
// adds an option to the list of options
|
||||||
void addOption(Option const& option) {
|
void addOption(Option const& option);
|
||||||
checkIfSealed();
|
|
||||||
auto it = _sections.find(option.section);
|
|
||||||
|
|
||||||
if (it == _sections.end()) {
|
|
||||||
throw std::logic_error(
|
|
||||||
std::string("no section defined for program option ") +
|
|
||||||
option.displayName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!option.shorthand.empty()) {
|
|
||||||
if (!_shorthands.emplace(option.shorthand, option.fullName()).second) {
|
|
||||||
throw std::logic_error(
|
|
||||||
std::string("shorthand option already defined for option ") +
|
|
||||||
option.displayName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(*it).second.options.emplace(option.name, option);
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine maximum width of all options labels
|
// determine maximum width of all options labels
|
||||||
size_t optionsWidth() const {
|
size_t optionsWidth() const;
|
||||||
size_t width = 0;
|
|
||||||
for (auto const& it : _sections) {
|
|
||||||
width = (std::max)(width, it.second.optionsWidth());
|
|
||||||
}
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the options are already sealed and throw if yes
|
// check if the options are already sealed and throw if yes
|
||||||
void checkIfSealed() const {
|
void checkIfSealed() const;
|
||||||
if (_sealed) {
|
|
||||||
throw std::logic_error("program options are already sealed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get a list of similar options
|
// get a list of similar options
|
||||||
std::vector<std::string> similar(std::string const& value, int cutOff,
|
std::vector<std::string> similar(std::string const& value, int cutOff,
|
||||||
size_t maxResults) {
|
size_t maxResults);
|
||||||
std::vector<std::string> result;
|
|
||||||
|
|
||||||
if (_similarity != nullptr) {
|
|
||||||
// build a sorted map of similar values first
|
|
||||||
std::multimap<int, std::string> distances;
|
|
||||||
// walk over all options
|
|
||||||
walk(
|
|
||||||
[this, &value, &distances](Section const&, Option const& option) {
|
|
||||||
if (option.fullName() != value) {
|
|
||||||
distances.emplace(_similarity(value, option.fullName()),
|
|
||||||
option.displayName());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
|
|
||||||
// now return the ones that have an edit distance not higher than the
|
|
||||||
// cutOff value
|
|
||||||
int last = 0;
|
|
||||||
for (auto const& it : distances) {
|
|
||||||
if (last > 1 && it.first > 2 * last) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (it.first > cutOff) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
result.emplace_back(it.second);
|
|
||||||
if (result.size() >= maxResults) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
last = it.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// name of binary (i.e. argv[0])
|
// name of binary (i.e. argv[0])
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// DISCLAIMER
|
||||||
|
///
|
||||||
|
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// @author Jan Steemann
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "Section.h"
|
||||||
|
#include "Basics/shell-colors.h"
|
||||||
|
#include "ProgramOptions/Option.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace arangodb::options;
|
||||||
|
|
||||||
|
// adds a program option to the section
|
||||||
|
void Section::addOption(Option const& option) { options.emplace(option.name, option); }
|
||||||
|
|
||||||
|
// whether or not the section has (displayable) options
|
||||||
|
bool Section::hasOptions() const {
|
||||||
|
if (!hidden) {
|
||||||
|
for (auto const& it : options) {
|
||||||
|
if (!it.second.hidden) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print help for a section
|
||||||
|
// the special search string "." will show help for all sections, even if hidden
|
||||||
|
void Section::printHelp(std::string const& search, size_t tw, size_t ow, bool colors) const {
|
||||||
|
if (search != "." && (hidden || !hasOptions())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colors) {
|
||||||
|
std::cout << "Section '" << TRI_SHELL_COLOR_BRIGHT << displayName() << TRI_SHELL_COLOR_RESET << "' (" << description << ")"
|
||||||
|
<< std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Section '" << displayName() << "' (" << description << ")"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// propagate print command to options
|
||||||
|
for (auto const& it : options) {
|
||||||
|
it.second.printHelp(search, tw, ow, colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine display width for a section
|
||||||
|
size_t Section::optionsWidth() const {
|
||||||
|
size_t width = 0;
|
||||||
|
|
||||||
|
if (!hidden) {
|
||||||
|
for (auto const& it : options) {
|
||||||
|
width = (std::max)(width, it.second.optionsWidth());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
#define ARANGODB_PROGRAM_OPTIONS_SECTION_H 1
|
#define ARANGODB_PROGRAM_OPTIONS_SECTION_H 1
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
#include "Basics/shell-colors.h"
|
|
||||||
|
|
||||||
#include "ProgramOptions/Option.h"
|
#include "ProgramOptions/Option.h"
|
||||||
|
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
|
@ -44,58 +42,20 @@ struct Section {
|
||||||
obsolete(obsolete) {}
|
obsolete(obsolete) {}
|
||||||
|
|
||||||
// adds a program option to the section
|
// adds a program option to the section
|
||||||
void addOption(Option const& option) { options.emplace(option.name, option); }
|
void addOption(Option const& option);
|
||||||
|
|
||||||
// get display name for the section
|
// get display name for the section
|
||||||
std::string displayName() const { return alias.empty() ? name : alias; }
|
std::string displayName() const { return alias.empty() ? name : alias; }
|
||||||
|
|
||||||
// whether or not the section has (displayable) options
|
// whether or not the section has (displayable) options
|
||||||
bool hasOptions() const {
|
bool hasOptions() const;
|
||||||
if (!hidden) {
|
|
||||||
for (auto const& it : options) {
|
|
||||||
if (!it.second.hidden) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// print help for a section
|
// print help for a section
|
||||||
// the special search string "." will show help for all sections, even if hidden
|
// the special search string "." will show help for all sections, even if hidden
|
||||||
void printHelp(std::string const& search, size_t tw, size_t ow, bool colors) const {
|
void printHelp(std::string const& search, size_t tw, size_t ow, bool colors) const;
|
||||||
if (search != "." && (hidden || !hasOptions())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colors) {
|
|
||||||
std::cout << "Section '" << TRI_SHELL_COLOR_BRIGHT << displayName() << TRI_SHELL_COLOR_RESET << "' (" << description << ")"
|
|
||||||
<< std::endl;
|
|
||||||
} else {
|
|
||||||
std::cout << "Section '" << displayName() << "' (" << description << ")"
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// propagate print command to options
|
|
||||||
for (auto const& it : options) {
|
|
||||||
it.second.printHelp(search, tw, ow, colors);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine display width for a section
|
// determine display width for a section
|
||||||
size_t optionsWidth() const {
|
size_t optionsWidth() const;
|
||||||
size_t width = 0;
|
|
||||||
|
|
||||||
if (!hidden) {
|
|
||||||
for (auto const& it : options) {
|
|
||||||
width = (std::max)(width, it.second.optionsWidth());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string description;
|
std::string description;
|
||||||
|
|
Loading…
Reference in New Issue