Read from file and execute

This commit is contained in:
Emily Toop 2017-05-26 14:01:32 +01:00
parent 66c402b205
commit de616a4f62
5 changed files with 89 additions and 22 deletions

View file

@ -12,14 +12,14 @@ doc = false
test = false
[dependencies]
combine = "2.2.2"
getopts = "0.2"
env_logger = "0.3"
error-chain = "0.8.1"
lazy_static = "0.2.2"
linefeed = "0.1"
log = "0.3"
tempfile = "1.1"
combine = "2.2.2"
lazy_static = "0.2.2"
error-chain = "0.8.1"
[dependencies.rusqlite]
version = "0.11"

View file

@ -59,16 +59,17 @@ impl Command {
/// false is returned if the command is not considered valid.
/// Defaults to true for all commands except Query and Transact.
/// TODO: for query and transact commands, they will be considered complete if a parsable EDN has been entered as an argument
pub fn is_complete(&self) -> bool {
pub fn is_complete(&self) -> (bool, Option<edn::ParseError>) {
match self {
&Command::Query(ref args) |
&Command::Transact(ref args) => {
edn::parse::value(&args).is_ok()
let r = edn::parse::value(&args);
(r.is_ok(), r.err())
},
&Command::Help(_) |
&Command::Open(_) |
&Command::Close |
&Command::Read(_) => true
&Command::Read(_) => (true, None)
}
}
@ -155,7 +156,8 @@ pub fn command(s: &str) -> Result<Command, cli::Error> {
.with(arguments())
.map(|args| {
// strip quotes from file paths.
let mut sargs = Vec::with_capacity(args.len());
// not sure how to map this and still throw the error so doing it the old fashioned way
let mut files = Vec::with_capacity(args.len());
for arg in args.iter() {
let start_char = arg.chars().nth(0);
match start_char {
@ -163,19 +165,20 @@ pub fn command(s: &str) -> Result<Command, cli::Error> {
Some('\'') => {
let separator = start_char.unwrap();
if arg.ends_with(separator) {
sargs.push(arg.split(separator).collect::<Vec<&str>>().into_iter().collect());
files.push(arg.split(separator).collect::<Vec<&str>>().into_iter().collect());
} else {
return Err(cli::ErrorKind::CommandParse(format!("Unrecognized argument {}", arg)).into());
}
},
_ => sargs.push(arg.clone()),
_ => files.push(arg.clone()),
}
}
println!("args: {:?}", sargs);
// check that we have at least one argument
if args.len() == 0 {
return Err(cli::ErrorKind::CommandParse("Missing required argument".to_string()).into());
}
Ok(Command::Read(sargs.clone()))
Ok(Command::Read(files.clone()))
});
spaces()

View file

@ -13,6 +13,7 @@
use rusqlite;
use mentat::errors as mentat;
use edn;
error_chain! {
types {
@ -20,6 +21,7 @@ error_chain! {
}
foreign_links {
EdnParseError(edn::ParseError);
Rusqlite(rusqlite::Error);
}
@ -32,5 +34,10 @@ error_chain! {
description("An error occured parsing the entered command")
display("{}", message)
}
FileError(filename: String, message: String) {
description("An error occured while reading file")
display("Unable to open file {}: {}", filename, message)
}
}
}

View file

@ -102,13 +102,20 @@ impl InputReader {
Command::Transact(args.clone() + " " + &line)
},
_ => {
try!(command(&self.buffer))
let res = command(&self.buffer);
match res {
Ok(cmd) => cmd,
Err(err) => {
self.buffer.clear();
bail!(err)
}
}
}
};
match cmd {
Command::Query(_) |
Command::Transact(_) if !cmd.is_complete() => {
Command::Transact(_) if !cmd.is_complete().0 => {
// a query or transact is complete if it contains a valid edn.
// if the command is not complete, ask for more from the repl and remember
// which type of command we've found here.

View file

@ -9,6 +9,15 @@
// specific language governing permissions and limitations under the License.
use std::collections::HashMap;
use std::io::BufReader;
use std::io::BufRead;
use std::fs::File;
use std::path::Path;
use error_chain::ChainedError;
use errors as cli;
use edn;
use mentat::query::QueryResults;
use mentat_core::TypedValue;
@ -44,7 +53,7 @@ lazy_static! {
map.insert(SHORT_QUERY_COMMAND, "Shortcut for `.query`. Execute a query against the current open database.");
map.insert(LONG_TRANSACT_COMMAND, "Execute a transact against the current open database.");
map.insert(SHORT_TRANSACT_COMMAND, "Shortcut for `.transact`. Execute a transact against the current open database.");
map.insert(READ_COMMAND, "Read in the file provided in argument. Transact each edn in turn.");
map.insert(READ_COMMAND, "Read a file containing one or more complete edn transact statements. Transacts each edn in turn.");
map
};
}
@ -90,7 +99,7 @@ impl Repl {
}
break;
},
Err(e) => println!("{}", e.to_string()),
Err(e) => println!("{}", e.display()),
}
}
}
@ -102,19 +111,19 @@ impl Repl {
Command::Open(db) => {
match self.store.open(Some(db.clone())) {
Ok(_) => println!("Database {:?} opened", db_output_name(&db)),
Err(e) => println!("{}", e.to_string())
Err(e) => println!("{}", e.display())
};
},
Command::Close => {
let old_db_name = self.store.db_name.clone();
match self.store.close() {
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),
Command::Read(file) => self.read_file(file),
Command::Read(file) => self.read_files(file),
}
}
@ -143,7 +152,7 @@ impl Repl {
Result::Ok(vals) => {
vals
},
Result::Err(err) => return println!("{:?}.", err),
Result::Err(err) => return println!("{}.", err.display()),
};
if results.is_empty() {
@ -181,7 +190,7 @@ impl Repl {
fn execute_transact(&mut self, transaction: String) {
match self.store.transact(transaction) {
Result::Ok(report) => println!("{:?}", report),
Result::Err(err) => println!("{:?}.", err),
Result::Err(err) => println!("{}.", err.display()),
}
}
@ -198,11 +207,52 @@ impl Repl {
}
}
fn read_file(&self, files: Vec<String>) {
fn read_files(&mut self, files: Vec<String>) {
for file in files {
println!("Executing edn in file {}", file);
let res = self.read_file(file);
if res.is_err() {
match res.unwrap_err() {
cli::Error(err, _) => { println!("{}", err) },
}
}
}
}
fn read_file(&mut self, file: String) -> Result<(), cli::Error> {
let path = Path::new(&file);
let display = path.display();
let f = match File::open(&path) {
Err(err) => bail!(cli::ErrorKind::FileError(display.to_string(), err.to_string())),
Ok(file) => file,
};
let mut buffer = String::new();
let mut cmd_err: Option<edn::ParseError> = None;
let file = BufReader::new(&f);
for line in file.lines() {
let l = line.unwrap();
println!("{}", l);
buffer.push_str(&l);
let cmd = Command::Transact(buffer.to_string());
let (is_complete, err) = cmd.is_complete();
if is_complete {
self.handle_command(cmd);
buffer.clear();
cmd_err = None;
} else {
cmd_err = err;
}
}
if let Some(err) = cmd_err {
println!("\nUnable to parse edn: {}", err.to_string());
}
Ok(())
}
}
#[cfg(test)]