diff --git a/Cargo.lock b/Cargo.lock index d2df98b..5b316a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,12 +99,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "anyhow" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" - [[package]] name = "arrayvec" version = "0.7.6" @@ -310,7 +304,6 @@ dependencies = [ name = "deno_task_shell" version = "0.17.0" dependencies = [ - "anyhow", "dirs", "futures", "glob", @@ -1236,7 +1229,6 @@ dependencies = [ name = "shell" version = "0.1.0" dependencies = [ - "anyhow", "chrono", "clap", "ctrlc", @@ -1247,6 +1239,7 @@ dependencies = [ "futures", "miette", "parse_datetime", + "miette", "rustyline", "tokio", "uu_date", @@ -1368,10 +1361,10 @@ dependencies = [ name = "tests" version = "0.1.0" dependencies = [ - "anyhow", "deno_task_shell", "dirs", "futures", + "miette", "pretty_assertions", "shell", "tempfile", diff --git a/crates/deno_task_shell/Cargo.toml b/crates/deno_task_shell/Cargo.toml index 655825e..778b834 100644 --- a/crates/deno_task_shell/Cargo.toml +++ b/crates/deno_task_shell/Cargo.toml @@ -15,7 +15,6 @@ shell = ["futures", "glob", "os_pipe", "path-dedot", "tokio", "tokio-util"] serialization = ["serde"] [dependencies] -anyhow = "1.0.87" futures = { version = "0.3.30", optional = true } glob = { version = "0.3.1", optional = true } path-dedot = { version = "3.1.1", optional = true } diff --git a/crates/deno_task_shell/src/shell/commands/args.rs b/crates/deno_task_shell/src/shell/commands/args.rs index d308500..fff34c5 100644 --- a/crates/deno_task_shell/src/shell/commands/args.rs +++ b/crates/deno_task_shell/src/shell/commands/args.rs @@ -1,7 +1,7 @@ // Copyright 2018-2024 the Deno authors. MIT license. -use anyhow::bail; -use anyhow::Result; +use miette::bail; +use miette::Result; #[derive(Debug, PartialEq, Eq)] pub enum ArgKind<'a> { diff --git a/crates/deno_task_shell/src/shell/commands/cat.rs b/crates/deno_task_shell/src/shell/commands/cat.rs index a82e6a5..d66d344 100644 --- a/crates/deno_task_shell/src/shell/commands/cat.rs +++ b/crates/deno_task_shell/src/shell/commands/cat.rs @@ -1,7 +1,8 @@ // Copyright 2018-2024 the Deno authors. MIT license. -use anyhow::Result; use futures::future::LocalBoxFuture; +use miette::IntoDiagnostic; +use miette::Result; use std::fs::File; use std::io::IsTerminal; use std::io::Read; @@ -52,7 +53,7 @@ fn execute_cat(mut context: ShellCommandContext) -> Result { return Ok(ExecuteResult::for_cancellation()); } - let size = file.read(&mut buf)?; + let size = file.read(&mut buf).into_diagnostic()?; if size == 0 { break; } else { diff --git a/crates/deno_task_shell/src/shell/commands/cd.rs b/crates/deno_task_shell/src/shell/commands/cd.rs index b4e1c3a..c2b6595 100644 --- a/crates/deno_task_shell/src/shell/commands/cd.rs +++ b/crates/deno_task_shell/src/shell/commands/cd.rs @@ -3,9 +3,9 @@ use std::path::Path; use std::path::PathBuf; -use anyhow::bail; -use anyhow::Result; use futures::future::LocalBoxFuture; +use miette::bail; +use miette::Result; use path_dedot::ParseDot; use crate::shell::fs_util; @@ -47,7 +47,7 @@ fn execute_cd(cwd: &Path, args: Vec) -> Result { let path = parse_args(args.clone())?; let new_dir = if path == "~" { dirs::home_dir() - .ok_or_else(|| anyhow::anyhow!("Home directory not found"))? + .ok_or_else(|| miette::miette!("Home directory not found"))? } else { cwd.join(&path) }; diff --git a/crates/deno_task_shell/src/shell/commands/cp_mv.rs b/crates/deno_task_shell/src/shell/commands/cp_mv.rs index 5647cfb..83fff6a 100644 --- a/crates/deno_task_shell/src/shell/commands/cp_mv.rs +++ b/crates/deno_task_shell/src/shell/commands/cp_mv.rs @@ -3,12 +3,13 @@ use std::path::Path; use std::path::PathBuf; -use anyhow::bail; -use anyhow::Context; -use anyhow::Result; use futures::future::BoxFuture; use futures::future::LocalBoxFuture; use futures::FutureExt; +use miette::bail; +use miette::Context; +use miette::IntoDiagnostic; +use miette::Result; use crate::shell::types::ExecuteResult; use crate::shell::types::ShellPipeWriter; @@ -87,7 +88,9 @@ async fn do_copy_operation( bail!("source was a directory; maybe specify -r") } } else { - tokio::fs::copy(&from.path, &to.path).await?; + tokio::fs::copy(&from.path, &to.path) + .await + .into_diagnostic()?; } Ok(()) } @@ -100,13 +103,15 @@ fn copy_dir_recursively( async move { tokio::fs::create_dir_all(&to) .await - .with_context(|| format!("Creating {}", to.display()))?; + .into_diagnostic() + .context(miette::miette!("Creating {}", to.display()))?; let mut read_dir = tokio::fs::read_dir(&from) .await - .with_context(|| format!("Reading {}", from.display()))?; + .into_diagnostic() + .context(miette::miette!("Reading {}", from.display()))?; - while let Some(entry) = read_dir.next_entry().await? { - let file_type = entry.file_type().await?; + while let Some(entry) = read_dir.next_entry().await.into_diagnostic()? { + let file_type = entry.file_type().await.into_diagnostic()?; let new_from = from.join(entry.file_name()); let new_to = to.join(entry.file_name()); @@ -117,9 +122,12 @@ fn copy_dir_recursively( format!("Dir {} to {}", new_from.display(), new_to.display()) })?; } else if file_type.is_file() { - tokio::fs::copy(&new_from, &new_to).await.with_context(|| { - format!("Copying {} to {}", new_from.display(), new_to.display()) - })?; + tokio::fs::copy(&new_from, &new_to) + .await + .into_diagnostic() + .with_context(|| { + format!("Copying {} to {}", new_from.display(), new_to.display()) + })?; } } diff --git a/crates/deno_task_shell/src/shell/commands/exit.rs b/crates/deno_task_shell/src/shell/commands/exit.rs index 5222c61..44ab7fb 100644 --- a/crates/deno_task_shell/src/shell/commands/exit.rs +++ b/crates/deno_task_shell/src/shell/commands/exit.rs @@ -1,8 +1,8 @@ // Copyright 2018-2024 the Deno authors. MIT license. -use anyhow::bail; -use anyhow::Result; use futures::future::LocalBoxFuture; +use miette::bail; +use miette::Result; use crate::shell::types::ExecuteResult; diff --git a/crates/deno_task_shell/src/shell/commands/head.rs b/crates/deno_task_shell/src/shell/commands/head.rs index bef3a46..c0a9344 100644 --- a/crates/deno_task_shell/src/shell/commands/head.rs +++ b/crates/deno_task_shell/src/shell/commands/head.rs @@ -3,9 +3,10 @@ use std::fs::File; use std::io::Read; -use anyhow::bail; -use anyhow::Result; use futures::future::LocalBoxFuture; +use miette::bail; +use miette::IntoDiagnostic; +use miette::Result; use tokio_util::sync::CancellationToken; use crate::ExecuteResult; @@ -96,7 +97,7 @@ fn execute_head(mut context: ShellCommandContext) -> Result { &mut context.stdout, flags.lines, context.state.token(), - |buf| file.read(buf).map_err(Into::into), + |buf| file.read(buf).into_diagnostic(), 512, ), Err(err) => { @@ -131,7 +132,7 @@ fn parse_args(args: Vec) -> Result { } ArgKind::ShortFlag('n') => match iterator.next() { Some(ArgKind::Arg(arg)) => { - lines = Some(arg.parse::()?); + lines = Some(arg.parse::().into_diagnostic()?); } _ => bail!("expected a value following -n"), }, @@ -139,7 +140,7 @@ fn parse_args(args: Vec) -> Result { if flag == "lines" || flag == "lines=" { bail!("expected a value for --lines"); } else if let Some(arg) = flag.strip_prefix("lines=") { - lines = Some(arg.parse::()?); + lines = Some(arg.parse::().into_diagnostic()?); } else { arg.bail_unsupported()? } diff --git a/crates/deno_task_shell/src/shell/commands/mkdir.rs b/crates/deno_task_shell/src/shell/commands/mkdir.rs index 25636ca..5d8d90f 100644 --- a/crates/deno_task_shell/src/shell/commands/mkdir.rs +++ b/crates/deno_task_shell/src/shell/commands/mkdir.rs @@ -1,9 +1,9 @@ // Copyright 2018-2024 the Deno authors. MIT license. -use anyhow::bail; -use anyhow::Result; use futures::future::LocalBoxFuture; use futures::FutureExt; +use miette::bail; +use miette::Result; use std::path::Path; use crate::shell::types::ExecuteResult; diff --git a/crates/deno_task_shell/src/shell/commands/pwd.rs b/crates/deno_task_shell/src/shell/commands/pwd.rs index 9da211c..bb6e933 100644 --- a/crates/deno_task_shell/src/shell/commands/pwd.rs +++ b/crates/deno_task_shell/src/shell/commands/pwd.rs @@ -1,8 +1,8 @@ // Copyright 2018-2024 the Deno authors. MIT license. -use anyhow::Context; -use anyhow::Result; use futures::future::LocalBoxFuture; +use miette::Context; +use miette::Result; use std::path::Path; use crate::shell::fs_util; diff --git a/crates/deno_task_shell/src/shell/commands/rm.rs b/crates/deno_task_shell/src/shell/commands/rm.rs index 72c1410..77cf9c3 100644 --- a/crates/deno_task_shell/src/shell/commands/rm.rs +++ b/crates/deno_task_shell/src/shell/commands/rm.rs @@ -1,9 +1,9 @@ // Copyright 2018-2024 the Deno authors. MIT license. -use anyhow::bail; -use anyhow::Result; use futures::future::LocalBoxFuture; use futures::FutureExt; +use miette::bail; +use miette::Result; use std::io::ErrorKind; use std::path::Path; diff --git a/crates/deno_task_shell/src/shell/commands/sleep.rs b/crates/deno_task_shell/src/shell/commands/sleep.rs index f1e68e6..b86d92d 100644 --- a/crates/deno_task_shell/src/shell/commands/sleep.rs +++ b/crates/deno_task_shell/src/shell/commands/sleep.rs @@ -2,10 +2,11 @@ use std::time::Duration; -use anyhow::bail; -use anyhow::Result; use futures::future::LocalBoxFuture; use futures::FutureExt; +use miette::bail; +use miette::IntoDiagnostic; +use miette::Result; use crate::shell::types::ExecuteResult; use crate::shell::types::ShellPipeWriter; @@ -54,19 +55,19 @@ async fn execute_sleep(args: Vec) -> Result<()> { fn parse_arg(arg: &str) -> Result { if let Some(t) = arg.strip_suffix('s') { - return Ok(t.parse()?); + return t.parse().into_diagnostic(); } if let Some(t) = arg.strip_suffix('m') { - return Ok(t.parse::()? * 60.); + return Ok(t.parse::().into_diagnostic()? * 60.); } if let Some(t) = arg.strip_suffix('h') { - return Ok(t.parse::()? * 60. * 60.); + return Ok(t.parse::().into_diagnostic()? * 60. * 60.); } if let Some(t) = arg.strip_suffix('d') { - return Ok(t.parse::()? * 60. * 60. * 24.); + return Ok(t.parse::().into_diagnostic()? * 60. * 60. * 24.); } - Ok(arg.parse()?) + arg.parse().into_diagnostic() } fn parse_args(args: Vec) -> Result { diff --git a/crates/deno_task_shell/src/shell/commands/unset.rs b/crates/deno_task_shell/src/shell/commands/unset.rs index 9a60c3b..bb9ec01 100644 --- a/crates/deno_task_shell/src/shell/commands/unset.rs +++ b/crates/deno_task_shell/src/shell/commands/unset.rs @@ -1,8 +1,8 @@ // Copyright 2018-2024 the Deno authors. MIT license. -use anyhow::bail; -use anyhow::Result; use futures::future::LocalBoxFuture; +use miette::bail; +use miette::Result; use crate::shell::types::ExecuteResult; use crate::EnvChange; diff --git a/crates/deno_task_shell/src/shell/commands/xargs.rs b/crates/deno_task_shell/src/shell/commands/xargs.rs index 7ff01e1..11e3609 100644 --- a/crates/deno_task_shell/src/shell/commands/xargs.rs +++ b/crates/deno_task_shell/src/shell/commands/xargs.rs @@ -1,9 +1,10 @@ // Copyright 2018-2024 the Deno authors. MIT license. -use anyhow::bail; -use anyhow::Result; use futures::future::LocalBoxFuture; use futures::FutureExt; +use miette::bail; +use miette::IntoDiagnostic; +use miette::Result; use crate::shell::types::ExecuteResult; use crate::shell::types::ShellPipeReader; @@ -51,7 +52,7 @@ fn xargs_collect_args( let flags = parse_args(cli_args)?; let mut buf = Vec::new(); stdin.pipe_to(&mut buf)?; - let text = String::from_utf8(buf)?; + let text = String::from_utf8(buf).into_diagnostic()?; let mut args = flags.initial_args; if args.is_empty() { diff --git a/crates/deno_task_shell/src/shell/execute.rs b/crates/deno_task_shell/src/shell/execute.rs index f2accae..c17c39e 100644 --- a/crates/deno_task_shell/src/shell/execute.rs +++ b/crates/deno_task_shell/src/shell/execute.rs @@ -4,11 +4,10 @@ use std::collections::HashMap; use std::path::Path; use std::rc::Rc; -use anyhow::Context; -use anyhow::Error; use futures::future; use futures::future::LocalBoxFuture; use futures::FutureExt; +use miette::Error; use thiserror::Error; use tokio::task::JoinHandle; use tokio_util::sync::CancellationToken; @@ -580,9 +579,9 @@ async fn evaluate_arithmetic_part( _ => { let var = state .get_var(name) - .ok_or_else(|| anyhow::anyhow!("Undefined variable: {}", name))?; + .ok_or_else(|| miette::miette!("Undefined variable: {}", name))?; let parsed_var = var.parse::().map_err(|e| { - anyhow::anyhow!("Failed to parse variable '{}': {}", name, e) + miette::miette!("Failed to parse variable '{}': {}", name, e) })?; match op { AssignmentOp::MultiplyAssign => val.checked_mul(&parsed_var), @@ -651,11 +650,11 @@ async fn evaluate_arithmetic_part( .get_var(name) .and_then(|s| s.parse::().ok()) .ok_or_else(|| { - anyhow::anyhow!("Undefined or non-integer variable: {}", name) + miette::miette!("Undefined or non-integer variable: {}", name) }), ArithmeticPart::Number(num_str) => num_str .parse::() - .map_err(|e| anyhow::anyhow!(e.to_string())), + .map_err(|e| miette::miette!(e.to_string())), } } @@ -1102,7 +1101,7 @@ pub enum EvaluateWordTextError { #[error("glob: no matches found '{}'", pattern)] NoFilesMatched { pattern: String }, #[error("Failed to get home directory")] - FailedToGetHomeDirectory(anyhow::Error), + FailedToGetHomeDirectory(miette::Error), } impl EvaluateWordTextError { @@ -1112,8 +1111,8 @@ impl EvaluateWordTextError { } } -impl From for EvaluateWordTextError { - fn from(err: anyhow::Error) -> Self { +impl From for EvaluateWordTextError { + fn from(err: miette::Error) -> Self { Self::FailedToGetHomeDirectory(err) } } @@ -1284,7 +1283,7 @@ fn evaluate_word_parts( WordPart::Tilde(tilde_prefix) => { if tilde_prefix.only_tilde() { let home_str = dirs::home_dir() - .context("Failed to get home directory")? + .ok_or_else(|| miette::miette!("Failed to get home directory"))? .display() .to_string(); current_text.push(TextPart::Text(home_str)); diff --git a/crates/deno_task_shell/src/shell/fs_util.rs b/crates/deno_task_shell/src/shell/fs_util.rs index 043b81f..a13aa77 100644 --- a/crates/deno_task_shell/src/shell/fs_util.rs +++ b/crates/deno_task_shell/src/shell/fs_util.rs @@ -3,11 +3,12 @@ use std::path::Path; use std::path::PathBuf; -use anyhow::Result; +use miette::IntoDiagnostic; +use miette::Result; /// Similar to `std::fs::canonicalize()` but strips UNC prefixes on Windows. pub fn canonicalize_path(path: &Path) -> Result { - let path = path.canonicalize()?; + let path = path.canonicalize().into_diagnostic()?; #[cfg(windows)] return Ok(strip_unc_prefix(path)); #[cfg(not(windows))] diff --git a/crates/deno_task_shell/src/shell/types.rs b/crates/deno_task_shell/src/shell/types.rs index bf079d9..3c87caa 100644 --- a/crates/deno_task_shell/src/shell/types.rs +++ b/crates/deno_task_shell/src/shell/types.rs @@ -12,9 +12,10 @@ use std::path::PathBuf; use std::rc::Rc; use std::str::FromStr; -use anyhow::Error; -use anyhow::Result; use futures::future::LocalBoxFuture; +use miette::Error; +use miette::IntoDiagnostic; +use miette::Result; use tokio::task::JoinHandle; use tokio_util::sync::CancellationToken; @@ -388,15 +389,19 @@ impl ShellPipeReader { loop { let mut buffer = [0; 512]; // todo: what is an appropriate buffer size? let size = match &mut self { - ShellPipeReader::OsPipe(pipe) => pipe.read(&mut buffer)?, - ShellPipeReader::StdFile(file) => file.read(&mut buffer)?, + ShellPipeReader::OsPipe(pipe) => { + pipe.read(&mut buffer).into_diagnostic()? + } + ShellPipeReader::StdFile(file) => { + file.read(&mut buffer).into_diagnostic()? + } }; if size == 0 { break; } - writer.write_all(&buffer[0..size])?; + writer.write_all(&buffer[0..size]).into_diagnostic()?; if flush { - writer.flush()?; + writer.flush().into_diagnostic()?; } } Ok(()) @@ -433,8 +438,8 @@ impl ShellPipeReader { pub fn read(&mut self, buf: &mut [u8]) -> Result { match self { - ShellPipeReader::OsPipe(pipe) => pipe.read(buf).map_err(|e| e.into()), - ShellPipeReader::StdFile(file) => file.read(buf).map_err(|e| e.into()), + ShellPipeReader::OsPipe(pipe) => pipe.read(buf).into_diagnostic(), + ShellPipeReader::StdFile(file) => file.read(buf).into_diagnostic(), } } } @@ -498,19 +503,19 @@ impl ShellPipeWriter { pub fn write_all(&mut self, bytes: &[u8]) -> Result<()> { match self { - Self::OsPipe(pipe) => pipe.write_all(bytes)?, - Self::StdFile(file) => file.write_all(bytes)?, + Self::OsPipe(pipe) => pipe.write_all(bytes).into_diagnostic()?, + Self::StdFile(file) => file.write_all(bytes).into_diagnostic()?, // For both stdout & stderr, we want to flush after each // write in order to bypass Rust's internal buffer. Self::Stdout => { let mut stdout = std::io::stdout().lock(); - stdout.write_all(bytes)?; - stdout.flush()?; + stdout.write_all(bytes).into_diagnostic()?; + stdout.flush().into_diagnostic()?; } Self::Stderr => { let mut stderr = std::io::stderr().lock(); - stderr.write_all(bytes)?; - stderr.flush()?; + stderr.write_all(bytes).into_diagnostic()?; + stderr.flush().into_diagnostic()?; } Self::Null => {} } @@ -583,14 +588,14 @@ impl ArithmeticResult { .checked_add(*rhs) .map(ArithmeticValue::Integer) .ok_or_else(|| { - anyhow::anyhow!("Integer overflow: {} + {}", lhs, rhs) + miette::miette!("Integer overflow: {} + {}", lhs, rhs) })?, (ArithmeticValue::Float(lhs), ArithmeticValue::Float(rhs)) => { let sum = lhs + rhs; if sum.is_finite() { ArithmeticValue::Float(sum) } else { - return Err(anyhow::anyhow!("Float overflow: {} + {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} + {}", lhs, rhs)); } } (ArithmeticValue::Integer(lhs), ArithmeticValue::Float(rhs)) @@ -599,7 +604,7 @@ impl ArithmeticResult { if sum.is_finite() { ArithmeticValue::Float(sum) } else { - return Err(anyhow::anyhow!("Float overflow: {} + {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} + {}", lhs, rhs)); } } }; @@ -622,14 +627,14 @@ impl ArithmeticResult { .checked_sub(*rhs) .map(ArithmeticValue::Integer) .ok_or_else(|| { - anyhow::anyhow!("Integer overflow: {} - {}", lhs, rhs) + miette::miette!("Integer overflow: {} - {}", lhs, rhs) })?, (ArithmeticValue::Float(lhs), ArithmeticValue::Float(rhs)) => { let diff = lhs - rhs; if diff.is_finite() { ArithmeticValue::Float(diff) } else { - return Err(anyhow::anyhow!("Float overflow: {} - {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} - {}", lhs, rhs)); } } (ArithmeticValue::Integer(lhs), ArithmeticValue::Float(rhs)) => { @@ -637,7 +642,7 @@ impl ArithmeticResult { if diff.is_finite() { ArithmeticValue::Float(diff) } else { - return Err(anyhow::anyhow!("Float overflow: {} - {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} - {}", lhs, rhs)); } } (ArithmeticValue::Float(lhs), ArithmeticValue::Integer(rhs)) => { @@ -645,7 +650,7 @@ impl ArithmeticResult { if diff.is_finite() { ArithmeticValue::Float(diff) } else { - return Err(anyhow::anyhow!("Float overflow: {} - {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} - {}", lhs, rhs)); } } }; @@ -668,14 +673,14 @@ impl ArithmeticResult { .checked_mul(*rhs) .map(ArithmeticValue::Integer) .ok_or_else(|| { - anyhow::anyhow!("Integer overflow: {} * {}", lhs, rhs) + miette::miette!("Integer overflow: {} * {}", lhs, rhs) })?, (ArithmeticValue::Float(lhs), ArithmeticValue::Float(rhs)) => { let product = lhs * rhs; if product.is_finite() { ArithmeticValue::Float(product) } else { - return Err(anyhow::anyhow!("Float overflow: {} * {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} * {}", lhs, rhs)); } } (ArithmeticValue::Integer(lhs), ArithmeticValue::Float(rhs)) @@ -684,7 +689,7 @@ impl ArithmeticResult { if product.is_finite() { ArithmeticValue::Float(product) } else { - return Err(anyhow::anyhow!("Float overflow: {} * {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} * {}", lhs, rhs)); } } }; @@ -705,46 +710,46 @@ impl ArithmeticResult { let result = match (&self.value, &other.value) { (ArithmeticValue::Integer(lhs), ArithmeticValue::Integer(rhs)) => { if *rhs == 0 { - return Err(anyhow::anyhow!("Division by zero: {} / {}", lhs, rhs)); + return Err(miette::miette!("Division by zero: {} / {}", lhs, rhs)); } lhs .checked_div(*rhs) .map(ArithmeticValue::Integer) .ok_or_else(|| { - anyhow::anyhow!("Integer overflow: {} / {}", lhs, rhs) + miette::miette!("Integer overflow: {} / {}", lhs, rhs) })? } (ArithmeticValue::Float(lhs), ArithmeticValue::Float(rhs)) => { if *rhs == 0.0 { - return Err(anyhow::anyhow!("Division by zero: {} / {}", lhs, rhs)); + return Err(miette::miette!("Division by zero: {} / {}", lhs, rhs)); } let quotient = lhs / rhs; if quotient.is_finite() { ArithmeticValue::Float(quotient) } else { - return Err(anyhow::anyhow!("Float overflow: {} / {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} / {}", lhs, rhs)); } } (ArithmeticValue::Integer(lhs), ArithmeticValue::Float(rhs)) => { if *rhs == 0.0 { - return Err(anyhow::anyhow!("Division by zero: {} / {}", lhs, rhs)); + return Err(miette::miette!("Division by zero: {} / {}", lhs, rhs)); } let quotient = *lhs as f64 / rhs; if quotient.is_finite() { ArithmeticValue::Float(quotient) } else { - return Err(anyhow::anyhow!("Float overflow: {} / {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} / {}", lhs, rhs)); } } (ArithmeticValue::Float(lhs), ArithmeticValue::Integer(rhs)) => { if *rhs == 0 { - return Err(anyhow::anyhow!("Division by zero: {} / {}", lhs, rhs)); + return Err(miette::miette!("Division by zero: {} / {}", lhs, rhs)); } let quotient = lhs / *rhs as f64; if quotient.is_finite() { ArithmeticValue::Float(quotient) } else { - return Err(anyhow::anyhow!("Float overflow: {} / {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} / {}", lhs, rhs)); } } }; @@ -765,46 +770,46 @@ impl ArithmeticResult { let result = match (&self.value, &other.value) { (ArithmeticValue::Integer(lhs), ArithmeticValue::Integer(rhs)) => { if *rhs == 0 { - return Err(anyhow::anyhow!("Modulo by zero: {} % {}", lhs, rhs)); + return Err(miette::miette!("Modulo by zero: {} % {}", lhs, rhs)); } lhs .checked_rem(*rhs) .map(ArithmeticValue::Integer) .ok_or_else(|| { - anyhow::anyhow!("Integer overflow: {} % {}", lhs, rhs) + miette::miette!("Integer overflow: {} % {}", lhs, rhs) })? } (ArithmeticValue::Float(lhs), ArithmeticValue::Float(rhs)) => { if *rhs == 0.0 { - return Err(anyhow::anyhow!("Modulo by zero: {} % {}", lhs, rhs)); + return Err(miette::miette!("Modulo by zero: {} % {}", lhs, rhs)); } let remainder = lhs % rhs; if remainder.is_finite() { ArithmeticValue::Float(remainder) } else { - return Err(anyhow::anyhow!("Float overflow: {} % {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} % {}", lhs, rhs)); } } (ArithmeticValue::Integer(lhs), ArithmeticValue::Float(rhs)) => { if *rhs == 0.0 { - return Err(anyhow::anyhow!("Modulo by zero: {} % {}", lhs, rhs)); + return Err(miette::miette!("Modulo by zero: {} % {}", lhs, rhs)); } let remainder = *lhs as f64 % rhs; if remainder.is_finite() { ArithmeticValue::Float(remainder) } else { - return Err(anyhow::anyhow!("Float overflow: {} % {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} % {}", lhs, rhs)); } } (ArithmeticValue::Float(lhs), ArithmeticValue::Integer(rhs)) => { if *rhs == 0 { - return Err(anyhow::anyhow!("Modulo by zero: {} % {}", lhs, rhs)); + return Err(miette::miette!("Modulo by zero: {} % {}", lhs, rhs)); } let remainder = lhs % *rhs as f64; if remainder.is_finite() { ArithmeticValue::Float(remainder) } else { - return Err(anyhow::anyhow!("Float overflow: {} % {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} % {}", lhs, rhs)); } } }; @@ -829,14 +834,14 @@ impl ArithmeticResult { if result.is_finite() { ArithmeticValue::Float(result) } else { - return Err(anyhow::anyhow!("Float overflow: {} ** {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} ** {}", lhs, rhs)); } } else { lhs .checked_pow(*rhs as u32) .map(ArithmeticValue::Integer) .ok_or_else(|| { - anyhow::anyhow!("Integer overflow: {} ** {}", lhs, rhs) + miette::miette!("Integer overflow: {} ** {}", lhs, rhs) })? } } @@ -845,7 +850,7 @@ impl ArithmeticResult { if result.is_finite() { ArithmeticValue::Float(result) } else { - return Err(anyhow::anyhow!("Float overflow: {} ** {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} ** {}", lhs, rhs)); } } (ArithmeticValue::Integer(lhs), ArithmeticValue::Float(rhs)) => { @@ -853,7 +858,7 @@ impl ArithmeticResult { if result.is_finite() { ArithmeticValue::Float(result) } else { - return Err(anyhow::anyhow!("Float overflow: {} ** {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} ** {}", lhs, rhs)); } } (ArithmeticValue::Float(lhs), ArithmeticValue::Integer(rhs)) => { @@ -861,7 +866,7 @@ impl ArithmeticResult { if result.is_finite() { ArithmeticValue::Float(result) } else { - return Err(anyhow::anyhow!("Float overflow: {} ** {}", lhs, rhs)); + return Err(miette::miette!("Float overflow: {} ** {}", lhs, rhs)); } } }; @@ -880,13 +885,13 @@ impl ArithmeticResult { ArithmeticValue::Integer(val) => val .checked_neg() .map(ArithmeticValue::Integer) - .ok_or_else(|| anyhow::anyhow!("Integer overflow: -{}", val))?, + .ok_or_else(|| miette::miette!("Integer overflow: -{}", val))?, ArithmeticValue::Float(val) => { let result = -val; if result.is_finite() { ArithmeticValue::Float(result) } else { - return Err(anyhow::anyhow!("Float overflow: -{}", val)); + return Err(miette::miette!("Float overflow: -{}", val)); } } }; @@ -901,7 +906,7 @@ impl ArithmeticResult { let result = match &self.value { ArithmeticValue::Integer(val) => ArithmeticValue::Integer(!val), ArithmeticValue::Float(_) => { - return Err(anyhow::anyhow!( + return Err(miette::miette!( "Invalid arithmetic result type for bitwise NOT: {}", self )) @@ -921,7 +926,7 @@ impl ArithmeticResult { let result = match (&self.value, &other.value) { (ArithmeticValue::Integer(lhs), ArithmeticValue::Integer(rhs)) => { if *rhs < 0 { - return Err(anyhow::anyhow!( + return Err(miette::miette!( "Negative shift amount: {} << {}", lhs, rhs @@ -931,11 +936,11 @@ impl ArithmeticResult { .checked_shl(*rhs as u32) .map(ArithmeticValue::Integer) .ok_or_else(|| { - anyhow::anyhow!("Integer overflow: {} << {}", lhs, rhs) + miette::miette!("Integer overflow: {} << {}", lhs, rhs) })? } _ => { - return Err(anyhow::anyhow!( + return Err(miette::miette!( "Invalid arithmetic result types for left shift: {} << {}", self, other @@ -959,7 +964,7 @@ impl ArithmeticResult { let result = match (&self.value, &other.value) { (ArithmeticValue::Integer(lhs), ArithmeticValue::Integer(rhs)) => { if *rhs < 0 { - return Err(anyhow::anyhow!( + return Err(miette::miette!( "Negative shift amount: {} >> {}", lhs, rhs @@ -969,11 +974,11 @@ impl ArithmeticResult { .checked_shr(*rhs as u32) .map(ArithmeticValue::Integer) .ok_or_else(|| { - anyhow::anyhow!("Integer underflow: {} >> {}", lhs, rhs) + miette::miette!("Integer underflow: {} >> {}", lhs, rhs) })? } _ => { - return Err(anyhow::anyhow!( + return Err(miette::miette!( "Invalid arithmetic result types for right shift: {} >> {}", self, other @@ -999,7 +1004,7 @@ impl ArithmeticResult { ArithmeticValue::Integer(lhs & rhs) } _ => { - return Err(anyhow::anyhow!( + return Err(miette::miette!( "Invalid arithmetic result types for bitwise AND: {} & {}", self, other @@ -1025,7 +1030,7 @@ impl ArithmeticResult { ArithmeticValue::Integer(lhs | rhs) } _ => { - return Err(anyhow::anyhow!( + return Err(miette::miette!( "Invalid arithmetic result types for bitwise OR: {} | {}", self, other @@ -1051,7 +1056,7 @@ impl ArithmeticResult { ArithmeticValue::Integer(lhs ^ rhs) } _ => { - return Err(anyhow::anyhow!( + return Err(miette::miette!( "Invalid arithmetic result types for bitwise XOR: {} ^ {}", self, other diff --git a/crates/shell/Cargo.toml b/crates/shell/Cargo.toml index 5ad0c9d..e54cd22 100644 --- a/crates/shell/Cargo.toml +++ b/crates/shell/Cargo.toml @@ -23,7 +23,6 @@ path = "src/main.rs" [features] [dependencies] -anyhow = "1.0.87" clap = { version = "4.5.17", features = ["derive"] } deno_task_shell = { path = "../deno_task_shell", features = ["shell"] } futures = "0.3.30" @@ -42,6 +41,7 @@ parse_datetime = "0.6.0" dtparse = "2.0.1" windows-sys = "0.59.0" ctrlc = "3.4.5" +miette = { version="7.2.0", features = ["fancy"] } [package.metadata.release] # Dont publish the binary diff --git a/crates/shell/src/execute.rs b/crates/shell/src/execute.rs index 0fbd05d..f52d299 100644 --- a/crates/shell/src/execute.rs +++ b/crates/shell/src/execute.rs @@ -1,10 +1,10 @@ -use anyhow::Context; use deno_task_shell::{ execute_sequential_list, AsyncCommandBehavior, ExecuteResult, ShellPipeReader, ShellPipeWriter, ShellState, }; +use miette::{Context, IntoDiagnostic}; -pub async fn execute_inner(text: &str, state: ShellState) -> anyhow::Result { +pub async fn execute_inner(text: &str, state: ShellState) -> miette::Result { let list = deno_task_shell::parser::parse(text); let mut stderr = ShellPipeWriter::stderr(); @@ -30,14 +30,16 @@ pub async fn execute_inner(text: &str, state: ShellState) -> anyhow::Result anyhow::Result { +pub async fn execute(text: &str, state: &mut ShellState) -> miette::Result { let result = execute_inner(text, state.clone()).await?; match result { ExecuteResult::Continue(exit_code, changes, _) => { // set CWD to the last command's CWD state.apply_changes(&changes); - std::env::set_current_dir(state.cwd()).context("Failed to set CWD")?; + std::env::set_current_dir(state.cwd()) + .into_diagnostic() + .context("Failed to set CWD")?; Ok(exit_code) } ExecuteResult::Exit(_, _) => Ok(0), diff --git a/crates/shell/src/main.rs b/crates/shell/src/main.rs index 583023a..dc8b27e 100644 --- a/crates/shell/src/main.rs +++ b/crates/shell/src/main.rs @@ -1,10 +1,11 @@ use std::path::Path; use std::path::PathBuf; -use anyhow::Context; use clap::Parser; use deno_task_shell::parser::debug_parse; use deno_task_shell::ShellState; +use miette::Context; +use miette::IntoDiagnostic; use rustyline::error::ReadlineError; use rustyline::{CompletionType, Config, Editor}; @@ -29,7 +30,7 @@ fn init_state() -> ShellState { ShellState::new(env_vars, &cwd, commands::get_commands()) } -async fn interactive() -> anyhow::Result<()> { +async fn interactive() -> miette::Result<()> { let config = Config::builder() .history_ignore_space(true) .completion_type(CompletionType::List) @@ -40,19 +41,20 @@ async fn interactive() -> anyhow::Result<()> { }) .expect("Error setting Ctrl-C handler"); - let mut rl = Editor::with_config(config)?; + let mut rl = Editor::with_config(config).into_diagnostic()?; let helper = helper::ShellPromptHelper::default(); rl.set_helper(Some(helper)); let mut state = init_state(); - let home = dirs::home_dir().context("Couldn't get home directory")?; + let home = dirs::home_dir().ok_or(miette::miette!("Couldn't get home directory"))?; let history_file: PathBuf = [home.as_path(), Path::new(".shell_history")] .iter() .collect(); if Path::new(history_file.as_path()).exists() { rl.load_history(history_file.as_path()) + .into_diagnostic() .context("Failed to read the command history")?; } @@ -64,9 +66,9 @@ async fn interactive() -> anyhow::Result<()> { // Display the prompt and read a line let readline = { let cwd = state.cwd().to_string_lossy().to_string(); - let home_str = home - .to_str() - .context("Couldn't convert home directory path to UTF-8 string")?; + let home_str = home.to_str().ok_or(miette::miette!( + "Couldn't convert home directory path to UTF-8 string" + ))?; if !state.last_command_cd() { state.update_git_branch(); } @@ -101,7 +103,7 @@ async fn interactive() -> anyhow::Result<()> { match readline { Ok(line) => { // Add the line to history - rl.add_history_entry(line.as_str())?; + rl.add_history_entry(line.as_str()).into_diagnostic()?; // Process the input (here we just echo it back) let prev_exit_code = execute(&line, &mut state) @@ -131,13 +133,14 @@ async fn interactive() -> anyhow::Result<()> { } } rl.save_history(history_file.as_path()) + .into_diagnostic() .context("Failed to write the command history")?; Ok(()) } #[tokio::main] -async fn main() -> anyhow::Result<()> { +async fn main() -> miette::Result<()> { let options = Options::parse(); if let Some(file) = options.file { diff --git a/crates/tests/Cargo.toml b/crates/tests/Cargo.toml index b0215d1..3e67bae 100644 --- a/crates/tests/Cargo.toml +++ b/crates/tests/Cargo.toml @@ -6,10 +6,10 @@ edition = "2021" [dependencies] deno_task_shell = { path = "../deno_task_shell", features = ["shell"] } shell = { path = "../shell" } -anyhow = "1.0.87" futures = "0.3.30" tokio = { version = "1.40.0", features = ["full"] } dirs = "5.0.1" +miette = "7.2.0" [dev-dependencies] pretty_assertions = "1.0.0" diff --git a/crates/tests/src/test_builder.rs b/crates/tests/src/test_builder.rs index 985aa0a..e45720f 100644 --- a/crates/tests/src/test_builder.rs +++ b/crates/tests/src/test_builder.rs @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. MIT license. -use anyhow::Context; use futures::future::LocalBoxFuture; +use miette::IntoDiagnostic; use pretty_assertions::assert_eq; use std::collections::HashMap; use std::fs; @@ -307,7 +307,7 @@ impl TestBuilder { } TestAssertion::FileTextEquals(path, text) => { let actual_text = std::fs::read_to_string(cwd.join(path)) - .with_context(|| format!("Error reading {path}")) + .into_diagnostic() .unwrap(); assert_eq!( &actual_text, text,