From 9ef73af8307bf3e2985e9436e0b0fcd91cb48b65 Mon Sep 17 00:00:00 2001 From: Alpha Chen Date: Fri, 24 Apr 2026 06:27:33 -0700 Subject: [PATCH] Switch from color-eyre to miette for error reporting Miette provides better diagnostic output and integrates with thiserror via the Diagnostic derive. Library errors now derive both Error and Diagnostic. Binary uses miette::Result with into_diagnostic() for third-party errors. Assisted-by: GLM-5.1 via pi --- Cargo.lock | 159 +++++++++++++++++++++----------- Cargo.toml | 2 +- src/bin/quire/commands/exec.rs | 28 +++--- src/bin/quire/commands/serve.rs | 4 +- src/bin/quire/main.rs | 7 +- src/error.rs | 2 +- 6 files changed, 130 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36e0fda..1dbce2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -118,6 +118,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] + [[package]] name = "bitflags" version = "2.11.1" @@ -196,33 +205,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" -[[package]] -name = "color-eyre" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - [[package]] name = "colorchoice" version = "1.0.5" @@ -251,16 +233,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - [[package]] name = "fastrand" version = "2.4.1" @@ -337,12 +309,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" -[[package]] -name = "indenter" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" - [[package]] name = "indexmap" version = "2.14.0" @@ -355,6 +321,12 @@ dependencies = [ "serde_core", ] +[[package]] +name = "is_ci" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -421,6 +393,36 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "backtrace", + "backtrace-ext", + "cfg-if", + "miette-derive", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "unicode-width 0.1.14", +] + +[[package]] +name = "miette-derive" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -577,8 +579,8 @@ dependencies = [ "assert_cmd", "clap", "clap_complete", - "color-eyre", "fs-err", + "miette", "predicates", "shell-words", "tempfile", @@ -761,6 +763,27 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "supports-color" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" +dependencies = [ + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" + +[[package]] +name = "supports-unicode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" + [[package]] name = "syn" version = "2.0.117" @@ -785,12 +808,32 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "terminal_size" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" +dependencies = [ + "rustix", + "windows-sys", +] + [[package]] name = "termtree" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "unicode-linebreak", + "unicode-width 0.2.2", +] + [[package]] name = "thiserror" version = "2.0.18" @@ -880,16 +923,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-error" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" -dependencies = [ - "tracing", - "tracing-subscriber", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -925,6 +958,24 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "unicode-xid" version = "0.2.6" diff --git a/Cargo.toml b/Cargo.toml index f8da1e0..92fa747 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ path = "src/bin/quire/main.rs" [dependencies] clap = { version = "*", features = ["derive", "env"] } clap_complete = "*" -color-eyre = "*" +miette = { version = "*", features = ["fancy"] } fs-err = "*" shell-words = "*" thiserror = "*" diff --git a/src/bin/quire/commands/exec.rs b/src/bin/quire/commands/exec.rs index 8aaacee..0b2ad73 100644 --- a/src/bin/quire/commands/exec.rs +++ b/src/bin/quire/commands/exec.rs @@ -2,8 +2,7 @@ use std::os::unix::process::CommandExt; use std::path::Path; use std::process::Command; -use color_eyre::eyre::{self, Context}; -use color_eyre::Result; +use miette::{miette, Context, IntoDiagnostic, Result}; const GIT_COMMANDS: &[&str] = &["git-receive-pack", "git-upload-pack", "git-upload-archive"]; @@ -19,27 +18,32 @@ pub async fn run(command: Vec) -> Result<()> { command.join(" ") }; - let words = shell_words::split(&input).context("failed to parse command")?; + let words = shell_words::split(&input) + .into_diagnostic() + .context("failed to parse command")?; if words.is_empty() { - eyre::bail!("no command provided"); + return Err(miette!("no command provided")); } let git_cmd = &words[0]; if !GIT_COMMANDS.contains(&git_cmd.as_str()) { - eyre::bail!("unsupported command: {git_cmd}"); + return Err(miette!("unsupported command: {git_cmd}")); } if words.len() != 2 { - eyre::bail!("expected usage: {git_cmd} '', got {} arguments", words.len() - 1); + return Err(miette!( + "expected usage: {git_cmd} '', got {} arguments", + words.len() - 1 + )); } let repo = validate_repo_path(&words[1])?; let repo_dir = Path::new(REPOS_DIR).join(&repo); if !repo_dir.is_dir() { - eyre::bail!("repository not found: {repo}"); + return Err(miette!("repository not found: {repo}")); } tracing::info!(%git_cmd, %repo, "dispatching git command"); @@ -47,7 +51,7 @@ pub async fn run(command: Vec) -> Result<()> { let repo_dir = Path::new(REPOS_DIR).join(&repo); let err = Command::new(git_cmd).arg(".").current_dir(&repo_dir).exec(); - Err(eyre::eyre!("exec failed: {err}")) + Err(miette!("exec failed: {err}")) } /// Validate a repo path argument from the SSH protocol. @@ -59,19 +63,19 @@ fn validate_repo_path(raw: &str) -> Result { let path = raw.trim_start_matches('/'); if path.is_empty() { - eyre::bail!("empty repository path"); + return Err(miette!("empty repository path")); } if path.contains("..") { - eyre::bail!("invalid repository path: {raw}"); + return Err(miette!("invalid repository path: {raw}")); } if !path.ends_with(".git") { - eyre::bail!("invalid repository path (must end in .git): {raw}"); + return Err(miette!("invalid repository path (must end in .git): {raw}")); } if path.contains("//") { - eyre::bail!("invalid repository path: {raw}"); + return Err(miette!("invalid repository path: {raw}")); } Ok(path.to_string()) diff --git a/src/bin/quire/commands/serve.rs b/src/bin/quire/commands/serve.rs index 1d09b84..114afed 100644 --- a/src/bin/quire/commands/serve.rs +++ b/src/bin/quire/commands/serve.rs @@ -1,4 +1,6 @@ -pub async fn run() -> color_eyre::Result<()> { +use miette::Result; + +pub async fn run() -> Result<()> { tracing::info!("quire serve starting"); // TODO: bind HTTP server Ok(()) diff --git a/src/bin/quire/main.rs b/src/bin/quire/main.rs index 0c96e5e..f9d56fc 100644 --- a/src/bin/quire/main.rs +++ b/src/bin/quire/main.rs @@ -2,6 +2,8 @@ mod commands; use clap::{CommandFactory, Parser, Subcommand}; use clap_complete::Shell; +use miette::IntoDiagnostic; +use miette::Result; use tracing_subscriber::EnvFilter; use tracing_subscriber::fmt; use tracing_subscriber::prelude::*; @@ -37,8 +39,7 @@ enum Commands { } #[tokio::main] -async fn main() -> color_eyre::Result<()> { - color_eyre::install()?; +async fn main() -> Result<()> { tracing_subscriber::registry() .with(fmt::layer()) .with(EnvFilter::from_default_env()) @@ -52,7 +53,7 @@ async fn main() -> color_eyre::Result<()> { } let Some(command) = cli.command else { - Cli::command().print_help()?; + Cli::command().print_help().into_diagnostic()?; return Ok(()); }; diff --git a/src/error.rs b/src/error.rs index 577c693..de0493d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, miette::Diagnostic)] pub enum Error { #[error("not found: {0}")] NotFound(String), -- 2.54.0