* Implement exit command for cli tool * Address review comments r=rnewman * Include exit commands in help
This commit is contained in:
parent
46fc1615fb
commit
ecc926086a
2 changed files with 87 additions and 20 deletions
|
@ -13,7 +13,6 @@ use combine::{
|
||||||
eof,
|
eof,
|
||||||
look_ahead,
|
look_ahead,
|
||||||
many1,
|
many1,
|
||||||
parser,
|
|
||||||
satisfy,
|
satisfy,
|
||||||
sep_end_by,
|
sep_end_by,
|
||||||
token,
|
token,
|
||||||
|
@ -29,8 +28,6 @@ use combine::combinator::{
|
||||||
try
|
try
|
||||||
};
|
};
|
||||||
|
|
||||||
use combine::primitives::Consumed;
|
|
||||||
|
|
||||||
use errors as cli;
|
use errors as cli;
|
||||||
|
|
||||||
use edn;
|
use edn;
|
||||||
|
@ -42,14 +39,17 @@ pub static LONG_QUERY_COMMAND: &'static str = &"query";
|
||||||
pub static SHORT_QUERY_COMMAND: &'static str = &"q";
|
pub static SHORT_QUERY_COMMAND: &'static str = &"q";
|
||||||
pub static LONG_TRANSACT_COMMAND: &'static str = &"transact";
|
pub static LONG_TRANSACT_COMMAND: &'static str = &"transact";
|
||||||
pub static SHORT_TRANSACT_COMMAND: &'static str = &"t";
|
pub static SHORT_TRANSACT_COMMAND: &'static str = &"t";
|
||||||
|
pub static LONG_EXIT_COMMAND: &'static str = &"exit";
|
||||||
|
pub static SHORT_EXIT_COMMAND: &'static str = &"e";
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
Transact(String),
|
Close,
|
||||||
Query(String),
|
Exit,
|
||||||
Help(Vec<String>),
|
Help(Vec<String>),
|
||||||
Open(String),
|
Open(String),
|
||||||
Close,
|
Query(String),
|
||||||
|
Transact(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command {
|
impl Command {
|
||||||
|
@ -65,7 +65,8 @@ impl Command {
|
||||||
},
|
},
|
||||||
&Command::Help(_) |
|
&Command::Help(_) |
|
||||||
&Command::Open(_) |
|
&Command::Open(_) |
|
||||||
&Command::Close => true
|
&Command::Close |
|
||||||
|
&Command::Exit => true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +87,9 @@ impl Command {
|
||||||
&Command::Close => {
|
&Command::Close => {
|
||||||
format!(".{}", CLOSE_COMMAND)
|
format!(".{}", CLOSE_COMMAND)
|
||||||
},
|
},
|
||||||
|
&Command::Exit => {
|
||||||
|
format!(".{}", LONG_EXIT_COMMAND)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,17 +117,28 @@ pub fn command(s: &str) -> Result<Command, cli::Error> {
|
||||||
Ok(Command::Open(args[0].clone()))
|
Ok(Command::Open(args[0].clone()))
|
||||||
});
|
});
|
||||||
|
|
||||||
let close_parser = string(CLOSE_COMMAND)
|
let no_arg_parser = || arguments()
|
||||||
.with(arguments())
|
|
||||||
.skip(spaces())
|
.skip(spaces())
|
||||||
.skip(eof())
|
.skip(eof());
|
||||||
|
|
||||||
|
let close_parser = string(CLOSE_COMMAND)
|
||||||
|
.with(no_arg_parser())
|
||||||
.map(|args| {
|
.map(|args| {
|
||||||
if args.len() > 0 {
|
if !args.is_empty() {
|
||||||
bail!(cli::ErrorKind::CommandParse(format!("Unrecognized argument {:?}", args[0])) );
|
bail!(cli::ErrorKind::CommandParse(format!("Unrecognized argument {:?}", args[0])) );
|
||||||
}
|
}
|
||||||
Ok(Command::Close)
|
Ok(Command::Close)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let exit_parser = try(string(LONG_EXIT_COMMAND)).or(try(string(SHORT_EXIT_COMMAND)))
|
||||||
|
.with(no_arg_parser())
|
||||||
|
.map(|args| {
|
||||||
|
if !args.is_empty() {
|
||||||
|
bail!(cli::ErrorKind::CommandParse(format!("Unrecognized argument {:?}", args[0])) );
|
||||||
|
}
|
||||||
|
Ok(Command::Exit)
|
||||||
|
});
|
||||||
|
|
||||||
let edn_arg_parser = || spaces()
|
let edn_arg_parser = || spaces()
|
||||||
.with(look_ahead(string("[").or(string("{")))
|
.with(look_ahead(string("[").or(string("{")))
|
||||||
.with(many1::<Vec<_>, _>(try(any())))
|
.with(many1::<Vec<_>, _>(try(any())))
|
||||||
|
@ -146,10 +161,11 @@ pub fn command(s: &str) -> Result<Command, cli::Error> {
|
||||||
|
|
||||||
spaces()
|
spaces()
|
||||||
.skip(token('.'))
|
.skip(token('.'))
|
||||||
.with(choice::<[&mut Parser<Input = _, Output = Result<Command, cli::Error>>; 5], _>
|
.with(choice::<[&mut Parser<Input = _, Output = Result<Command, cli::Error>>; 6], _>
|
||||||
([&mut try(help_parser),
|
([&mut try(help_parser),
|
||||||
&mut try(open_parser),
|
&mut try(open_parser),
|
||||||
&mut try(close_parser),
|
&mut try(close_parser),
|
||||||
|
&mut try(exit_parser),
|
||||||
&mut try(query_parser),
|
&mut try(query_parser),
|
||||||
&mut try(transact_parser)]))
|
&mut try(transact_parser)]))
|
||||||
.parse(s)
|
.parse(s)
|
||||||
|
@ -294,6 +310,43 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_exit_parser_with_args() {
|
||||||
|
let input = ".exit arg1";
|
||||||
|
let err = command(&input).expect_err("Expected an error");
|
||||||
|
assert_eq!(err.to_string(), format!("Invalid command {:?}", input));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_exit_parser_no_args() {
|
||||||
|
let input = ".exit";
|
||||||
|
let cmd = command(&input).expect("Expected exit command");
|
||||||
|
match cmd {
|
||||||
|
Command::Exit => assert!(true),
|
||||||
|
_ => assert!(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_exit_parser_no_args_trailing_whitespace() {
|
||||||
|
let input = ".exit ";
|
||||||
|
let cmd = command(&input).expect("Expected exit command");
|
||||||
|
match cmd {
|
||||||
|
Command::Exit => assert!(true),
|
||||||
|
_ => assert!(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_exit_parser_short_command() {
|
||||||
|
let input = ".e";
|
||||||
|
let cmd = command(&input).expect("Expected exit command");
|
||||||
|
match cmd {
|
||||||
|
Command::Exit => assert!(true),
|
||||||
|
_ => assert!(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_query_parser_complete_edn() {
|
fn test_query_parser_complete_edn() {
|
||||||
let input = ".q [:find ?x :where [?x foo/bar ?y]]";
|
let input = ".q [:find ?x :where [?x foo/bar ?y]]";
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::process;
|
||||||
|
|
||||||
|
use error_chain::ChainedError;
|
||||||
|
|
||||||
use mentat::query::QueryResults;
|
use mentat::query::QueryResults;
|
||||||
use mentat_core::TypedValue;
|
use mentat_core::TypedValue;
|
||||||
|
@ -21,6 +24,8 @@ use command_parser::{
|
||||||
SHORT_QUERY_COMMAND,
|
SHORT_QUERY_COMMAND,
|
||||||
LONG_TRANSACT_COMMAND,
|
LONG_TRANSACT_COMMAND,
|
||||||
SHORT_TRANSACT_COMMAND,
|
SHORT_TRANSACT_COMMAND,
|
||||||
|
LONG_EXIT_COMMAND,
|
||||||
|
SHORT_EXIT_COMMAND,
|
||||||
};
|
};
|
||||||
use input::InputReader;
|
use input::InputReader;
|
||||||
use input::InputResult::{
|
use input::InputResult::{
|
||||||
|
@ -37,6 +42,8 @@ use store::{
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref COMMAND_HELP: HashMap<&'static str, &'static str> = {
|
static ref COMMAND_HELP: HashMap<&'static str, &'static str> = {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
map.insert(LONG_EXIT_COMMAND, "Close the current database and exit the REPL.");
|
||||||
|
map.insert(SHORT_EXIT_COMMAND, "Shortcut for `.exit`. Close the current database and exit the REPL.");
|
||||||
map.insert(HELP_COMMAND, "Show help for commands.");
|
map.insert(HELP_COMMAND, "Show help for commands.");
|
||||||
map.insert(OPEN_COMMAND, "Open a database at path.");
|
map.insert(OPEN_COMMAND, "Open a database at path.");
|
||||||
map.insert(LONG_QUERY_COMMAND, "Execute a query against the current open database.");
|
map.insert(LONG_QUERY_COMMAND, "Execute a query against the current open database.");
|
||||||
|
@ -103,16 +110,23 @@ impl Repl {
|
||||||
Err(e) => println!("{}", e.to_string())
|
Err(e) => println!("{}", e.to_string())
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
Command::Close => {
|
Command::Close => self.close(),
|
||||||
|
Command::Query(query) => self.execute_query(query),
|
||||||
|
Command::Transact(transaction) => self.execute_transact(transaction),
|
||||||
|
Command::Exit => {
|
||||||
|
self.close();
|
||||||
|
println!("Exiting...");
|
||||||
|
process::exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&mut self) {
|
||||||
let old_db_name = self.store.db_name.clone();
|
let old_db_name = self.store.db_name.clone();
|
||||||
match self.store.close() {
|
match self.store.close() {
|
||||||
Ok(_) => println!("Database {:?} closed", db_output_name(&old_db_name)),
|
Ok(_) => println!("Database {:?} closed", db_output_name(&old_db_name)),
|
||||||
Err(e) => println!("{}", e.to_string())
|
Err(e) => println!("{}", e.display())
|
||||||
};
|
};
|
||||||
},
|
|
||||||
Command::Query(query) => self.execute_query(query),
|
|
||||||
Command::Transact(transaction) => self.execute_transact(transaction),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn help_command(&self, args: Vec<String>) {
|
fn help_command(&self, args: Vec<String>) {
|
||||||
|
|
Loading…
Reference in a new issue