Read from file and execute
This commit is contained in:
parent
66c402b205
commit
de616a4f62
5 changed files with 89 additions and 22 deletions
|
@ -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"
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,12 +207,53 @@ 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)]
|
||||
mod tests {
|
||||
|
|
Loading…
Reference in a new issue