1
0
Fork 0

added option `--console.history` to arangosh (#8328)

This commit is contained in:
Jan 2019-03-07 13:14:51 +01:00 committed by GitHub
parent f437b83832
commit 6941eb941c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 113 additions and 19 deletions

View File

@ -1,3 +1,19 @@
v3.4.5 (XXXX-XX-XX)
-------------------
* added option `--console.history` to arangosh for controlling whether
the command-line history should be loaded from and persisted in a file.
The default value for this option is `true`. Setting it to `false`
will make arangosh not load any command-line history from the history
file, and not store the current session's history when the shell is
exited. The command-line history will then only be available in the
current shell session.
* display the server role when connecting arangosh against a server (e.g.
SINGLE, COORDINATOR)
v3.4.4 (2019-03-08)
-------------------

View File

@ -1047,6 +1047,18 @@ versions on the same machine (e.g. for testing).
Client tools
------------
### Arangosh
Starting with ArangoDB version 3.4.5, the ArangoShell (arangosh) provides the option
`--console.history` for controlling whether the shell's command-line history
should be loaded from and persisted in a file.
The default value for this option is `true`. Setting it to `false`
will make arangosh not load any command-line history from the history
file, and not store the current session's history when the shell is
exited. The command-line history will then only be available in the
current shell session.
### Arangodump
Arangodump can now dump multiple collections in parallel. This can significantly

View File

@ -66,6 +66,10 @@ RestStatus RestVersionHandler::execute() {
auto server = application_features::ApplicationServer::server->getFeature<ServerFeature>(
"Server");
result.add("mode", VPackValue(server->operationModeString()));
auto serverState = ServerState::instance();
if (serverState != nullptr) {
result.add("role", VPackValue(ServerState::roleToString(serverState->getRole())));
}
}
std::string host = ServerState::instance()->getHost();

View File

@ -59,6 +59,7 @@ ConsoleFeature::ConsoleFeature(application_features::ApplicationServer& server)
#endif
_quiet(false),
_colors(true),
_useHistory(true),
_autoComplete(true),
_prettyPrint(true),
_auditFile(),
@ -108,6 +109,12 @@ void ConsoleFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
options->addOption("--console.audit-file",
"audit log file to save commands and results",
new StringParameter(&_auditFile));
options->addOption("--console.history",
"whether or not to load and persist command-line history",
new BooleanParameter(&_useHistory))
.setIntroducedIn(30405)
.setIntroducedIn(30500);
options->addOption("--console.pager", "enable paging", new BooleanParameter(&_pager));
@ -309,13 +316,23 @@ std::string ConsoleFeature::readPassword() {
}
void ConsoleFeature::printWelcomeInfo() {
if (!_quiet && _pager) {
std::ostringstream s;
s << "Using pager '" << _pagerCommand << "' for output buffering.";
printLine(s.str());
if (_quiet) {
return;
}
std::ostringstream s;
if (_pager) {
s << "Using pager '" << _pagerCommand << "' for output buffering. ";
}
if (_useHistory) {
s << "Command-line history will be persisted when the shell is exited.";
} else {
s << "Command-line history is enabled for this session only and will *not* be persisted.";
}
printLine(s.str());
}
void ConsoleFeature::printByeBye() {

View File

@ -41,6 +41,7 @@ class ConsoleFeature final : public application_features::ApplicationFeature {
bool quiet() const { return _quiet; }
void setQuiet(bool value) { _quiet = value; }
bool colors() const { return _colors; }
bool useHistory() const { return _useHistory; }
bool autoComplete() const { return _autoComplete; }
bool prettyPrint() const { return _prettyPrint; }
bool pager() const { return _pager; }
@ -54,6 +55,7 @@ class ConsoleFeature final : public application_features::ApplicationFeature {
#endif
bool _quiet;
bool _colors;
bool _useHistory;
bool _autoComplete;
bool _prettyPrint;
std::string _auditFile;

View File

@ -60,6 +60,7 @@ V8ClientConnection::V8ClientConnection()
_lastErrorMessage(""),
_version("arango"),
_mode("unknown mode"),
_role("UNKNOWN"),
_loop(1),
_vpackOptions(VPackOptions::Defaults) {
_vpackOptions.buildUnindexedObjects = true;
@ -123,6 +124,10 @@ void V8ClientConnection::createConnection() {
if (mode.isString()) {
_mode = mode.copyString();
}
VPackSlice role = details.get("role");
if (role.isString()) {
_role = role.copyString();
}
}
std::string const versionString =
VelocyPackHelper::getStringValue(body, "version", "");
@ -227,7 +232,7 @@ void V8ClientConnection::reconnect(ClientFeature* client) {
LOG_TOPIC(INFO, arangodb::Logger::FIXME)
<< "Connected to ArangoDB "
<< "'" << endpointSpecification() << "', "
<< "version " << _version << " [" << _mode << "], "
<< "version " << _version << " [" << _role << ", " << _mode << "], "
<< "database '" << _databaseName << "', "
<< "username: '" << client->username() << "'";
} else {
@ -353,7 +358,7 @@ static void ClientConnection_ConstructorCallback(v8::FunctionCallbackInfo<v8::Va
LOG_TOPIC(INFO, arangodb::Logger::FIXME)
<< "Connected to ArangoDB "
<< "'" << v8connection->endpointSpecification() << "', "
<< "version " << v8connection->version() << " [" << v8connection->mode() << "], "
<< "version " << v8connection->version() << " [" << v8connection->role() << ", " << v8connection->mode() << "], "
<< "database '" << v8connection->databaseName() << "', "
<< "username: '" << v8connection->username() << "'";
@ -1276,6 +1281,30 @@ static void ClientConnection_getMode(v8::FunctionCallbackInfo<v8::Value> const&
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief ClientConnection method "getRole"
////////////////////////////////////////////////////////////////////////////////
static void ClientConnection_getRole(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
// get the connection
V8ClientConnection* v8connection =
TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION);
if (v8connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
}
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("getRole()");
}
TRI_V8_RETURN_STD_STRING(v8connection->role());
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief ClientConnection method "getDatabaseName"
////////////////////////////////////////////////////////////////////////////////
@ -1752,6 +1781,9 @@ void V8ClientConnection::initServer(v8::Isolate* isolate, v8::Local<v8::Context>
connection_proto->Set(isolate, "getMode",
v8::FunctionTemplate::New(isolate, ClientConnection_getMode));
connection_proto->Set(isolate, "getRole",
v8::FunctionTemplate::New(isolate, ClientConnection_getRole));
connection_proto->Set(isolate, "getDatabaseName",
v8::FunctionTemplate::New(isolate, ClientConnection_getDatabaseName));

View File

@ -77,6 +77,7 @@ class V8ClientConnection {
std::string lastErrorMessage() const { return _lastErrorMessage; }
std::string const& version() const { return _version; }
std::string const& mode() const { return _mode; }
std::string const& role() const { return _role; }
std::string endpointSpecification() const;
v8::Handle<v8::Value> getData(v8::Isolate* isolate, StringRef const& location,
@ -145,6 +146,7 @@ class V8ClientConnection {
std::string _lastErrorMessage;
std::string _version;
std::string _mode;
std::string _role;
fuerte::EventLoopService _loop;
fuerte::ConnectionBuilder _builder;

View File

@ -342,7 +342,7 @@ bool V8ShellFeature::printHello(V8ClientConnection* v8connection) {
std::ostringstream is;
is << "Connected to ArangoDB '" << v8connection->endpointSpecification()
<< "' version: " << v8connection->version() << " ["
<< "' version: " << v8connection->version() << " [" << v8connection->role() << ", "
<< v8connection->mode() << "], database: '" << v8connection->databaseName()
<< "', username: '" << v8connection->username() << "'";
@ -350,7 +350,8 @@ bool V8ShellFeature::printHello(V8ClientConnection* v8connection) {
} else {
std::ostringstream is;
is << "Could not connect to endpoint '" << v8connection->endpointSpecification()
auto client = server()->getFeature<ClientFeature>("Client");
is << "Could not connect to endpoint '" << client->endpoint()
<< "', database: '" << v8connection->databaseName()
<< "', username: '" << v8connection->username() << "'";
@ -422,7 +423,7 @@ int V8ShellFeature::runShell(std::vector<std::string> const& positionals) {
bool promptError;
auto v8connection = setup(context, true, positionals, &promptError);
V8LineEditor v8LineEditor(_isolate, context, "." + _name + ".history");
V8LineEditor v8LineEditor(_isolate, context, _console->useHistory() ? "." + _name + ".history" : "");
if (v8connection != nullptr) {
v8LineEditor.setSignalFunction(

View File

@ -63,7 +63,9 @@ LinenoiseShell::LinenoiseShell(std::string const& history, Completer* completer)
LinenoiseShell::~LinenoiseShell() { COMPLETER = nullptr; }
bool LinenoiseShell::open(bool) {
linenoiseHistoryLoad(_historyFilename.c_str());
if (!_historyFilename.empty()) {
linenoiseHistoryLoad(_historyFilename.c_str());
}
_state = STATE_OPENED;
return true;
}
@ -89,7 +91,9 @@ void LinenoiseShell::addHistory(std::string const& str) {
}
bool LinenoiseShell::writeHistory() {
linenoiseHistorySave(_historyFilename.c_str());
if (!_historyFilename.empty()) {
linenoiseHistorySave(_historyFilename.c_str());
}
return true;
}

View File

@ -54,14 +54,18 @@ void ShellBase::sortAlternatives(std::vector<std::string>& completions) {
ShellBase::ShellBase(std::string const& history, Completer* completer)
: _current(), _historyFilename(), _state(STATE_NONE), _completer(completer) {
// construct the complete history path
std::string path(TRI_HomeDirectory());
if (!history.empty()) {
// note: if history is empty, we will not write any history and not
// construct the full filename
std::string path(TRI_HomeDirectory());
if (!path.empty() && path[path.size() - 1] != TRI_DIR_SEPARATOR_CHAR) {
path.push_back(TRI_DIR_SEPARATOR_CHAR);
if (!path.empty() && path[path.size() - 1] != TRI_DIR_SEPARATOR_CHAR) {
path.push_back(TRI_DIR_SEPARATOR_CHAR);
}
path.append(history);
_historyFilename = path;
}
path.append(history);
_historyFilename = path;
}
ShellBase::~ShellBase() { delete _completer; }