From 6b82e3a8a8c83fceed216b26176646bd1299e42b Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Wed, 15 May 2019 17:21:46 -0700 Subject: [PATCH] Simplify commands --- src/commands/cd.rs | 32 ++++++-------------------------- src/commands/command.rs | 9 ++++++++- src/commands/ls.rs | 28 +++++----------------------- src/commands/ps.rs | 17 +---------------- src/commands/reject.rs | 38 ++++++++++++-------------------------- src/commands/select.rs | 38 ++++++++++++-------------------------- src/commands/take.rs | 38 ++++++++++---------------------------- src/commands/to_array.rs | 18 ++---------------- src/context.rs | 26 +++++++++++++++++++------- src/main.rs | 23 ++++++++++++++--------- src/prelude.rs | 2 +- 11 files changed, 90 insertions(+), 179 deletions(-) diff --git a/src/commands/cd.rs b/src/commands/cd.rs index d7104f388..399610b8a 100644 --- a/src/commands/cd.rs +++ b/src/commands/cd.rs @@ -1,42 +1,22 @@ use crate::errors::ShellError; -use crate::object::Value; use crate::prelude::*; use derive_new::new; -use std::path::PathBuf; #[derive(new)] -pub struct CdBlueprint; +pub struct Cd; -impl crate::CommandBlueprint for CdBlueprint { - fn create( - &self, - args: Vec, - _host: &dyn Host, - env: &mut Environment, - ) -> Result, ShellError> { - let target = match args.first() { +impl crate::Command for Cd { + fn run(&self, args: CommandArgs<'caller>) -> Result, ShellError> { + let target = match args.args.first() { // TODO: This needs better infra None => return Err(ShellError::string(format!("cd must take one arg"))), Some(v) => v.as_string()?.clone(), }; - Ok(Box::new(Cd { - cwd: env.cwd().to_path_buf(), - target, - })) - } -} + let cwd = args.env.cwd().to_path_buf(); -#[derive(new)] -pub struct Cd { - cwd: PathBuf, - target: String, -} - -impl crate::Command for Cd { - fn run(&mut self, _stream: VecDeque) -> Result, ShellError> { let mut stream = VecDeque::new(); - let path = dunce::canonicalize(self.cwd.join(&self.target).as_path())?; + let path = dunce::canonicalize(cwd.join(&target).as_path())?; stream.push_back(ReturnValue::change_cwd(path)); Ok(stream) } diff --git a/src/commands/command.rs b/src/commands/command.rs index 753135f86..e3cff2f25 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -3,6 +3,13 @@ use crate::object::Value; use crate::prelude::*; use std::path::PathBuf; +pub struct CommandArgs<'caller> { + pub host: &'caller dyn Host, + pub env: &'caller crate::Environment, + pub args: Vec, + pub input: VecDeque, +} + pub trait CommandBlueprint { fn create( &self, @@ -36,5 +43,5 @@ impl ReturnValue { } pub trait Command { - fn run(&mut self, stream: VecDeque) -> Result, ShellError>; + fn run(&self, args: CommandArgs<'caller>) -> Result, ShellError>; } diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 29f089cd6..aec984a50 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -1,35 +1,17 @@ use crate::errors::ShellError; use crate::object::{dir_entry_dict, Value}; use crate::prelude::*; -use crate::Command; use derive_new::new; -use std::path::PathBuf; #[derive(new)] -pub struct LsBlueprint; - -impl crate::CommandBlueprint for LsBlueprint { - fn create( - &self, - _args: Vec, - _host: &dyn crate::Host, - env: &mut crate::Environment, - ) -> Result, ShellError> { - Ok(Box::new(Ls { - cwd: env.cwd().to_path_buf(), - })) - } -} - -#[derive(new)] -pub struct Ls { - cwd: PathBuf, -} +pub struct Ls; impl crate::Command for Ls { - fn run(&mut self, _stream: VecDeque) -> Result, ShellError> { + fn run(&self, args: CommandArgs<'value>) -> Result, ShellError> { + let cwd = args.env.cwd().to_path_buf(); + let entries = - std::fs::read_dir(&self.cwd).map_err(|e| ShellError::string(format!("{:?}", e)))?; + std::fs::read_dir(&cwd).map_err(|e| ShellError::string(format!("{:?}", e)))?; let mut shell_entries = VecDeque::new(); diff --git a/src/commands/ps.rs b/src/commands/ps.rs index cb4ea3b6a..c06543f4f 100644 --- a/src/commands/ps.rs +++ b/src/commands/ps.rs @@ -2,29 +2,14 @@ use crate::errors::ShellError; use crate::object::process::process_dict; use crate::object::Value; use crate::prelude::*; -use crate::Command; use derive_new::new; use sysinfo::SystemExt; -#[derive(new)] -pub struct PsBlueprint; - -impl crate::CommandBlueprint for PsBlueprint { - fn create( - &self, - _args: Vec, - _host: &dyn crate::Host, - _env: &mut crate::Environment, - ) -> Result, ShellError> { - Ok(Box::new(Ps::new())) - } -} - #[derive(new)] pub struct Ps; impl crate::Command for Ps { - fn run(&mut self, _stream: VecDeque) -> Result, ShellError> { + fn run(&self, _args: CommandArgs<'caller>) -> Result, ShellError> { let mut system = sysinfo::System::new(); system.refresh_all(); diff --git a/src/commands/reject.rs b/src/commands/reject.rs index 057ccd5cf..4780ac013 100644 --- a/src/commands/reject.rs +++ b/src/commands/reject.rs @@ -5,35 +5,21 @@ use crate::prelude::*; use derive_new::new; #[derive(new)] -pub struct RejectBlueprint; - -impl crate::CommandBlueprint for RejectBlueprint { - fn create( - &self, - args: Vec, - _host: &dyn Host, - _env: &mut Environment, - ) -> Result, ShellError> { - if args.is_empty() { - return Err(ShellError::string("take requires an integer")); - } - - let fields: Result<_, _> = args.iter().map(|a| a.as_string()).collect(); - - Ok(Box::new(Reject { fields: fields? })) - } -} - -#[derive(new)] -pub struct Reject { - fields: Vec, -} +pub struct Reject; impl crate::Command for Reject { - fn run(&mut self, stream: VecDeque) -> Result, ShellError> { - let objects = stream + fn run(&self, args: CommandArgs<'value>) -> Result, ShellError> { + if args.args.is_empty() { + return Err(ShellError::string("select requires a field")); + } + + let fields: Result, _> = args.args.iter().map(|a| a.as_string()).collect(); + let fields = fields?; + + let objects = args + .input .iter() - .map(|item| Value::Object(reject(item, &self.fields))) + .map(|item| Value::Object(reject(item, &fields))) .map(|item| ReturnValue::Value(item)) .collect(); diff --git a/src/commands/select.rs b/src/commands/select.rs index 8f890d827..15298c9c2 100644 --- a/src/commands/select.rs +++ b/src/commands/select.rs @@ -5,35 +5,21 @@ use crate::prelude::*; use derive_new::new; #[derive(new)] -pub struct SelectBlueprint; - -impl crate::CommandBlueprint for SelectBlueprint { - fn create( - &self, - args: Vec, - _host: &dyn Host, - _env: &mut Environment, - ) -> Result, ShellError> { - if args.is_empty() { - return Err(ShellError::string("take requires an integer")); - } - - let fields: Result<_, _> = args.iter().map(|a| a.as_string()).collect(); - - Ok(Box::new(Select { fields: fields? })) - } -} - -#[derive(new)] -pub struct Select { - fields: Vec, -} +pub struct Select; impl crate::Command for Select { - fn run(&mut self, stream: VecDeque) -> Result, ShellError> { - let objects = stream + fn run(&self, args: CommandArgs<'caller>) -> Result, ShellError> { + if args.args.is_empty() { + return Err(ShellError::string("select requires a field")); + } + + let fields: Result, _> = args.args.iter().map(|a| a.as_string()).collect(); + let fields = fields?; + + let objects = args + .input .iter() - .map(|item| Value::Object(select(item, &self.fields))) + .map(|item| Value::Object(select(item, &fields))) .map(|item| ReturnValue::Value(item)) .collect(); diff --git a/src/commands/take.rs b/src/commands/take.rs index 64a95486e..c4753e0d6 100644 --- a/src/commands/take.rs +++ b/src/commands/take.rs @@ -1,42 +1,24 @@ use crate::errors::ShellError; -use crate::object::Value; use crate::prelude::*; use derive_new::new; #[derive(new)] -pub struct TakeBlueprint; +pub struct Take; -impl crate::CommandBlueprint for TakeBlueprint { - fn create( - &self, - args: Vec, - _host: &dyn Host, - _env: &mut Environment, - ) -> Result, ShellError> { - if args.is_empty() { - return Err(ShellError::string("take requires an integer")); - } - - let amount = args[0].as_int()?; - - Ok(Box::new(Take { amount })) - } -} - -#[derive(new)] -pub struct Take { - amount: i64, -} +// TODO: "Amount remaining" wrapper impl crate::Command for Take { - fn run(&mut self, stream: VecDeque) -> Result, ShellError> { - let amount = if stream.len() > self.amount as usize { - self.amount as usize + fn run(&self, args: CommandArgs<'caller>) -> Result, ShellError> { + let amount = args.args[0].as_int()?; + + let amount = if args.input.len() > amount as usize { + amount as usize } else { - stream.len() + args.input.len() }; - let out: VecDeque = stream + let out: VecDeque = args + .input .into_iter() .take(amount) .map(|v| ReturnValue::Value(v)) diff --git a/src/commands/to_array.rs b/src/commands/to_array.rs index feb01e62f..f20ee55dc 100644 --- a/src/commands/to_array.rs +++ b/src/commands/to_array.rs @@ -3,26 +3,12 @@ use crate::object::Value; use crate::prelude::*; use derive_new::new; -#[derive(new)] -pub struct ToArrayBlueprint; - -impl crate::CommandBlueprint for ToArrayBlueprint { - fn create( - &self, - _args: Vec, - _host: &dyn Host, - _env: &mut Environment, - ) -> Result, ShellError> { - Ok(Box::new(ToArray)) - } -} - #[derive(new)] pub struct ToArray; impl crate::Command for ToArray { - fn run(&mut self, stream: VecDeque) -> Result, ShellError> { - let out = stream.into_iter().collect(); + fn run(&self, args: CommandArgs<'caller>) -> Result, ShellError> { + let out = args.input.into_iter().collect(); Ok(ReturnValue::single(Value::List(out))) } } diff --git a/src/context.rs b/src/context.rs index b420b05d5..e87d23ff6 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,8 +1,9 @@ use crate::prelude::*; + use std::error::Error; pub struct Context { - commands: indexmap::IndexMap>, + commands: indexmap::IndexMap>, crate host: Box, crate env: Environment, } @@ -16,7 +17,7 @@ impl Context { }) } - pub fn add_commands(&mut self, commands: Vec<(&str, Box)>) { + pub fn add_commands(&mut self, commands: Vec<(&str, Box)>) { for (name, command) in commands { self.commands.insert(name.to_string(), command); } @@ -26,14 +27,25 @@ impl Context { self.commands.contains_key(name) } - crate fn create_command( - &mut self, + crate fn run_command( + &self, name: &str, arg_list: Vec, - ) -> Result, ShellError> { + input: VecDeque, + ) -> Result, ShellError> { + let command_args = CommandArgs { + host: &self.host, + env: &self.env, + args: arg_list, + input, + }; + match self.commands.get(name) { - Some(command) => Ok(command.create(arg_list, &self.host, &mut self.env)?), - None => Err(ShellError::string(format!("Missing command {}", name))), + None => Err(ShellError::string(format!( + "Command {} did not exist", + name + ))), + Some(command) => command.run(command_args), } } } diff --git a/src/main.rs b/src/main.rs index 7c8316ce0..6eba36722 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] +#[allow(unused)] +use crate::prelude::*; + mod commands; mod context; mod env; @@ -53,13 +56,13 @@ fn main() -> Result<(), Box> { use crate::commands::*; context.lock().unwrap().add_commands(vec![ - ("ps", Box::new(ps::PsBlueprint)), - ("ls", Box::new(ls::LsBlueprint)), - ("cd", Box::new(cd::CdBlueprint)), - ("take", Box::new(take::TakeBlueprint)), - ("select", Box::new(select::SelectBlueprint)), - ("reject", Box::new(reject::RejectBlueprint)), - ("to-array", Box::new(to_array::ToArrayBlueprint)), + ("ps", Box::new(ps::Ps)), + ("ls", Box::new(ls::Ls)), + ("cd", Box::new(cd::Cd)), + ("take", Box::new(take::Take)), + ("select", Box::new(select::Select)), + ("reject", Box::new(reject::Reject)), + ("to-array", Box::new(to_array::ToArray)), ]); } @@ -140,9 +143,11 @@ fn process_command( match ctx.has_command(*command) { true => { - let mut instance = ctx.create_command(command, arg_list)?; + // let mut instance = ctx.create_command(command, arg_list)?; - let result = instance.run(input)?; + let result = ctx.run_command(command, arg_list, input)?; + + // let result = command.run(input_args)?; let mut next = VecDeque::new(); for v in result { diff --git a/src/prelude.rs b/src/prelude.rs index f115ad8d8..3dec21a32 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,4 +1,4 @@ -crate use crate::commands::command::{Command, ReturnValue}; +crate use crate::commands::command::{CommandArgs, ReturnValue}; crate use crate::env::{Environment, Host}; crate use crate::errors::ShellError; crate use crate::object::{Primitive, Value};