1
0
Fork 0

move parts from ProgramOptions from headers into cpp files

This commit is contained in:
jsteemann 2017-05-23 10:30:36 +02:00
parent 6c065cd889
commit 53fa66e60d
24 changed files with 818 additions and 671 deletions

View File

@ -44,7 +44,7 @@ class BindParameters {
: _builder(nullptr), _parameters(), _processed(false) {}
/// @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) {}
/// @brief destroy the parameters

View File

@ -23,6 +23,7 @@
#include "Query.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Aql/AqlItemBlock.h"
#include "Aql/AqlTransaction.h"
#include "Aql/ExecutionBlock.h"
@ -42,6 +43,7 @@
#include "Cluster/ServerState.h"
#include "Logger/Logger.h"
#include "RestServer/AqlFeature.h"
#include "RestServer/QueryRegistryFeature.h"
#include "StorageEngine/TransactionState.h"
#include "Transaction/Methods.h"
#include "Transaction/StandaloneContext.h"
@ -69,23 +71,11 @@ static std::atomic<TRI_voc_tick_t> NextQueryId(1);
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
Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
char const* queryString, size_t queryLength,
std::shared_ptr<VPackBuilder> bindParameters,
std::shared_ptr<VPackBuilder> options, QueryPart part)
std::shared_ptr<VPackBuilder> const& bindParameters,
std::shared_ptr<VPackBuilder> const& options, QueryPart part)
: _id(0),
_resourceMonitor(),
_resources(&_resourceMonitor),
@ -102,6 +92,7 @@ Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
_maxWarningCount(10),
_warnings(),
_startTime(TRI_microtime()),
_queryRegistry(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")),
_part(part),
_contextOwnedByExterior(contextOwnedByExterior),
_killed(false),
@ -152,8 +143,8 @@ Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
/// @brief creates a query from VelocyPack
Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
std::shared_ptr<VPackBuilder> const queryStruct,
std::shared_ptr<VPackBuilder> options, QueryPart part)
std::shared_ptr<VPackBuilder> const& queryStruct,
std::shared_ptr<VPackBuilder> const& options, QueryPart part)
: _id(0),
_resourceMonitor(),
_resources(&_resourceMonitor),
@ -169,6 +160,7 @@ Query::Query(bool contextOwnedByExterior, TRI_vocbase_t* vocbase,
_maxWarningCount(10),
_warnings(),
_startTime(TRI_microtime()),
_queryRegistry(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")),
_part(part),
_contextOwnedByExterior(contextOwnedByExterior),
_killed(false),
@ -211,21 +203,7 @@ Query::~Query() {
_executor.reset();
if (_context != nullptr) {
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;
}
exitContext();
_ast.reset();
@ -376,7 +354,7 @@ void Query::registerErrorCustom(int code, char const* details) {
void Query::registerWarning(int code, char const* details) {
TRI_ASSERT(code != TRI_ERROR_NO_ERROR);
if (DoFailOnWarning) {
if (_queryRegistry->failOnWarning()) {
// make an error from each warning if requested
if (details == nullptr) {
THROW_ARANGO_EXCEPTION(code);
@ -1139,7 +1117,6 @@ void Query::exitContext() {
V8DealerFeature::DEALER->exitContext(_context);
_context = nullptr;
}
TRI_ASSERT(_context == nullptr);
}
}
@ -1473,8 +1450,18 @@ Graph const* Query::lookupGraphByName(std::string const& name) {
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
TRI_voc_tick_t Query::NextId() {
return NextQueryId.fetch_add(1, std::memory_order_seq_cst);
}

View File

@ -53,6 +53,8 @@ namespace velocypack {
class Builder;
}
class QueryRegistryFeature;
namespace aql {
struct AstNode;
@ -75,12 +77,12 @@ class Query {
public:
Query(bool, TRI_vocbase_t*, char const*, size_t,
std::shared_ptr<arangodb::velocypack::Builder>,
std::shared_ptr<arangodb::velocypack::Builder>, QueryPart);
std::shared_ptr<arangodb::velocypack::Builder> const& bindParameters,
std::shared_ptr<arangodb::velocypack::Builder> const& options, QueryPart);
Query(bool, TRI_vocbase_t*,
std::shared_ptr<arangodb::velocypack::Builder> const,
std::shared_ptr<arangodb::velocypack::Builder>, QueryPart);
Query(bool contextOwnedByExterior, TRI_vocbase_t*,
std::shared_ptr<arangodb::velocypack::Builder> const& queryStruct,
std::shared_ptr<arangodb::velocypack::Builder> const& options, QueryPart);
~Query();
@ -185,13 +187,7 @@ class Query {
}
/// @brief memory limit for query
size_t memoryLimit() const {
uint64_t value = getNumericOption<decltype(MemoryLimitValue)>("memoryLimit", MemoryLimitValue);
if (value > 0) {
return static_cast<size_t>(value);
}
return 0;
}
size_t memoryLimit() const;
/// @brief maximum number of plans to produce
int64_t literalSizeThreshold() const {
@ -274,37 +270,6 @@ class Query {
/// NOTE: returns nullptr if there are no warnings.
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
std::string getStateString() const;
@ -400,7 +365,7 @@ class Query {
/// @brief the currently used V8 context
V8Context* _context;
/// @brief warnings collected during execution
/// @brief graphs used in query, identified by name
std::unordered_map<std::string, Graph*> _graphs;
/// @brief the actual query string
@ -452,6 +417,8 @@ class Query {
/// @brief query start time
double _startTime;
QueryRegistryFeature const* _queryRegistry;
/// @brief the query part
QueryPart const _part;
@ -463,18 +430,6 @@ class Query {
/// @brief whether or not the query is a data modification query
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;
};
}
}

View File

@ -21,7 +21,8 @@
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "Aql/QueryList.h"
#include "QueryList.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Aql/Query.h"
#include "Aql/QueryProfile.h"
#include "Basics/ReadLocker.h"
@ -29,8 +30,10 @@
#include "Basics/WriteLocker.h"
#include "Basics/Exceptions.h"
#include "Logger/Logger.h"
#include "RestServer/QueryRegistryFeature.h"
#include "VocBase/vocbase.h"
using namespace arangodb;
using namespace arangodb::aql;
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),
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
QueryList::QueryList(TRI_vocbase_t*)
: _lock(),
_current(),
_slow(),
_slowCount(0),
_enabled(!Query::DisableQueryTracking()),
_trackSlowQueries(!Query::DisableQueryTracking()),
_slowQueryThreshold(Query::SlowQueryThreshold()),
_maxSlowQueries(QueryList::DefaultMaxSlowQueries),
_maxQueryStringLength(QueryList::DefaultMaxQueryStringLength) {
_enabled(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")->queryTracking()),
_trackSlowQueries(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")->queryTracking()),
_slowQueryThreshold(application_features::ApplicationServer::getFeature<arangodb::QueryRegistryFeature>("QueryRegistry")->slowThreshold()),
_maxSlowQueries(defaultMaxSlowQueries),
_maxQueryStringLength(defaultMaxQueryStringLength) {
_current.reserve(64);
}

View File

@ -162,6 +162,12 @@ class QueryList {
private:
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:
/// @brief r/w lock for the list
arangodb::basics::ReadWriteLock _lock;
@ -189,15 +195,6 @@ class QueryList {
/// @brief max length of query strings to return
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;
};
}
}

View File

@ -30,6 +30,8 @@
#include "RestServer/DatabaseFeature.h"
#include "RestServer/ServerFeature.h"
#include <iostream>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::options;

View File

@ -23,12 +23,15 @@
#include "InitDatabaseFeature.h"
#include "Basics/FileUtils.h"
#include "Basics/terminal-utils.h"
#include "Logger/Logger.h"
#include "Logger/LoggerFeature.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "RestServer/DatabasePathFeature.h"
#include <iostream>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::basics;

View File

@ -80,22 +80,7 @@ void QueryRegistryFeature::collectOptions(
new UInt64Parameter(&_queryCacheEntries));
}
void QueryRegistryFeature::validateOptions(
std::shared_ptr<ProgramOptions> options) {
}
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
std::pair<std::string, size_t> cacheProperties{_queryCacheMode,
_queryCacheEntries};
@ -106,8 +91,7 @@ void QueryRegistryFeature::prepare() {
QUERY_REGISTRY = _queryRegistry.get();
}
void QueryRegistryFeature::start() {
}
void QueryRegistryFeature::start() {}
void QueryRegistryFeature::unprepare() {
// clear the query registery

View File

@ -39,11 +39,15 @@ class QueryRegistryFeature final : public application_features::ApplicationFeatu
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override final;
void validateOptions(std::shared_ptr<options::ProgramOptions>) override final;
void prepare() override final;
void start() 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:
bool _queryTracking;
bool _failOnWarning;

View File

@ -33,6 +33,8 @@
#include "V8Server/V8Context.h"
#include "V8Server/V8DealerFeature.h"
#include <iostream>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::options;

View File

@ -36,6 +36,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/detail/xml_parser_utils.hpp>
#include <regex>
#include <iostream>
using namespace arangodb;
using namespace arangodb::basics;

View File

@ -33,6 +33,7 @@
#include "SimpleHttpClient/SimpleHttpClient.h"
#include <regex>
#include <iostream>
using namespace arangodb;
using namespace arangodb::basics;

View File

@ -32,6 +32,8 @@
#include "SimpleHttpClient/SimpleHttpClient.h"
#include "Ssl/ssl-helper.h"
#include <iostream>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::httpclient;

View File

@ -31,6 +31,8 @@
#include "ProgramOptions/Section.h"
#include "Shell/ClientFeature.h"
#include <iostream>
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::options;

View File

@ -29,6 +29,8 @@
#include "Logger/Logger.h"
#include "ProgramOptions/ArgumentParser.h"
#include <iostream>
using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::options;

View File

@ -33,6 +33,7 @@
#include "ProgramOptions/IniFileParser.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "ProgramOptions/Translator.h"
using namespace arangodb;
using namespace arangodb::basics;
@ -71,7 +72,7 @@ void ConfigFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
void ConfigFeature::loadOptions(std::shared_ptr<ProgramOptions> options,
char const* binaryPath) {
for (auto const& def : _defines) {
DefineEnvironment(def);
arangodb::options::DefineEnvironment(def);
}
loadConfigFile(options, _progname, binaryPath);

View File

@ -188,6 +188,9 @@ add_library(${LIB_ARANGO} STATIC
Logger/LoggerBufferFeature.cpp
Logger/LoggerFeature.cpp
Logger/LoggerStream.cpp
ProgramOptions/Option.cpp
ProgramOptions/ProgramOptions.cpp
ProgramOptions/Section.cpp
ProgramOptions/Translator.cpp
Random/RandomFeature.cpp
Random/RandomGenerator.cpp

View File

@ -26,7 +26,6 @@
#include "Basics/FileUtils.h"
#include <fstream>
#include <iostream>
#include <regex>
#include "ProgramOptions/ProgramOptions.h"

View File

@ -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);
}

View File

@ -27,41 +27,21 @@
#include "ProgramOptions/Parameters.h"
#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>
#include <iostream>
namespace arangodb {
namespace options {
struct Parameter;
// a single program option container
struct Option {
// options are default copy-constructible and default movable
// create an option, consisting of single string
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;
Parameter* parameter, bool hidden, bool obsolete);
size_t const pos = name.find(',');
if (pos != std::string::npos) {
shorthand = stripShorthand(name.substr(pos + 1));
name = name.substr(0, pos);
}
}
void toVPack(VPackBuilder& builder) const {
parameter->toVPack(builder);
}
void toVPack(arangodb::velocypack::Builder& builder) const;
// get display name for the option
std::string displayName() const { return "--" + fullName(); }
@ -76,127 +56,31 @@ struct Option {
// print help for an option
// 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 {
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) << " ";
}
}
}
}
void printHelp(std::string const& search, size_t tw, size_t ow, bool) const;
std::string nameWithType() const {
return displayName() + " " + parameter->typeDescription();
}
// determine the width of an option help string
size_t optionsWidth() const {
if (hidden) {
return 0;
}
return nameWithType().size();
}
size_t optionsWidth() const;
// strip the "--" from a string
static std::string stripPrefix(std::string const& name) {
size_t pos = name.find("--");
if (pos == 0) {
// strip initial "--"
return name.substr(2);
}
return name;
}
static std::string stripPrefix(std::string const& name);
// strip the "-" from a string
static std::string stripShorthand(std::string const& name) {
size_t pos = name.find("-");
if (pos == 0) {
// strip initial "-"
return name.substr(1);
}
return name;
}
static std::string stripShorthand(std::string const& name);
// split an option name at the ".", if it exists
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::pair<std::string, std::string> splitName(std::string name);
static std::vector<std::string> 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;
}
size_t size);
// right-pad a string
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 pad(std::string const& value, size_t length);
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);
}
static std::string trim(std::string const& value);
std::string section;
std::string name;

View File

@ -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;
}

View File

@ -25,16 +25,10 @@
#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/Section.h"
#include "ProgramOptions/Translator.h"
#define ARANGODB_PROGRAM_OPTIONS_PROGNAME "#progname#"
#include <velocypack/Builder.h>
namespace arangodb {
namespace options {
@ -102,35 +96,11 @@ class ProgramOptions {
ProgramOptions(char const* progname, std::string const& usage,
std::string const& more,
const char *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;
}
char const* binaryPath);
// sets a value translator
void setTranslator(
std::function<std::string(std::string const&, char const*)> translator) {
_translator = translator;
}
std::function<std::string(std::string const&, char const*)> translator);
// return a const reference to the processing result
ProcessingResult const& processingResult() const { return _processingResult; }
@ -205,201 +175,40 @@ class ProgramOptions {
}
// 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
// the special search string "*" will show help for all sections
// the special search string "." will show help for all sections, even if
// hidden
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();
}
}
void printHelp(std::string const& search) const;
// prints the names for all section help options
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;
}
void printSectionsHelp() const;
// returns a VPack representation of the option values
VPackBuilder 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;
}
arangodb::velocypack::Builder toVPack(bool onlyTouched,
std::unordered_set<std::string> const& exclude) const;
// translate a shorthand option
std::string translateShorthand(std::string const& name) const {
auto it = _shorthands.find(name);
if (it == _shorthands.end()) {
return name;
}
return (*it).second;
}
std::string translateShorthand(std::string const& name) const;
void 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);
}
}
}
bool onlyTouched) const;
// checks whether a specific option exists
// if the option does not exist, this will flag an error
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;
}
bool require(std::string const& name);
// sets a value for an option
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;
}
bool setValue(std::string const& name, std::string const& value);
// finalizes a pass, copying touched into frozen
void endPass() {
if (_overrideOptions) {
return;
}
for (auto const& it : _processingResult._touched) {
_processingResult.freeze(it);
}
}
void endPass();
// check whether or not an option requires a value
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();
}
bool requiresValue(std::string const& name) const;
// returns a pointer to an option value, specified by option name
// returns a nullptr if the option is unknown
template <typename T>
@ -423,184 +232,32 @@ class ProgramOptions {
}
// returns an option description
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;
}
std::string getDescription(std::string const& name);
// handle an unknown option
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;
}
bool unknownOption(std::string const& name);
// report an error (callback from parser)
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;
}
bool fail(std::string const& message);
void failNotice(std::string const& message) {
_processingResult.failed(true);
std::cerr << " " << message << std::endl;
}
void failNotice(std::string const& message);
// add a positional argument (callback from parser)
void addPositional(std::string const& value) {
_processingResult._positionals.emplace_back(value);
}
void addPositional(std::string const& value);
private:
// adds an option to the list of options
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);
}
void addOption(Option const& option);
// determine maximum width of all options labels
size_t optionsWidth() const {
size_t width = 0;
for (auto const& it : _sections) {
width = (std::max)(width, it.second.optionsWidth());
}
return width;
}
size_t optionsWidth() const;
// check if the options are already sealed and throw if yes
void checkIfSealed() const {
if (_sealed) {
throw std::logic_error("program options are already sealed");
}
}
void checkIfSealed() const;
// get a list of similar options
std::vector<std::string> 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;
}
size_t maxResults);
private:
// name of binary (i.e. argv[0])

View File

@ -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;
}

View File

@ -24,8 +24,6 @@
#define ARANGODB_PROGRAM_OPTIONS_SECTION_H 1
#include "Basics/Common.h"
#include "Basics/shell-colors.h"
#include "ProgramOptions/Option.h"
namespace arangodb {
@ -44,58 +42,20 @@ struct Section {
obsolete(obsolete) {}
// 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
std::string displayName() const { return alias.empty() ? name : alias; }
// whether or not the section has (displayable) options
bool hasOptions() const {
if (!hidden) {
for (auto const& it : options) {
if (!it.second.hidden) {
return true;
}
}
}
return false;
}
bool hasOptions() const;
// print help for a section
// 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 {
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;
}
void printHelp(std::string const& search, size_t tw, size_t ow, bool colors) const;
// determine display width for a section
size_t optionsWidth() const {
size_t width = 0;
if (!hidden) {
for (auto const& it : options) {
width = (std::max)(width, it.second.optionsWidth());
}
}
return width;
}
size_t optionsWidth() const;
std::string name;
std::string description;