From 3064ba5b173c75811b714b7a8ccca0de30bcd1d3 Mon Sep 17 00:00:00 2001 From: Daniel Bulant Date: Sun, 6 Aug 2023 16:01:39 +0200 Subject: [PATCH] improved redirection handling --- src/parser/exec.rs | 284 ++++++++++++++++++++++++--------------------- src/parser/vars.rs | 65 ++++++++++- 2 files changed, 209 insertions(+), 140 deletions(-) diff --git a/src/parser/exec.rs b/src/parser/exec.rs index 0ca7b10..f9be175 100644 --- a/src/parser/exec.rs +++ b/src/parser/exec.rs @@ -1,11 +1,45 @@ use std::fs::File; -use std::process::{Command}; +use std::io::Read; +use std::process::Command; +use std::thread; use crate::parser::ast::{AndExpression, BreakExpression, CommandValue, Expression, FileSourceExpression, FileTargetExpression, ForExpression, IfExpression, LetExpression, OrExpression, RedirectTargetExpression, Value, WhileExpression}; -use crate::parser::vars::{AnyFunction, Context, Variable}; +use crate::parser::vars::{AnyFunction, Context, ReaderOverride, Variable, WriterOverride}; use anyhow::{Result, bail, Context as AnyhowContext}; +#[derive(Debug, Default)] +struct ExecResult { + commands: Vec +} + +impl ExecResult { + fn exec(self, ctx: &mut Context) -> Result> { + let mut children = Vec::new(); + for mut command in self.commands { + let name = command.get_program().to_str().unwrap_or("unknown").to_string(); + let out = command.spawn() + .with_context(|| "Failed to spawn process ".to_string() + &name)?; + drop(command); + children.push(out); + } + let mut code = None; + for mut child in children { + let out = child.wait() + .with_context(|| "Command failed")?; + code = Some(out.code().unwrap_or(-1)); + } + if let Some(code) = code { + ctx.set_var(String::from("?"), Variable::I32(code)); + } + Ok(code) + } + + fn merge(&mut self, mut other: ExecResult) { + self.commands.append(&mut other.commands); + } +} + trait ExecExpression { - fn exec(&mut self, ctx: &mut Context) -> Result>; + fn exec(&mut self, ctx: &mut Context) -> Result; } trait GetValue { @@ -30,19 +64,22 @@ impl GetValue for Value { Value::Variable(str) => Ok(ctx.get_var(str).unwrap_or(&mut Variable::String(String::from(""))).clone()), Value::ArrayVariable(str) => Ok(ctx.get_var(str).unwrap_or(&mut Variable::Array(Vec::new())).clone()), Value::Expressions(expressions) => { - let mut out = String::new(); ctx.add_scope(); - for expr in expressions { - let res = expr.exec(ctx)?; - match res { - None => {}, - Some(mut cmd) => { - out += &*String::from_utf8_lossy(&cmd.output().with_context(|| "Failed to read output of command")?.stdout); - } - } - } + let (mut reader, writer) = os_pipe::pipe()?; + let mut data = String::new(); + thread::scope(|s| -> Result<()> { + ctx.scopes.last_mut().unwrap().stdout_override = Some(WriterOverride::Pipe(writer)); + s.spawn(|| -> Result<()> { + let mut buf = Vec::new(); + reader.read_to_end(&mut buf)?; + data = String::from_utf8_lossy(&buf).to_string(); + Ok(()) + }); + expressions.exec(ctx)?.exec(ctx)?; + Ok(()) + })?; ctx.pop_scope(); - Ok(Variable::String(out)) + Ok(Variable::String(data)) }, Value::Values(vec) | Value::ArrayDefinition(vec) => { let mut out = Vec::new(); @@ -74,7 +111,7 @@ fn get_variables(ctx: &mut Context, args: &mut Vec) -> Result Result> { + fn exec(self: &mut Expression, ctx: &mut Context) -> Result { match self { Expression::LetExpression(expr) => expr.exec(ctx), Expression::Command(expr) => expr.exec(ctx), @@ -94,58 +131,33 @@ impl ExecExpression for Expression { } } -impl ExecExpression for Command { - fn exec(&mut self, ctx: &mut Context) -> Result> { - let overrides = ctx.get_overrides()?; - if let Some(stdout) = overrides.stdout { self.stdout(stdout); } - if let Some(stderr) = overrides.stderr { self.stderr(stderr); } - if let Some(stdin) = overrides.stdin { self.stdin(stdin); } - let name = self.get_program().to_str().unwrap_or("unknown").to_string(); - let out = self.spawn() - .with_context(|| "Failed to spawn process ".to_string() + &name)? - .wait() - .with_context(|| "Failed to wait for process")?; - ctx.set_var(String::from("?"), Variable::I32(out.code().unwrap_or(-1))); - Ok(None) - } -} - -impl ExecExpression for Option { - fn exec(&mut self, ctx: &mut Context) -> Result> { - match self { - None => Ok(None), - Some(cmd) => cmd.exec(ctx) - } - } -} - impl ExecExpression for BreakExpression { - fn exec(self: &mut BreakExpression, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { ctx.break_num -= 1; return Ok(None) } + fn exec(self: &mut BreakExpression, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { ctx.break_num -= 1; return Ok(ExecResult::default()) } let val = self.num.get(ctx)?.to_string(); let num: u16 = if !val.is_empty() { val.parse()? } else { 1 }; ctx.break_num = if num == 0 { 1 } else { num }; - Ok(None) + Ok(ExecResult::default()) } } impl ExecExpression for WhileExpression { - fn exec(self: &mut WhileExpression, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { ctx.break_num -= 1; return Ok(None) } - let mut condition = match self.condition.exec(ctx)? { - None => bail!("Invalid while expression"), - Some(cmd) => cmd - }; + fn exec(self: &mut WhileExpression, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { ctx.break_num -= 1; return Ok(ExecResult::default()) } ctx.add_scope(); - let mut res; + let mut res: Option = None; loop { + let condition = self.condition.exec(ctx)?; let condition_res = condition.exec(ctx)?; - let code = ctx.get_last_exit_code().unwrap_or(1); + let code = condition_res.unwrap_or(1); if code == 0 { - res = self.contents.exec(ctx)? + if let Some(result) = res { + result.exec(ctx)?; + } + res = Some(self.contents.exec(ctx)?); } else { - res = condition_res; + res = None; break; } if ctx.break_num > 0 { @@ -155,13 +167,13 @@ impl ExecExpression for WhileExpression { } ctx.pop_scope(); - Ok(res) + Ok(res.unwrap_or(ExecResult::default())) } } impl ExecExpression for ForExpression { - fn exec<'a>(&mut self, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { ctx.break_num -= 1; return Ok(None) } + fn exec<'a>(&mut self, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { ctx.break_num -= 1; return Ok(ExecResult::default()) } let arg_value = self.arg_value.get(ctx)?; let arg_key = match &self.arg_key { None => None, @@ -171,7 +183,7 @@ impl ExecExpression for ForExpression { Some(res) } }; - let mut res: Option = None; + let mut res: Option = None; let list = self.list.get(ctx)?; fn process(i: usize, val: Variable, ctx: &mut Context, arg_key: &Option, arg_value: &Variable) -> Result<()> { @@ -190,8 +202,10 @@ impl ExecExpression for ForExpression { } else { for (i, val) in arr.iter().enumerate() { process(i, val.clone(), ctx, &arg_key, &arg_value)?; - res.exec(ctx)?; - res = self.contents.exec(ctx)?; + if let Some(res) = res { + res.exec(ctx)?; + } + res = Some(self.contents.exec(ctx)?); ctx.pop_scope(); if ctx.break_num > 0 { ctx.break_num -= 1; @@ -206,8 +220,10 @@ impl ExecExpression for ForExpression { } else { for (i, char) in str.chars().enumerate() { process(i, Variable::String(char.to_string()), ctx, &arg_key, &arg_value)?; - res.exec(ctx)?; - res = self.contents.exec(ctx)?; + if let Some(res) = res { + res.exec(ctx)?; + } + res = Some(self.contents.exec(ctx)?); ctx.pop_scope(); if ctx.break_num > 0 { ctx.break_num -= 1; @@ -219,20 +235,17 @@ impl ExecExpression for ForExpression { _ => bail!("Invalid for expression") }; - Ok(res) + Ok(res.unwrap_or(ExecResult::default())) } } impl ExecExpression for IfExpression { - fn exec(self: &mut IfExpression, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { return Ok(None) } - let mut condition = match self.condition.exec(ctx)? { - None => bail!("Invalid IF expression"), - Some(cmd) => cmd - }; + fn exec(self: &mut IfExpression, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { return Ok(ExecResult::default()) } + let condition = self.condition.exec(ctx)?; ctx.add_scope(); - condition.exec(ctx)?; - let code = ctx.get_last_exit_code().unwrap_or(1); + let condition_result = condition.exec(ctx)?; + let code = condition_result.unwrap_or(1); let res= if code == 0 { self.contents.exec(ctx)? } else { @@ -245,18 +258,18 @@ impl ExecExpression for IfExpression { } impl ExecExpression for LetExpression { - fn exec(self: &mut LetExpression, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { return Ok(None) } + fn exec(self: &mut LetExpression, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { return Ok(ExecResult::default()) } let key = self.key.get(ctx)?; let val = self.value.get(ctx)?; ctx.set_var(key.to_string(), val); - Ok(None) + Ok(ExecResult::default()) } } impl ExecExpression for Vec { - fn exec(self: &mut Vec, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { return Ok(None) } + fn exec(self: &mut Vec, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { return Ok(ExecResult::default()) } if self.is_empty() { bail!("Command with 0 length"); } let first = self.get_mut(0).unwrap(); let command_name = first.get(ctx)?.to_string(); @@ -264,96 +277,102 @@ impl ExecExpression for Vec { for value in &mut self[1..] { cmd.arg(value.get(ctx)?.to_string()); } - Ok(Some(cmd)) + let overrides = ctx.get_overrides()?; + if let Some(stdout) = overrides.stdout { cmd.stdout(stdout); } + if let Some(stderr) = overrides.stderr { cmd.stderr(stderr); } + if let Some(stdin) = overrides.stdin { cmd.stdin(stdin); } + Ok(ExecResult { + commands: vec![cmd] + }) } } impl ExecExpression for RedirectTargetExpression { - fn exec(self: &mut RedirectTargetExpression, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { return Ok(None) } + fn exec(self: &mut RedirectTargetExpression, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { return Ok(ExecResult::default()) } let (reader, writer) = os_pipe::pipe()?; - let mut src = self.source.exec(ctx)?.unwrap(); - let mut target = self.target.exec(ctx)?.unwrap(); - target.stdin(reader); - ctx.add_scope(); - ctx.scopes.last_mut().unwrap().stdout_override = Some(writer); - src.exec(ctx)?; - ctx.pop_scope(); - Ok(Some(target)) + ctx.add_scope(); + ctx.scopes.last_mut().unwrap().stdout_override = Some(WriterOverride::Pipe(writer)); + let mut src = self.source.exec(ctx)?; + ctx.pop_scope(); + ctx.add_scope(); + ctx.scopes.last_mut().unwrap().stdin_override = Some(ReaderOverride::Pipe(reader)); + let target = self.target.exec(ctx)?; + ctx.pop_scope(); + src.merge(target); + + Ok(src) } } impl ExecExpression for FileTargetExpression { - fn exec(self: &mut FileTargetExpression, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { return Ok(None) } + fn exec(self: &mut FileTargetExpression, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { return Ok(ExecResult::default()) } let src = &mut self.source; let target = self.target.get(ctx)?; + + ctx.add_scope(); + + let file = File::create(target.to_string())?; + ctx.scopes.last_mut().unwrap().stdout_override = Some(WriterOverride::File(file)); + let src = match src { Some(expr) => expr.exec(ctx)?, None => { - todo!("Redirect without target file"); + bail!("Redirect without target file"); } }; - let command = match src { - Some(mut cmd) => { - let file = File::create(target.to_string())?; - cmd.stdout(file); - cmd - }, - None => { bail!("Invalid command provided for file target"); } - }; - Ok(Some(command)) + ctx.pop_scope(); + Ok(src) } } impl ExecExpression for FileSourceExpression { - fn exec(self: &mut FileSourceExpression, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { return Ok(None) } + fn exec(self: &mut FileSourceExpression, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { return Ok(ExecResult::default()) } let source = self.source.get(ctx)?.to_string(); + let source = File::open(source).with_context(|| "Couldn't open file to read")?; let target = &mut self.target; + + ctx.add_scope(); + ctx.scopes.last_mut().unwrap().stdin_override = Some(ReaderOverride::File(source)); let target = match target { Some(expr) => expr.exec(ctx)?, None => { - Some(Command::new("less")) + vec![CommandValue::Value(Value::Literal(String::from("less")))].exec(ctx)? } }; - let mut command = match target { - None => { bail!("Invalid command") }, - Some(cmd) => cmd - }; - let source = File::open(source).with_context(|| "Couldn't open file to read")?; - command.stdin(source); + ctx.pop_scope(); - Ok(Some(command)) + Ok(target) } } impl ExecExpression for Vec { - fn exec(self: &mut Vec, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { return Ok(None) } - let mut last = None; + fn exec(self: &mut Vec, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { return Ok(ExecResult::default()) } + let mut last: Option = None; for expr in self { - last.exec(ctx)?; - last = expr.exec(ctx)?; - if ctx.break_num > 0 { return Ok(last) } + if let Some(last) = last { + last.exec(ctx)?; + } + last = Some(expr.exec(ctx)?); + if ctx.break_num > 0 { return Ok(last.unwrap()) } } - Ok(last) + Ok(last.unwrap_or(ExecResult::default())) } } impl ExecExpression for OrExpression { - fn exec(self: &mut OrExpression, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { return Ok(None) } - let mut first = match self.first.exec(ctx)? { - None => bail!("Invalid OR expression"), - Some(cmd) => cmd - }; - first.exec(ctx)?; - let code = ctx.get_last_exit_code().unwrap_or(1); + fn exec(self: &mut OrExpression, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { return Ok(ExecResult::default()) } + let first = self.first.exec(ctx)?; + let code = first.exec(ctx)?; + let code = code.unwrap_or(1); if code == 0 { - Ok(Some(first)) + Ok(ExecResult::default()) } else { self.second.exec(ctx) } @@ -361,25 +380,22 @@ impl ExecExpression for OrExpression { } impl ExecExpression for AndExpression { - fn exec(self: &mut AndExpression, ctx: &mut Context) -> Result> { - if ctx.break_num > 0 { return Ok(None) } - let mut first = match self.first.exec(ctx)? { - None => bail!("Invalid AND expression"), - Some(cmd) => cmd - }; - first.exec(ctx)?; - let code = ctx.get_last_exit_code().unwrap_or(1); + fn exec(self: &mut AndExpression, ctx: &mut Context) -> Result { + if ctx.break_num > 0 { return Ok(ExecResult::default()) } + let first = self.first.exec(ctx)?; + let code = first.exec(ctx)?; + let code = code.unwrap_or(1); if code == 0 { self.second.exec(ctx) } else { - Ok(Some(first)) + Ok(ExecResult::default()) } } } pub fn exec_tree(tree: Vec, ctx: &mut Context) -> Result<()> { for mut expression in tree { - let mut cmd = expression.exec(ctx)?; + let cmd = expression.exec(ctx)?; cmd.exec(ctx)?; if ctx.break_num > 0 { bail!("Too many break statements") } } diff --git a/src/parser/vars.rs b/src/parser/vars.rs index 0305fb4..1f96ea9 100644 --- a/src/parser/vars.rs +++ b/src/parser/vars.rs @@ -1,5 +1,9 @@ use std::collections::HashMap; use std::fmt::{Debug, Display, Formatter}; +use std::fs::File; +use std::io::{Read, Write}; +use std::process::Stdio; +use std::sync::Arc; use anyhow::{bail, Result}; use os_pipe::{PipeReader, PipeWriter}; use crate::parser::ast::FunctionDefinitionExpression; @@ -172,10 +176,59 @@ pub enum AnyFunction<'a> { UserDefined(&'a mut FunctionDefinitionExpression) } + +trait TryClone { + fn try_clone(&self) -> Result; +} + +#[derive(Debug)] +pub enum WriterOverride { + Pipe(PipeWriter), + File(File) +} +#[derive(Debug)] +pub enum ReaderOverride { + Pipe(PipeReader), + File(File) +} + +impl TryClone for WriterOverride { + fn try_clone(&self) -> Result { + Ok(match self { + WriterOverride::Pipe(pipe) => WriterOverride::Pipe(pipe.try_clone()?), + WriterOverride::File(file) => WriterOverride::File(file.try_clone()?) + }) + } +} +impl TryClone for ReaderOverride { + fn try_clone(&self) -> Result { + Ok(match self { + ReaderOverride::Pipe(pipe) => ReaderOverride::Pipe(pipe.try_clone()?), + ReaderOverride::File(file) => ReaderOverride::File(file.try_clone()?) + }) + } +} +impl From for Stdio { + fn from(value: WriterOverride) -> Self { + match value { + WriterOverride::Pipe(pipe) => pipe.into(), + WriterOverride::File(file) => file.into() + } + } +} +impl From for Stdio { + fn from(value: ReaderOverride) -> Self { + match value { + ReaderOverride::Pipe(pipe) => pipe.into(), + ReaderOverride::File(file) => file.into() + } + } +} + pub struct Overrides { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option + pub stdin: Option, + pub stdout: Option, + pub stderr: Option } #[derive(Debug)] @@ -186,9 +239,9 @@ pub struct Scope { pub func: HashMap, /// list of file descriptors, to be closed when the scope is left pub fd: Vec, - pub stdin_override: Option, - pub stdout_override: Option, - pub stderr_override: Option + pub stdin_override: Option, + pub stdout_override: Option, + pub stderr_override: Option } #[derive(Debug)]