// the result is wrapped in a Javascript variable SYS_ARANGO V8ClientConnection* V8ShellFeature::setup( v8::Local<v8::Context>& context, bool createConnection, std::vector<std::string> const& positionals, bool* promptError) { std::unique_ptr<V8ClientConnection> v8connection; ClientFeature* client = nullptr; if (createConnection) { client = dynamic_cast<ClientFeature*>(server()->feature("Client")); if (client != nullptr && client->isEnabled()) { auto connection = client->createConnection(); v8connection = std::make_unique<V8ClientConnection>( connection, client->databaseName(), client->username(), client->password(), client->requestTimeout()); } else { client = nullptr; } } initMode(ShellFeature::RunMode::INTERACTIVE, positionals); if (createConnection && client != nullptr) { v8connection->initServer(_isolate, context, client); } bool pe = printHello(v8connection.get()); loadModules(ShellFeature::RunMode::INTERACTIVE); if (promptError != nullptr) { *promptError = pe; } return v8connection.release(); }
int V8ShellFeature::runShell(std::vector<std::string> const& positionals) { v8::Locker locker{_isolate}; v8::Isolate::Scope isolate_scope(_isolate); v8::HandleScope handle_scope(_isolate); v8::Local<v8::Context> context = v8::Local<v8::Context>::New(_isolate, _context); v8::Context::Scope context_scope{context}; bool promptError; auto v8connection = setup(context, true, positionals, &promptError); std::unique_ptr<V8ClientConnection> guard(v8connection); V8LineEditor v8LineEditor(_isolate, context, "." + _name + ".history"); if (v8connection != nullptr) { v8LineEditor.setSignalFunction( [&v8connection]() { v8connection->setInterrupted(true); }); } v8LineEditor.open(_console->autoComplete()); v8::Local<v8::String> name( TRI_V8_ASCII_STRING2(_isolate, TRI_V8_SHELL_COMMAND_NAME)); uint64_t nrCommands = 0; ClientFeature* client = server()->getFeature<ClientFeature>("Client"); if (!client->isEnabled()) { client = nullptr; } bool const isBatch = isatty(STDIN_FILENO) == 0; bool lastEmpty = isBatch; while (true) { _console->setPromptError(promptError); auto prompt = _console->buildPrompt(client); ShellBase::EofType eof = ShellBase::EOF_NONE; std::string input = v8LineEditor.prompt(prompt._colored, prompt._plain, eof); if (eof == ShellBase::EOF_FORCE_ABORT || (eof == ShellBase::EOF_ABORT && lastEmpty)) { break; } if (input.empty()) { promptError = false; lastEmpty = true; continue; } lastEmpty = isBatch; _console->log(prompt._plain + input + "\n"); std::string i = StringUtils::trim(input); if (i == "exit" || i == "quit" || i == "exit;" || i == "quit;") { break; } if (i == "help" || i == "help;") { input = "help()"; } v8LineEditor.addHistory(input); v8::TryCatch tryCatch; _console->startPager(); // assume the command succeeds promptError = false; // execute command and register its result in __LAST__ v8LineEditor.setExecutingCommand(true); v8::Handle<v8::Value> v = TRI_ExecuteJavaScriptString( _isolate, context, TRI_V8_STRING2(_isolate, input.c_str()), name, true); v8LineEditor.setExecutingCommand(false); if (v.IsEmpty()) { context->Global()->Set(TRI_V8_ASCII_STRING2(_isolate, "_last"), v8::Undefined(_isolate)); } else { context->Global()->Set(TRI_V8_ASCII_STRING2(_isolate, "_last"), v); } // command failed if (tryCatch.HasCaught()) { std::string exception; if (!tryCatch.CanContinue() || tryCatch.HasTerminated()) { exception = "command locally aborted\n"; } else { exception = TRI_StringifyV8Exception(_isolate, &tryCatch); } _console->printErrorLine(exception); _console->log(exception); // this will change the prompt for the next round promptError = true; } if (v8connection != nullptr) { v8connection->setInterrupted(false); } _console->stopPager(); _console->printLine(""); _console->log("\n"); // make sure the last command result makes it into the log file _console->flushLog(); // gc if (++nrCommands >= _gcInterval || V8PlatformFeature::isOutOfMemory(_isolate)) { nrCommands = 0; TRI_RunGarbageCollectionV8(_isolate, 500.0); // needs to be reset after the garbage collection V8PlatformFeature::resetOutOfMemory(_isolate); } } if (!_console->quiet()) { _console->printLine(""); _console->printByeBye(); } return promptError ? TRI_ERROR_INTERNAL : TRI_ERROR_NO_ERROR; }