Files
mongo/shell/dbshell.cpp

759 lines
22 KiB
C++
Raw Normal View History

2009-01-26 22:19:15 -05:00
// dbshell.cpp
/*
* Copyright 2010 10gen Inc.
*
* 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.
*/
2010-06-05 20:55:11 -04:00
#include "pch.h"
#include <stdio.h>
2009-01-26 22:19:15 -05:00
2011-03-18 15:17:40 -04:00
2011-03-18 15:19:43 -04:00
#define USE_LINENOISE
2011-03-18 02:41:55 -04:00
#include "../third_party/linenoise/linenoise.h"
2010-06-15 10:31:01 -04:00
#include "../scripting/engine.h"
#include "../client/dbclient.h"
#include "../util/unittest.h"
#include "../db/cmdline.h"
#include "utils.h"
#include "../util/password.h"
#include "../util/version.h"
2010-06-14 16:22:11 -04:00
#include "../util/goodies.h"
#include "../db/repl/rs_member.h"
2009-01-26 22:19:15 -05:00
using namespace std;
using namespace boost::filesystem;
using namespace mongo;
2010-06-07 11:06:02 -04:00
string historyFile;
2009-08-25 17:00:01 -04:00
bool gotInterrupted = 0;
bool inMultiLine = 0;
2010-07-21 18:10:37 -04:00
static volatile bool atPrompt = false; // can eval before getting to prompt
2010-07-21 18:45:40 -04:00
bool autoKillOp = false;
#if defined(USE_LINENOISE) && !defined(__freebsd__) && !defined(__openbsd__) && !defined(_WIN32)
2011-03-18 15:19:43 -04:00
// this is for ctrl-c handling
#include <setjmp.h>
jmp_buf jbuf;
#endif
namespace mongo {
Scope * shellMainScope;
extern bool dbexitCalled;
}
2010-06-07 11:06:02 -04:00
2011-01-04 00:40:41 -05:00
void generateCompletions( const string& prefix , vector<string>& all ) {
2010-06-07 11:06:02 -04:00
if ( prefix.find( '"' ) != string::npos )
return;
2010-08-09 20:19:00 -04:00
shellMainScope->invokeSafe("function(x) {shellAutocomplete(x)}", BSON("0" << prefix), 1000);
2010-06-07 11:06:02 -04:00
BSONObjBuilder b;
shellMainScope->append( b , "" , "__autocomplete__" );
BSONObj res = b.obj();
BSONObj arr = res.firstElement().Obj();
BSONObjIterator i(arr);
2011-01-04 00:40:41 -05:00
while ( i.more() ) {
2010-06-07 11:06:02 -04:00
BSONElement e = i.next();
all.push_back( e.String() );
}
}
2011-03-18 02:41:55 -04:00
#ifdef USE_LINENOISE
void completionHook(const char* text , linenoiseCompletions* lc ) {
2010-06-07 11:06:02 -04:00
vector<string> all;
2011-03-18 02:41:55 -04:00
generateCompletions( text , all );
2011-01-04 00:40:41 -05:00
2011-03-18 02:41:55 -04:00
for ( unsigned i=0; i<all.size(); i++ )
linenoiseAddCompletion( lc , (char*)all[i].c_str() );
2010-06-07 11:06:02 -04:00
2010-06-04 15:35:51 -04:00
}
2010-07-29 11:40:36 -04:00
#endif
2010-06-04 15:35:51 -04:00
2011-01-04 00:40:41 -05:00
void shellHistoryInit() {
#ifdef USE_LINENOISE
stringstream ss;
char * h = getenv( "HOME" );
if ( h )
ss << h << "/";
ss << ".dbshell";
historyFile = ss.str();
2011-03-18 02:41:55 -04:00
linenoiseHistoryLoad( (char*)historyFile.c_str() );
linenoiseSetCompletionCallback( completionHook );
2010-08-09 20:19:00 -04:00
2009-02-11 09:15:06 -05:00
#else
2010-06-07 11:17:08 -04:00
//cout << "type \"exit\" to exit" << endl;
2009-02-10 13:45:30 -05:00
#endif
}
2011-01-04 00:40:41 -05:00
void shellHistoryDone() {
#ifdef USE_LINENOISE
2011-03-18 02:41:55 -04:00
linenoiseHistorySave( (char*)historyFile.c_str() );
2009-02-10 13:45:30 -05:00
#endif
}
2011-01-04 00:40:41 -05:00
void shellHistoryAdd( const char * line ) {
#ifdef USE_LINENOISE
2010-06-29 18:00:07 -04:00
if ( line[0] == '\0' )
2009-02-10 13:45:30 -05:00
return;
// dont record duplicate lines
static string lastLine;
if (lastLine == line)
return;
lastLine = line;
2010-06-29 18:00:07 -04:00
if ((strstr(line, ".auth")) == NULL)
2011-03-18 02:41:55 -04:00
linenoiseHistoryAdd( line );
2009-02-10 13:45:30 -05:00
#endif
}
2011-01-04 00:40:41 -05:00
void intr( int sig ) {
#ifdef CTRLC_HANDLE
2009-08-25 17:00:01 -04:00
longjmp( jbuf , 1 );
2009-08-25 17:22:00 -04:00
#endif
2009-08-25 17:00:01 -04:00
}
2009-08-25 17:26:43 -04:00
#if !defined(_WIN32)
void killOps() {
2010-03-07 14:05:12 -05:00
if ( mongo::shellUtils::_nokillop || mongo::shellUtils::_allMyUris.size() == 0 )
return;
2010-07-21 18:10:37 -04:00
if ( atPrompt )
return;
sleepmillis(10); // give current op a chance to finish
2010-07-21 18:10:37 -04:00
2011-01-04 00:40:41 -05:00
for( map< string, set<string> >::const_iterator i = shellUtils::_allMyUris.begin(); i != shellUtils::_allMyUris.end(); ++i ) {
2010-08-17 18:09:53 -04:00
string errmsg;
ConnectionString cs = ConnectionString::parse(i->first, errmsg);
if (!cs.isValid()) continue;
boost::scoped_ptr<DBClientWithCommands> conn (cs.connect(errmsg));
if (!conn) continue;
const set<string>& uris = i->second;
BSONObj inprog = conn->findOne("admin.$cmd.sys.inprog", Query())["inprog"].embeddedObject().getOwned();
2011-01-04 00:40:41 -05:00
BSONForEach(op, inprog) {
2010-08-17 18:09:53 -04:00
if ( uris.count(op["client"].String()) ) {
ONCE if ( !autoKillOp ) {
cout << endl << "do you want to kill the current op(s) on the server? (y/n): ";
cout.flush();
char yn;
cin >> yn;
if (yn != 'y' && yn != 'Y')
return;
}
2010-08-17 18:09:53 -04:00
conn->findOne("admin.$cmd.sys.killop", QUERY("op"<< op["opid"]));
}
}
}
}
2011-01-04 00:40:41 -05:00
void quitNicely( int sig ) {
mongo::dbexitCalled = true;
2011-01-04 00:40:41 -05:00
if ( sig == SIGINT && inMultiLine ) {
2009-08-25 17:00:01 -04:00
gotInterrupted = 1;
return;
}
if ( sig == SIGPIPE )
mongo::rawOut( "mongo got signal SIGPIPE\n" );
killOps();
2009-02-10 13:45:30 -05:00
shellHistoryDone();
2009-01-26 22:19:15 -05:00
exit(0);
2010-06-15 10:31:01 -04:00
}
#else
2011-01-04 00:40:41 -05:00
void quitNicely( int sig ) {
mongo::dbexitCalled = true;
2010-06-15 10:31:01 -04:00
//killOps();
shellHistoryDone();
exit(0);
2009-01-26 22:19:15 -05:00
}
2009-08-25 17:26:43 -04:00
#endif
2009-01-26 22:19:15 -05:00
2011-01-04 00:40:41 -05:00
char * shellReadline( const char * prompt , int handlesigint = 0 ) {
atPrompt = true;
2011-03-18 02:41:55 -04:00
#ifdef USE_LINENOISE
2010-06-07 11:06:02 -04:00
#ifdef CTRLC_HANDLE
2011-01-04 00:40:41 -05:00
if ( ! handlesigint ) {
2011-03-18 02:41:55 -04:00
char* ret = linenoise( prompt );
atPrompt = false;
return ret;
}
2011-01-04 00:40:41 -05:00
if ( setjmp( jbuf ) ) {
2009-08-25 17:00:01 -04:00
gotInterrupted = 1;
sigrelse(SIGINT);
2009-08-25 17:00:01 -04:00
signal( SIGINT , quitNicely );
return 0;
}
signal( SIGINT , intr );
#endif
2011-03-18 02:41:55 -04:00
char * ret = linenoise( prompt );
2010-07-29 16:55:15 -04:00
signal( SIGINT , quitNicely );
atPrompt = false;
2009-08-25 17:00:01 -04:00
return ret;
#else
printf("%s", prompt); cout.flush();
2009-08-25 17:00:01 -04:00
char * buf = new char[1024];
char * l = fgets( buf , 1024 , stdin );
int len = strlen( buf );
2010-07-14 13:23:08 -04:00
if ( len )
buf[len-1] = 0;
atPrompt = false;
2009-08-25 17:00:01 -04:00
return l;
#endif
}
#if !defined(_WIN32)
#include <string.h>
void quitAbruptly( int sig ) {
ostringstream ossSig;
ossSig << "mongo got signal " << sig << " (" << strsignal( sig ) << "), stack trace: " << endl;
mongo::rawOut( ossSig.str() );
2009-08-06 14:15:18 -04:00
ostringstream ossBt;
mongo::printStackTrace( ossBt );
mongo::rawOut( ossBt.str() );
2009-08-06 14:15:18 -04:00
mongo::shellUtils::KillMongoProgramInstances();
2009-08-06 14:15:18 -04:00
exit(14);
}
2010-09-07 13:26:30 -07:00
// this will be called in certain c++ error cases, for example if there are two active
// exceptions
void myterminate() {
mongo::rawOut( "terminate() called in shell, printing stack:" );
mongo::printStackTrace();
exit(14);
}
void setupSignals() {
signal( SIGINT , quitNicely );
2009-02-02 09:53:14 -05:00
signal( SIGTERM , quitNicely );
signal( SIGPIPE , quitNicely ); // Maybe just log and continue?
signal( SIGABRT , quitAbruptly );
2009-02-02 09:53:14 -05:00
signal( SIGSEGV , quitAbruptly );
signal( SIGBUS , quitAbruptly );
signal( SIGFPE , quitAbruptly );
2010-09-07 13:26:30 -07:00
set_terminate( myterminate );
}
2009-03-24 17:35:50 -04:00
#else
inline void setupSignals() {}
#endif
2011-01-04 00:40:41 -05:00
string fixHost( string url , string host , string port ) {
//cout << "fixHost url: " << url << " host: " << host << " port: " << port << endl;
2011-01-04 00:40:41 -05:00
if ( host.size() == 0 && port.size() == 0 ) {
if ( url.find( "/" ) == string::npos ) {
// check for ips
if ( url.find( "." ) != string::npos )
return url + "/test";
if ( url.rfind( ":" ) != string::npos &&
2011-01-04 00:40:41 -05:00
isdigit( url[url.rfind(":")+1] ) )
return url + "/test";
}
2009-01-29 07:46:43 -05:00
return url;
2009-01-30 13:00:47 -05:00
}
2009-08-06 14:15:18 -04:00
2011-01-04 00:40:41 -05:00
if ( url.find( "/" ) != string::npos ) {
2009-01-29 07:46:43 -05:00
cerr << "url can't have host or port if you specify them individually" << endl;
exit(-1);
}
2009-08-06 14:15:18 -04:00
2009-01-29 07:46:43 -05:00
if ( host.size() == 0 )
host = "127.0.0.1";
string newurl = host;
if ( port.size() > 0 )
newurl += ":" + port;
2011-01-04 00:40:41 -05:00
else if (host.find(':') == string::npos) {
// need to add port with IPv6 addresses
newurl += ":27017";
}
2009-08-06 14:15:18 -04:00
2009-01-29 07:46:43 -05:00
newurl += "/" + url;
2009-08-06 14:15:18 -04:00
2009-01-29 07:46:43 -05:00
return newurl;
}
static string OpSymbols = "~!%^&*-+=|:,<>/?";
2011-01-04 00:40:41 -05:00
bool isOpSymbol( char c ) {
for ( size_t i = 0; i < OpSymbols.size(); i++ )
if ( OpSymbols[i] == c ) return true;
return false;
}
2011-01-04 00:40:41 -05:00
bool isBalanced( string code ) {
int brackets = 0;
int parens = 0;
bool danglingOp = false;
2011-01-04 00:40:41 -05:00
for ( size_t i=0; i<code.size(); i++ ) {
switch( code[i] ) {
case '/':
2011-01-04 00:40:41 -05:00
if ( i+1 < code.size() && code[i+1] == '/' ) {
while ( i<code.size() && code[i] != '\n' )
i++;
}
continue;
case '{': brackets++; break;
2009-12-08 15:14:00 -05:00
case '}': if ( brackets <= 0 ) return true; brackets--; break;
case '(': parens++; break;
2009-12-08 15:14:00 -05:00
case ')': if ( parens <= 0 ) return true; parens--; break;
case '"':
i++;
while ( i < code.size() && code[i] != '"' ) i++;
break;
case '\'':
i++;
while ( i < code.size() && code[i] != '\'' ) i++;
break;
case '\\':
if ( i+1 < code.size() && code[i+1] == '/') i++;
break;
case '+':
case '-':
if ( i+1 < code.size() && code[i+1] == code[i]) {
i++;
continue; // postfix op (++/--) can't be a dangling op
}
break;
}
if ( isOpSymbol( code[i] )) danglingOp = true;
else if (! std::isspace( code[i] )) danglingOp = false;
}
return brackets == 0 && parens == 0 && !danglingOp;
}
using mongo::asserted;
struct BalancedTest : public mongo::UnitTest {
public:
2011-01-04 00:40:41 -05:00
void run() {
assert( isBalanced( "x = 5" ) );
assert( isBalanced( "function(){}" ) );
assert( isBalanced( "function(){\n}" ) );
assert( ! isBalanced( "function(){" ) );
assert( isBalanced( "x = \"{\";" ) );
assert( isBalanced( "// {" ) );
assert( ! isBalanced( "// \n {" ) );
2009-09-01 13:50:54 -04:00
assert( ! isBalanced( "\"//\" {" ) );
assert( isBalanced( "{x:/x\\//}" ) );
assert( ! isBalanced( "{ \\/// }" ) );
assert( isBalanced( "x = 5 + y ") );
assert( ! isBalanced( "x = ") );
assert( ! isBalanced( "x = // hello") );
assert( ! isBalanced( "x = 5 +") );
assert( isBalanced( " x ++") );
assert( isBalanced( "-- x") );
}
} balnaced_test;
2011-01-04 00:40:41 -05:00
string finishCode( string code ) {
while ( ! isBalanced( code ) ) {
2009-08-25 17:00:01 -04:00
inMultiLine = 1;
code += "\n";
2009-08-25 17:00:01 -04:00
char * line = shellReadline("... " , 1 );
if ( gotInterrupted )
return "";
if ( ! line )
return "";
while (startsWith(line, "... "))
line += 4;
code += line;
}
return code;
}
2009-08-07 10:43:39 -04:00
#include <boost/program_options.hpp>
namespace po = boost::program_options;
void show_help_text(const char* name, po::options_description options) {
2009-09-22 10:07:53 -04:00
cout << "MongoDB shell version: " << mongo::versionString << endl;
2009-08-07 10:43:39 -04:00
cout << "usage: " << name << " [options] [db address] [file names (ending in .js)]" << endl
<< "db address can be:" << endl
<< " foo foo database on local machine" << endl
<< " 192.169.0.5/foo foo database on 192.168.0.5 machine" << endl
<< " 192.169.0.5:9999/foo foo database on 192.168.0.5 machine on port 9999" << endl
<< options << endl
<< "file names: a list of files to run. files have to end in .js and will exit after "
<< "unless --shell is specified" << endl;
};
2011-01-04 00:40:41 -05:00
bool fileExists( string file ) {
2009-09-19 22:06:36 -04:00
try {
path p(file);
return boost::filesystem::exists( file );
}
2011-01-04 00:40:41 -05:00
catch (...) {
2009-09-19 22:06:36 -04:00
return false;
}
}
2010-06-07 21:50:36 -04:00
namespace mongo {
extern bool isShell;
extern DBClientWithCommands *latestConn;
}
2011-01-04 00:40:41 -05:00
string stateToString(MemberState s) {
if( s.s == MemberState::RS_STARTUP ) return "STARTUP";
if( s.s == MemberState::RS_PRIMARY ) return "PRIMARY";
if( s.s == MemberState::RS_SECONDARY ) return "SECONDARY";
if( s.s == MemberState::RS_RECOVERING ) return "RECOVERING";
if( s.s == MemberState::RS_FATAL ) return "FATAL";
if( s.s == MemberState::RS_STARTUP2 ) return "STARTUP2";
if( s.s == MemberState::RS_ARBITER ) return "ARBITER";
if( s.s == MemberState::RS_DOWN ) return "DOWN";
if( s.s == MemberState::RS_ROLLBACK ) return "ROLLBACK";
return "";
}
2011-01-04 00:40:41 -05:00
string sayReplSetMemberState() {
try {
2011-01-04 00:40:41 -05:00
if( latestConn ) {
BSONObj info;
if( latestConn->runCommand("admin", BSON( "replSetGetStatus" << 1 << "forShell" << 1 ) , info ) ) {
stringstream ss;
ss << info["set"].String() << ':';
2010-11-23 08:18:37 -05:00
int s = info["myState"].Int();
MemberState ms(s);
ss << stateToString(ms);
2010-12-03 15:55:40 -05:00
return ss.str();
}
}
2011-01-04 00:40:41 -05:00
}
2011-02-01 11:38:33 -05:00
catch( std::exception& e ) {
log(1) << "error in sayReplSetMemberState:" << e.what() << endl;
}
2010-12-03 15:55:40 -05:00
return "";
2010-06-07 21:50:36 -04:00
}
2009-08-10 10:25:43 -04:00
int _main(int argc, char* argv[]) {
2010-06-07 21:50:36 -04:00
mongo::isShell = true;
setupSignals();
2009-08-06 14:15:18 -04:00
mongo::shellUtils::RecordMyLocation( argv[ 0 ] );
2009-01-26 22:19:15 -05:00
2009-01-29 07:46:43 -05:00
string url = "test";
string dbhost;
string port;
2009-08-07 10:43:39 -04:00
vector<string> files;
2009-08-06 14:15:18 -04:00
2009-01-26 22:19:15 -05:00
string username;
string password;
bool runShell = false;
2009-01-28 10:25:16 -05:00
bool nodb = false;
2011-01-04 00:40:41 -05:00
string script;
2009-08-06 14:15:18 -04:00
2009-08-07 10:43:39 -04:00
po::options_description shell_options("options");
2009-08-07 16:02:56 -04:00
po::options_description hidden_options("Hidden options");
po::options_description cmdline_options("Command line options");
2009-08-07 10:43:39 -04:00
po::positional_options_description positional_options;
2011-01-04 00:40:41 -05:00
2009-08-07 10:43:39 -04:00
shell_options.add_options()
2011-01-04 00:40:41 -05:00
("shell", "run the shell after executing files")
("nodb", "don't connect to mongod on startup - no 'db address' arg expected")
("quiet", "be less chatty" )
("port", po::value<string>(&port), "port to connect to")
("host", po::value<string>(&dbhost), "server to connect to")
("eval", po::value<string>(&script), "evaluate javascript")
("username,u", po::value<string>(&username), "username for authentication")
("password,p", new mongo::PasswordValue(&password),
"password for authentication")
("help,h", "show this usage information")
("version", "show version information")
2011-02-01 11:38:33 -05:00
("verbose", "increase verbosity")
2011-01-04 00:40:41 -05:00
("ipv6", "enable IPv6 support (disabled by default)")
;
2009-08-07 10:43:39 -04:00
2009-08-07 16:02:56 -04:00
hidden_options.add_options()
2011-01-04 00:40:41 -05:00
("dbaddress", po::value<string>(), "dbaddress")
("files", po::value< vector<string> >(), "files")
("nokillop", "nokillop") // for testing, kill op will also be disabled automatically if the tests starts a mongo program
("autokillop", "autokillop") // for testing, will kill op without prompting
;
2009-08-07 16:02:56 -04:00
2009-08-07 10:43:39 -04:00
positional_options.add("dbaddress", 1);
positional_options.add("files", -1);
2009-08-07 16:02:56 -04:00
cmdline_options.add(shell_options).add(hidden_options);
po::variables_map params;
/* using the same style as db.cpp uses because eventually we're going
* to merge some of this stuff. */
int command_line_style = (((po::command_line_style::unix_style ^
po::command_line_style::allow_guessing) |
po::command_line_style::allow_long_disguise) ^
po::command_line_style::allow_sticky);
try {
po::store(po::command_line_parser(argc, argv).options(cmdline_options).
positional(positional_options).
style(command_line_style).run(), params);
po::notify(params);
2011-01-04 00:40:41 -05:00
}
catch (po::error &e) {
cout << "ERROR: " << e.what() << endl << endl;
show_help_text(argv[0], shell_options);
return mongo::EXIT_BADOPTIONS;
}
2009-08-07 10:43:39 -04:00
// hide password from ps output
2011-01-04 00:40:41 -05:00
for (int i=0; i < (argc-1); ++i) {
if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--password")) {
char* arg = argv[i+1];
2011-01-04 00:40:41 -05:00
while (*arg) {
*arg++ = 'x';
}
}
}
if (params.count("shell")) {
runShell = true;
}
if (params.count("nodb")) {
nodb = true;
}
if (params.count("help")) {
show_help_text(argv[0], shell_options);
return mongo::EXIT_CLEAN;
}
if (params.count("files")) {
files = params["files"].as< vector<string> >();
}
2009-09-22 10:07:53 -04:00
if (params.count("version")) {
cout << "MongoDB shell version: " << mongo::versionString << endl;
return mongo::EXIT_CLEAN;
}
if (params.count("quiet")) {
mongo::cmdLine.quiet = true;
}
if (params.count("nokillop")) {
mongo::shellUtils::_nokillop = true;
}
2010-07-21 18:45:40 -04:00
if (params.count("autokillop")) {
autoKillOp = true;
}
2011-01-04 00:40:41 -05:00
/* This is a bit confusing, here are the rules:
*
* if nodb is set then all positional parameters are files
* otherwise the first positional parameter might be a dbaddress, but
* only if one of these conditions is met:
* - it contains no '.' after the last appearance of '\' or '/'
* - it doesn't end in '.js' and it doesn't specify a path to an existing file */
if (params.count("dbaddress")) {
string dbaddress = params["dbaddress"].as<string>();
if (nodb) {
files.insert(files.begin(), dbaddress);
2011-01-04 00:40:41 -05:00
}
else {
string basename = dbaddress.substr(dbaddress.find_last_of("/\\") + 1);
if (basename.find_first_of('.') == string::npos ||
2011-01-04 00:40:41 -05:00
(basename.find(".js", basename.size() - 3) == string::npos && !fileExists(dbaddress))) {
url = dbaddress;
2011-01-04 00:40:41 -05:00
}
else {
files.insert(files.begin(), dbaddress);
2009-08-07 10:43:39 -04:00
}
2009-01-30 13:00:47 -05:00
}
2009-01-26 22:19:15 -05:00
}
2011-01-04 00:40:41 -05:00
if (params.count("ipv6")) {
mongo::enableIPv6();
}
2011-02-01 11:38:33 -05:00
if (params.count("verbose")) {
logLevel = 1;
}
2011-01-04 00:40:41 -05:00
if ( ! mongo::cmdLine.quiet )
cout << "MongoDB shell version: " << mongo::versionString << endl;
2009-06-24 14:53:58 -04:00
mongo::UnitTest::runTests();
if ( !nodb ) { // connect to db
2010-06-07 11:17:08 -04:00
//if ( ! mongo::cmdLine.quiet ) cout << "url: " << url << endl;
2011-01-04 00:40:41 -05:00
stringstream ss;
if ( mongo::cmdLine.quiet )
ss << "__quiet = true;";
ss << "db = connect( \"" << fixHost( url , dbhost , port ) << "\")";
2011-01-04 00:40:41 -05:00
mongo::shellUtils::_dbConnect = ss.str();
2009-08-06 14:15:18 -04:00
if ( params.count( "password" )
2011-01-04 00:40:41 -05:00
&& ( password.empty() ) ) {
password = mongo::askPassword();
}
2011-01-04 00:40:41 -05:00
if ( username.size() && password.size() ) {
2009-01-26 22:19:15 -05:00
stringstream ss;
ss << "if ( ! db.auth( \"" << username << "\" , \"" << password << "\" ) ){ throw 'login failed'; }";
mongo::shellUtils::_dbAuth = ss.str();
2009-01-26 22:19:15 -05:00
}
2009-08-06 14:15:18 -04:00
}
mongo::ScriptEngine::setConnectCallback( mongo::shellUtils::onConnect );
mongo::ScriptEngine::setup();
mongo::globalScriptEngine->setScopeInitCallback( mongo::shellUtils::initScope );
2011-01-04 00:40:41 -05:00
auto_ptr< mongo::Scope > scope( mongo::globalScriptEngine->newScope() );
2010-06-07 11:06:02 -04:00
shellMainScope = scope.get();
if( runShell )
cout << "type \"help\" for help" << endl;
2011-01-04 00:40:41 -05:00
if ( !script.empty() ) {
mongo::shellUtils::MongoProgramScope s;
2009-08-28 13:26:23 -04:00
if ( ! scope->exec( script , "(shell eval)" , true , true , false ) )
return -4;
}
2009-08-06 14:15:18 -04:00
2009-08-07 10:43:39 -04:00
for (size_t i = 0; i < files.size(); i++) {
mongo::shellUtils::MongoProgramScope s;
2009-08-14 11:06:10 -04:00
if ( files.size() > 1 )
cout << "loading file: " << files[i] << endl;
2011-01-04 00:40:41 -05:00
if ( ! scope->execFile( files[i] , false , true , false ) ) {
2009-08-14 11:06:10 -04:00
cout << "failed to load: " << files[i] << endl;
return -3;
2009-01-26 22:19:15 -05:00
}
}
2009-08-06 14:15:18 -04:00
2009-08-07 10:43:39 -04:00
if ( files.size() == 0 && script.empty() ) {
2009-01-26 22:19:15 -05:00
runShell = true;
2009-08-07 10:43:39 -04:00
}
2009-01-26 22:19:15 -05:00
2011-01-04 00:40:41 -05:00
if ( runShell ) {
2009-08-06 14:15:18 -04:00
mongo::shellUtils::MongoProgramScope s;
2009-02-10 13:45:30 -05:00
shellHistoryInit();
2009-08-06 14:15:18 -04:00
//v8::Handle<v8::Object> shellHelper = baseContext_->Global()->Get( v8::String::New( "shellHelper" ) )->ToObject();
2009-08-06 14:15:18 -04:00
2011-01-04 00:40:41 -05:00
while ( 1 ) {
2009-08-25 17:00:01 -04:00
inMultiLine = 0;
gotInterrupted = 0;
// shellMainScope->localConnect;
//DBClientWithCommands *c = getConnection( JSContext *cx, JSObject *obj );
2010-12-03 15:55:40 -05:00
string prompt(sayReplSetMemberState()+"> ");
2010-12-03 15:55:40 -05:00
char * line = shellReadline( prompt.c_str() );
2011-01-04 00:40:41 -05:00
if ( line ) {
while (startsWith(line, "> "))
line += 2;
2009-07-10 14:17:19 -04:00
while ( line[0] == ' ' )
line++;
}
2011-01-04 00:40:41 -05:00
if ( ! line || ( strlen(line) == 4 && strstr( line , "exit" ) ) ) {
2009-01-26 22:19:15 -05:00
cout << "bye" << endl;
break;
}
2009-08-06 14:15:18 -04:00
2009-01-26 22:19:15 -05:00
string code = line;
2011-01-04 00:40:41 -05:00
if ( code == "exit" || code == "exit;" ) {
2009-03-27 16:11:57 -04:00
break;
}
2009-08-20 13:23:21 -04:00
if ( code.size() == 0 )
continue;
2009-08-25 17:00:01 -04:00
code = finishCode( code );
2011-01-04 00:40:41 -05:00
if ( gotInterrupted ) {
cout << endl;
continue;
}
if ( code.size() == 0 )
break;
2009-08-06 14:15:18 -04:00
bool wascmd = false;
2009-01-26 22:19:15 -05:00
{
string cmd = line;
if ( cmd.find( " " ) > 0 )
cmd = cmd.substr( 0 , cmd.find( " " ) );
2011-01-04 00:40:41 -05:00
if ( cmd.find( "\"" ) == string::npos ) {
2010-02-10 21:57:14 -05:00
try {
scope->exec( (string)"__iscmd__ = shellHelper[\"" + cmd + "\"];" , "(shellhelp1)" , false , true , true );
2011-01-04 00:40:41 -05:00
if ( scope->getBoolean( "__iscmd__" ) ) {
2010-02-10 21:57:14 -05:00
scope->exec( (string)"shellHelper( \"" + cmd + "\" , \"" + code.substr( cmd.size() ) + "\");" , "(shellhelp2)" , false , true , false );
wascmd = true;
}
}
2011-01-04 00:40:41 -05:00
catch ( std::exception& e ) {
cout << "error2:" << e.what() << endl;
2009-06-22 09:31:28 -04:00
wascmd = true;
}
2009-01-26 22:19:15 -05:00
}
2009-08-06 14:15:18 -04:00
2009-01-26 22:19:15 -05:00
}
2009-08-06 14:15:18 -04:00
2011-01-04 00:40:41 -05:00
if ( ! wascmd ) {
2009-09-22 10:22:24 -04:00
try {
if ( scope->exec( code.c_str() , "(shell)" , false , true , false ) )
scope->exec( "shellPrintHelper( __lastres__ );" , "(shell2)" , true , true , false );
2009-09-22 10:22:24 -04:00
}
2011-01-04 00:40:41 -05:00
catch ( std::exception& e ) {
2009-09-22 10:22:24 -04:00
cout << "error:" << e.what() << endl;
}
2009-06-11 20:27:07 -04:00
}
2009-08-06 14:15:18 -04:00
2009-03-27 16:11:57 -04:00
shellHistoryAdd( line );
2009-01-26 22:19:15 -05:00
}
2009-08-06 14:15:18 -04:00
2009-03-27 16:11:57 -04:00
shellHistoryDone();
2009-01-26 22:19:15 -05:00
}
2009-08-06 14:15:18 -04:00
mongo::dbexitCalled = true;
2009-01-26 22:19:15 -05:00
return 0;
}
2009-08-10 10:25:43 -04:00
int main(int argc, char* argv[]) {
static mongo::StaticObserver staticObserver;
2009-08-10 10:25:43 -04:00
try {
return _main( argc , argv );
}
2011-01-04 00:40:41 -05:00
catch ( mongo::DBException& e ) {
2009-08-10 10:25:43 -04:00
cerr << "exception: " << e.what() << endl;
return -1;
2009-08-10 10:25:43 -04:00
}
}
2009-01-26 22:19:15 -05:00