Skip to content

Commit

Permalink
Binary search and Result overriding -> RResult (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
zakstucke authored Jun 13, 2024
1 parent 5c5ff70 commit 8b79da8
Show file tree
Hide file tree
Showing 28 changed files with 180 additions and 99 deletions.
3 changes: 2 additions & 1 deletion .zetch.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/bitbazaar/cli/bash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl Bash {
}

/// Execute the current contents of the bash script.
pub fn run(self) -> Result<BashOut, BashErr> {
pub fn run(self) -> RResult<BashOut, BashErr> {
if self.cmds.is_empty() {
return Ok(BashOut::empty());
}
Expand Down
2 changes: 1 addition & 1 deletion rust/bitbazaar/cli/bash_out.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ impl BashOut {
}

/// Throw an error if the last command run was not successful.
pub fn throw_on_bad_code<T: error_stack::Context>(&self, err_variant: T) -> Result<(), T> {
pub fn throw_on_bad_code<T: error_stack::Context>(&self, err_variant: T) -> RResult<(), T> {
if self.success() {
Ok(())
} else {
Expand Down
2 changes: 1 addition & 1 deletion rust/bitbazaar/cli/builtins/cd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
};

/// https://www.gnu.org/software/bash/manual/bash.html#index-cd
pub fn cd(shell: &mut Shell, args: &[String]) -> Result<BashOut, BuiltinErr> {
pub fn cd(shell: &mut Shell, args: &[String]) -> RResult<BashOut, BuiltinErr> {
macro_rules! hd {
() => {
if let Ok(hd) = shell.home_dir() {
Expand Down
2 changes: 1 addition & 1 deletion rust/bitbazaar/cli/builtins/echo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
};

/// https://www.gnu.org/software/bash/manual/bash.html#index-echo
pub fn echo(_shell: &mut Shell, args: &[String]) -> Result<BashOut, BuiltinErr> {
pub fn echo(_shell: &mut Shell, args: &[String]) -> RResult<BashOut, BuiltinErr> {
let mut newline = true;

let mut stdout = String::new();
Expand Down
2 changes: 1 addition & 1 deletion rust/bitbazaar/cli/builtins/exit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
/// Exit the shell, returning a status of n to the shell's parent.
/// If n is omitted, the exit status is that of the last command executed.
/// Any trap on EXIT is executed before the shell terminates.
pub fn exit(shell: &mut Shell, args: &[String]) -> Result<BashOut, BuiltinErr> {
pub fn exit(shell: &mut Shell, args: &[String]) -> RResult<BashOut, BuiltinErr> {
let exit_code = if args.is_empty() {
// Last code
shell.code()
Expand Down
4 changes: 2 additions & 2 deletions rust/bitbazaar/cli/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::prelude::*;
/// - Performance
/// - Needs to implement the pseudo rust shell
/// - Windows compatibility - all implement builtins conform to linux/mac/bash expected usage.
pub type Builtin = fn(&mut Shell, &[String]) -> Result<BashOut, BuiltinErr>;
pub type Builtin = fn(&mut Shell, &[String]) -> RResult<BashOut, BuiltinErr>;

/// Helper for creating BashOut with an error code and writing to stderr.
macro_rules! bad_call {
Expand All @@ -41,7 +41,7 @@ pub static BUILTINS: Lazy<HashMap<&'static str, Builtin>> = Lazy::new(|| {
});

#[cfg(test)]
fn std_err_echo(_shell: &mut Shell, args: &[String]) -> Result<BashOut, BuiltinErr> {
fn std_err_echo(_shell: &mut Shell, args: &[String]) -> RResult<BashOut, BuiltinErr> {
use super::CmdResult;

Ok(CmdResult::new("", 0, "", args.join(" ")).into())
Expand Down
2 changes: 1 addition & 1 deletion rust/bitbazaar/cli/builtins/pwd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
};

/// https://www.gnu.org/software/bash/manual/bash.html#index-pwd
pub fn pwd(shell: &mut Shell, args: &[String]) -> Result<BashOut, BuiltinErr> {
pub fn pwd(shell: &mut Shell, args: &[String]) -> RResult<BashOut, BuiltinErr> {
if !args.is_empty() {
return Err(
err!(BuiltinErr::Unsupported).attach_printable("pwd: options are not supported")
Expand Down
2 changes: 1 addition & 1 deletion rust/bitbazaar/cli/builtins/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
};

/// https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
pub fn set(shell: &mut Shell, args: &[String]) -> Result<BashOut, BuiltinErr> {
pub fn set(shell: &mut Shell, args: &[String]) -> RResult<BashOut, BuiltinErr> {
if let Some(arg) = args.first() {
match arg.as_str() {
"+e" => {
Expand Down
10 changes: 5 additions & 5 deletions rust/bitbazaar/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ mod tests {
#[case] exp_sterr: Option<&str>, // Only check if Some()
#[case] test_on_windows: bool, // Only check if Some()
#[allow(unused_variables)] logging: (),
) -> Result<(), AnyErr> {
) -> RResult<(), AnyErr> {
if cfg!(windows) && !test_on_windows {
return Ok(());
}
Expand Down Expand Up @@ -232,7 +232,7 @@ mod tests {
#[case] exp_std_all: S,
#[case] code: i32,
#[allow(unused_variables)] logging: (),
) -> Result<(), AnyErr> {
) -> RResult<(), AnyErr> {
let mut bash = Bash::new();
for cmd in cmds.into() {
bash = bash.cmd(cmd);
Expand All @@ -246,7 +246,7 @@ mod tests {

/// Confirm setting a custom working dir on the builder works plus when changing with cd in bash.
#[rstest]
fn test_run_dir(#[allow(unused_variables)] logging: ()) -> Result<(), AnyErr> {
fn test_run_dir(#[allow(unused_variables)] logging: ()) -> RResult<(), AnyErr> {
let temp_dir = tempfile::tempdir().change_context(AnyErr)?;
// normalise to make sure absolute (as pwd should always be absolute)
let temp_dir_pb = temp_dir
Expand Down Expand Up @@ -287,7 +287,7 @@ mod tests {

/// Confirm setting env vars on the builder work.
#[rstest]
fn test_builder_env(#[allow(unused_variables)] logging: ()) -> Result<(), AnyErr> {
fn test_builder_env(#[allow(unused_variables)] logging: ()) -> RResult<(), AnyErr> {
let res = Bash::new()
.env("FOO", "bar")
.env("BAZ", "qux")
Expand All @@ -301,7 +301,7 @@ mod tests {

// Confirm when both when doesn't error but not all commands run AND when Bash errors the final command that was attempted is accessible and printable.
#[rstest]
fn test_error_source_attached(#[allow(unused_variables)] logging: ()) -> Result<(), AnyErr> {
fn test_error_source_attached(#[allow(unused_variables)] logging: ()) -> RResult<(), AnyErr> {
let err_cmd = "ab||][/?cd";

// Confirm that when bash itself fails (i.e. invalid syntax), the source is attached to the error:
Expand Down
10 changes: 5 additions & 5 deletions rust/bitbazaar/cli/redirect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub fn handle_redirect(
shell: &mut Shell,
last_out: Option<&mut RunnerBashOut>,
redirect: ast::DefaultRedirect,
) -> Result<RunnerBashOut, ShellErr> {
) -> RResult<RunnerBashOut, ShellErr> {
Ok(match redirect {
ast::Redirect::Write(fd, name) => {
let dest = Target::new(shell, name)?.set_write();
Expand Down Expand Up @@ -75,7 +75,7 @@ enum TargetVariant {
}

impl Target {
fn new(shell: &mut Shell, name: TopLevelWord<String>) -> Result<Self, ShellErr> {
fn new(shell: &mut Shell, name: TopLevelWord<String>) -> RResult<Self, ShellErr> {
let name = shell.process_complex_word(&name.0)?;

if name == "/dev/stdin" || name == "0" {
Expand Down Expand Up @@ -153,7 +153,7 @@ enum Data {
}

impl Data {
fn new(last: Option<&mut RunnerBashOut>, fd: Option<u16>) -> Result<Self, ShellErr> {
fn new(last: Option<&mut RunnerBashOut>, fd: Option<u16>) -> RResult<Self, ShellErr> {
let fd = fd.unwrap_or(1);

Ok(match fd {
Expand Down Expand Up @@ -204,7 +204,7 @@ impl Data {
})
}

fn submit(self, shell: &Shell, dest: Target) -> Result<RunnerBashOut, ShellErr> {
fn submit(self, shell: &Shell, dest: Target) -> RResult<RunnerBashOut, ShellErr> {
let mut conc = ConcreteOutput::default();

match dest.variant {
Expand Down Expand Up @@ -272,7 +272,7 @@ impl Data {
Ok(RunnerBashOut::Concrete(conc))
}

fn write(self, mut writer: impl Write) -> Result<(), ShellErr> {
fn write(self, mut writer: impl Write) -> RResult<(), ShellErr> {
match self {
Data::StdoutHandle(mut h) => {
std::io::copy(&mut h, &mut writer).change_context(ShellErr::InternalError)?;
Expand Down
8 changes: 4 additions & 4 deletions rust/bitbazaar/cli/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub struct ConcreteOutput {
}

impl RunnerBashOut {
fn into_shell(self, shell: &mut Shell) -> Result<(), ShellErr> {
fn into_shell(self, shell: &mut Shell) -> RResult<(), ShellErr> {
match self {
RunnerBashOut::Concrete(conc) => {
if let Some(stdout) = conc.stdout {
Expand Down Expand Up @@ -99,7 +99,7 @@ impl From<BashOut> for RunnerBashOut {

impl PipeRunner {
/// Add a new command to the runner.
pub fn add(&mut self, args: Vec<String>) -> Result<(), ShellErr> {
pub fn add(&mut self, args: Vec<String>) -> RResult<(), ShellErr> {
let first_arg = args
.first()
.ok_or_else(|| err!(ShellErr::InternalError, "No command provided"))?
Expand All @@ -125,7 +125,7 @@ impl PipeRunner {
Ok(())
}

pub fn add_redirect(&mut self, redirect: &ast::DefaultRedirect) -> Result<(), ShellErr> {
pub fn add_redirect(&mut self, redirect: &ast::DefaultRedirect) -> RResult<(), ShellErr> {
self.commands.push(VariCommand::Redirect(redirect.clone()));
Ok(())
}
Expand All @@ -134,7 +134,7 @@ impl PipeRunner {
self.commands.push(VariCommand::PipedStdout(stdout));
}

pub fn run(mut self, shell: &mut Shell) -> Result<(), ShellErr> {
pub fn run(mut self, shell: &mut Shell) -> RResult<(), ShellErr> {
for command in self.commands.into_iter() {
let last_out = self.outputs.last_mut();
let next_out: RunnerBashOut = match command {
Expand Down
38 changes: 19 additions & 19 deletions rust/bitbazaar/cli/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl From<Shell> for BashOut {
}

impl Shell {
pub fn new(env: HashMap<String, String>, root_dir: Option<PathBuf>) -> Result<Self, ShellErr> {
pub fn new(env: HashMap<String, String>, root_dir: Option<PathBuf>) -> RResult<Self, ShellErr> {
let mut shell = Self {
cmd_results: Vec::new(),
root_dir: None,
Expand All @@ -66,7 +66,7 @@ impl Shell {
Ok(shell)
}

pub fn execute_command_strings(&mut self, commands: Vec<String>) -> Result<(), ShellErr> {
pub fn execute_command_strings(&mut self, commands: Vec<String>) -> RResult<(), ShellErr> {
// Whilst all commands could be given to the parser together (newline separated),
// and run internally by the shell in a single function call,
// that mean's the source command string that causes an issues would be lost
Expand All @@ -88,7 +88,7 @@ impl Shell {

let parsed_top_cmds = parser
.into_iter()
.collect::<core::result::Result<Vec<_>, _>>()
.collect::<Result<Vec<_>, _>>()
.change_context(ShellErr::BashSyntaxError)?;

// Run the command:
Expand Down Expand Up @@ -145,7 +145,7 @@ impl Shell {
self.code
}

pub fn active_dir(&self) -> Result<PathBuf, ShellErr> {
pub fn active_dir(&self) -> RResult<PathBuf, ShellErr> {
if let Some(root_dir) = &self.root_dir {
Ok(root_dir.clone())
} else {
Expand All @@ -154,7 +154,7 @@ impl Shell {
}
}

pub fn chdir(&mut self, new_root_dir: PathBuf) -> Result<(), ShellErr> {
pub fn chdir(&mut self, new_root_dir: PathBuf) -> RResult<(), ShellErr> {
// normalise to ensure its absolute (to not break e.g. pwd)
self.root_dir = Some(
new_root_dir
Expand All @@ -176,7 +176,7 @@ impl Shell {
}
}

fn run_top_cmds(&mut self, cmds: Vec<ast::TopLevelCommand<String>>) -> Result<(), ShellErr> {
fn run_top_cmds(&mut self, cmds: Vec<ast::TopLevelCommand<String>>) -> RResult<(), ShellErr> {
// Each res equates to a line in a multi line bash script. E.g. a single line command will only have one res.
for cmd in cmds {
match cmd.0 {
Expand Down Expand Up @@ -219,7 +219,7 @@ impl Shell {
Ok(())
}

fn run_listable_command(&mut self, cmd: ast::DefaultListableCommand) -> Result<(), ShellErr> {
fn run_listable_command(&mut self, cmd: ast::DefaultListableCommand) -> RResult<(), ShellErr> {
let mut pipe_runner = PipeRunner::default();

match cmd {
Expand All @@ -246,7 +246,7 @@ impl Shell {
&mut self,
pipe_runner: &mut PipeRunner,
cmd: &ast::DefaultPipeableCommand,
) -> Result<(), ShellErr> {
) -> RResult<(), ShellErr> {
match cmd {
ast::PipeableCommand::Simple(cmd) => self.add_simple_command(pipe_runner, cmd)?,
ast::PipeableCommand::Compound(compound) => {
Expand Down Expand Up @@ -309,7 +309,7 @@ impl Shell {
&mut self,
pipe_runner: &mut PipeRunner,
cmd: &ast::DefaultSimpleCommand,
) -> Result<(), ShellErr> {
) -> RResult<(), ShellErr> {
let mut env = Vec::<(String, String)>::new();

for item in cmd.redirects_or_env_vars.iter() {
Expand Down Expand Up @@ -358,7 +358,7 @@ impl Shell {
pub fn process_complex_word(
&mut self,
word: &ast::DefaultComplexWord,
) -> Result<String, ShellErr> {
) -> RResult<String, ShellErr> {
match word {
ast::ComplexWord::Single(word) => self.process_word(word, None, false),
ast::ComplexWord::Concat(words) => {
Expand All @@ -371,7 +371,7 @@ impl Shell {
concat_state.active = index;
self.process_word(word, Some(&concat_state), false)
})
.collect::<Result<Vec<_>, _>>()?
.collect::<RResult<Vec<_>, _>>()?
.join("");
Ok(result)
}
Expand All @@ -383,7 +383,7 @@ impl Shell {
word: &ast::DefaultWord,
concat_state: Option<&'_ WordConcatState<'_>>,
is_lookaround: bool,
) -> Result<String, ShellErr> {
) -> RResult<String, ShellErr> {
Ok(match word {
// Single quoted means no processing inside needed:
ast::Word::SingleQuoted(word) => word.to_string(),
Expand All @@ -393,14 +393,14 @@ impl Shell {
ast::Word::DoubleQuoted(words) => words
.iter()
.map(|word| self.process_simple_word(word, concat_state, is_lookaround))
.collect::<Result<Vec<_>, _>>()?
.collect::<RResult<Vec<_>, _>>()?
.into_iter()
.collect::<Vec<_>>()
.join(""),
})
}

pub fn home_dir(&self) -> Result<PathBuf, ShellErr> {
pub fn home_dir(&self) -> RResult<PathBuf, ShellErr> {
homedir::get_my_home()
.change_context(ShellErr::InternalError)?
.ok_or_else(|| err!(ShellErr::InternalError))
Expand All @@ -411,7 +411,7 @@ impl Shell {
word: &ast::DefaultSimpleWord,
concat_state: Option<&'_ WordConcatState<'_>>,
is_lookaround: bool,
) -> Result<String, ShellErr> {
) -> RResult<String, ShellErr> {
Ok(match word {
ast::SimpleWord::Literal(lit) => lit.to_string(),
ast::SimpleWord::Escaped(a) => a.to_string(),
Expand Down Expand Up @@ -442,7 +442,7 @@ impl Shell {
})
}

fn process_param(&mut self, param: &ast::DefaultParameter) -> Result<String, ShellErr> {
fn process_param(&mut self, param: &ast::DefaultParameter) -> RResult<String, ShellErr> {
Ok(match param {
ast::Parameter::Var(var) => {
// First try variables in current shell, otherwise try env:
Expand Down Expand Up @@ -485,7 +485,7 @@ impl Shell {
fn process_substitution(
&mut self,
sub: &ast::DefaultParameterSubstitution,
) -> Result<String, ShellErr> {
) -> RResult<String, ShellErr> {
match sub {
ast::ParameterSubstitution::Command(cmds) => {
// Run the nested command, from my tests with terminal:
Expand Down Expand Up @@ -563,7 +563,7 @@ impl Shell {
&mut self,
concat_state: Option<&'_ WordConcatState<'_>>,
is_lookaround: bool,
) -> Result<bool, ShellErr> {
) -> RResult<bool, ShellErr> {
// Handle infinite loop:
if is_lookaround {
return Ok(false);
Expand All @@ -589,7 +589,7 @@ impl Shell {
}

/// Helper to create unsupported error message.
fn unsup(desc: &'static str) -> error_stack::Report<ShellErr> {
fn unsup(desc: &'static str) -> Report<ShellErr> {
err!(
ShellErr::BashFeatureUnsupported,
"Used valid bash syntax not implemented: {}",
Expand Down
Loading

0 comments on commit 8b79da8

Please sign in to comment.