mentat/tools/cli/src/mentat_cli/lib.rs
Nick Alexander 4ea9c78c50 [cli] Part 3: {load,save}_history as appropriate.
It's possible that we should be saving more aggressively -- perhaps
after each entered command -- but we can add that later.
2018-06-22 15:39:29 -07:00

173 lines
4.8 KiB
Rust

// Copyright 2017 Mozilla
//
// 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.
#![crate_name = "mentat_cli"]
use std::path::{
PathBuf,
};
#[macro_use] extern crate failure_derive;
#[macro_use] extern crate log;
#[macro_use] extern crate lazy_static;
extern crate combine;
extern crate env_logger;
extern crate failure;
extern crate getopts;
extern crate linefeed;
extern crate rusqlite;
extern crate tabwriter;
extern crate termion;
extern crate time;
extern crate mentat;
extern crate edn;
extern crate mentat_query;
extern crate mentat_core;
extern crate mentat_db;
use getopts::Options;
use termion::{
color,
};
static HISTORY_FILE_PATH: &str = ".mentat_history";
/// The Mentat CLI stores input history in a readline-compatible file like "~/.mentat_history".
/// This accords with main other tools which prefix with "." and suffix with "_history": lein,
/// node_repl, python, and sqlite, at least.
pub(crate) fn history_file_path() -> PathBuf {
let mut p = ::std::env::home_dir().unwrap_or_default();
p.push(::HISTORY_FILE_PATH);
p
}
static BLUE: color::Rgb = color::Rgb(0x99, 0xaa, 0xFF);
static GREEN: color::Rgb = color::Rgb(0x77, 0xFF, 0x99);
pub mod command_parser;
pub mod input;
pub mod repl;
#[derive(Debug, Fail)]
pub enum CliError {
#[fail(display = "{}", _0)]
CommandParse(String),
}
pub fn run() -> i32 {
env_logger::init();
let args = std::env::args().collect::<Vec<_>>();
let mut opts = Options::new();
opts.optopt("d", "", "The path to a database to open", "DATABASE");
if cfg!(feature = "sqlcipher") {
opts.optopt("k", "key", "The key to use to open the database (only available when using sqlcipher)", "KEY");
}
opts.optflag("h", "help", "Print this help message and exit");
opts.optmulti("q", "query", "Execute a query on startup. Queries are executed after any transacts.", "QUERY");
opts.optmulti("t", "transact", "Execute a transact on startup. Transacts are executed before queries.", "TRANSACT");
opts.optmulti("i", "import", "Execute an import on startup. Imports are executed before queries.", "PATH");
opts.optflag("v", "version", "Print version and exit");
opts.optflag("", "no-tty", "Don't try to use a TTY for readline-like input processing");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(e) => {
println!("{}: {}", args[0], e);
return 1;
}
};
if matches.opt_present("version") {
print_version();
return 0;
}
if matches.opt_present("help") {
print_usage(&args[0], &opts);
return 0;
}
// It's still possible to pass this in even if it's not a documented flag above.
let key = match cfg!(feature = "sqlcipher") {
true => matches.opt_str("key"),
false => None,
};
let mut last_arg: Option<&str> = None;
let cmds:Vec<command_parser::Command> = args.iter().filter_map(|arg| {
match last_arg {
Some("-d") => {
last_arg = None;
if let &Some(ref k) = &key {
Some(command_parser::Command::OpenEncrypted(arg.clone(), k.clone()))
} else {
Some(command_parser::Command::Open(arg.clone()))
}
},
Some("-q") => {
last_arg = None;
Some(command_parser::Command::Query(arg.clone()))
},
Some("-i") => {
last_arg = None;
Some(command_parser::Command::Import(arg.clone()))
},
Some("-t") => {
last_arg = None;
Some(command_parser::Command::Transact(arg.clone()))
},
Some(_) |
None => {
last_arg = Some(&arg);
None
},
}
}).collect();
let mut repl = match repl::Repl::new(!matches.opt_present("no-tty")) {
Ok(repl) => repl,
Err(e) => {
println!("{}", e);
return 1
}
};
repl.run(Some(cmds));
0
}
/// Returns a version string.
pub fn version() -> &'static str {
env!("CARGO_PKG_VERSION")
}
fn print_usage(arg0: &str, opts: &Options) {
print!("{}", opts.usage(&format!(
"Usage: {} [OPTIONS] [FILE]", arg0)));
}
fn print_version() {
println!("mentat {}", version());
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
}
}