Skip to content

Commit

Permalink
Add some color to error messages (#1028)
Browse files Browse the repository at this point in the history
* Add some color to error messages

This commit updates the errors printed by the CLI to have `error` in
red, the main error message in bold, and the rest of it is unchanged.

* Fix tests

* Fix no-default-features build
  • Loading branch information
alexcrichton authored May 15, 2023
1 parent 837a14a commit fa52023
Show file tree
Hide file tree
Showing 21 changed files with 160 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
failed to parse component `tests/compositions/component-missing/a.wat`

Caused by:
0: failed to read from `tests/compositions/component-missing/a.wat`: No such file or directory (os error 2)
0: failed to read from `tests/compositions/component-missing/a.wat`
1: No such file or directory (os error 2)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
failed to parse component `tests/compositions/missing-explicit-dep/a.wat`

Caused by:
0: failed to read from `tests/compositions/missing-explicit-dep/a.wat`: No such file or directory (os error 2)
0: failed to read from `tests/compositions/missing-explicit-dep/a.wat`
1: No such file or directory (os error 2)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
failed to parse component `tests/compositions/missing-root/root.wat`

Caused by:
0: failed to read from `tests/compositions/missing-root/root.wat`: No such file or directory (os error 2)
0: failed to read from `tests/compositions/missing-root/root.wat`
1: No such file or directory (os error 2)
4 changes: 2 additions & 2 deletions crates/wat/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ impl fmt::Display for Error {
},
ErrorKind::Io { err, file, .. } => match file {
Some(file) => {
write!(f, "failed to read from `{}`: {}", file.display(), err)
write!(f, "failed to read from `{}`", file.display())
}
None => err.fmt(f),
},
Expand Down Expand Up @@ -321,7 +321,7 @@ mod test {
let e = parse_file("_does_not_exist_").unwrap_err();
assert!(e
.to_string()
.starts_with("failed to read from `_does_not_exist_`: "));
.starts_with("failed to read from `_does_not_exist_`"));

let mut e = parse_bytes("()".as_bytes()).unwrap_err();
e.set_path("foo");
Expand Down
4 changes: 4 additions & 0 deletions src/bin/wasm-tools/addr2line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ pub struct Opts {
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(&self) -> Result<()> {
let wasm = self.io.parse_input_wasm()?;

Expand Down
23 changes: 21 additions & 2 deletions src/bin/wasm-tools/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ impl Opts {
Opts::Embed(embed) => embed.run(),
}
}

pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
match self {
Opts::New(new) => new.general_opts(),
Opts::Wit(wit) => wit.general_opts(),
Opts::Embed(embed) => embed.general_opts(),
}
}
}

fn parse_optionally_name_file(s: &str) -> (&str, &str) {
Expand Down Expand Up @@ -91,6 +99,10 @@ pub struct NewOpts {
}

impl NewOpts {
fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

/// Executes the application.
fn run(self) -> Result<()> {
let wasm = self.io.parse_input_wasm()?;
Expand Down Expand Up @@ -172,10 +184,13 @@ pub struct EmbedOpts {
}

impl EmbedOpts {
fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

/// Executes the application.
fn run(self) -> Result<()> {
let wasm = if self.dummy {
self.io.init_logger();
None
} else {
Some(self.io.parse_input_wasm()?)
Expand Down Expand Up @@ -217,7 +232,7 @@ impl EmbedOpts {
#[derive(Parser)]
pub struct WitOpts {
#[clap(flatten)]
verbosity: wasm_tools::Verbosity,
general: wasm_tools::GeneralOpts,

/// Input file or directory to process.
///
Expand Down Expand Up @@ -275,6 +290,10 @@ pub struct WitOpts {
}

impl WitOpts {
fn general_opts(&self) -> &wasm_tools::GeneralOpts {
&self.general
}

/// Executes the application.
fn run(self) -> Result<()> {
let name = match &self.name {
Expand Down
7 changes: 5 additions & 2 deletions src/bin/wasm-tools/compose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ pub struct Opts {
#[clap(flatten)]
cmd: WasmComposeCommand,
#[clap(flatten)]
verbosity: wasm_tools::Verbosity,
general: wasm_tools::GeneralOpts,
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
&self.general
}

pub fn run(self) -> Result<()> {
self.verbosity.init_logger();
self.cmd.execute()
}
}
4 changes: 4 additions & 0 deletions src/bin/wasm-tools/demangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ pub struct Opts {
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(&self) -> Result<()> {
let input = self.io.parse_input_wasm()?;
let mut module = wasm_encoder::Module::new();
Expand Down
4 changes: 4 additions & 0 deletions src/bin/wasm-tools/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ pub struct Opts {
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(&self) -> Result<()> {
let input = self.io.parse_input_wasm()?;
let output = self.io.output_writer()?;
Expand Down
56 changes: 53 additions & 3 deletions src/bin/wasm-tools/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use anyhow::Result;
use clap::Parser;
use std::io;
use std::io::{self, Write};
use std::process::ExitCode;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

macro_rules! subcommands {
($(
Expand Down Expand Up @@ -33,6 +34,15 @@ macro_rules! subcommands {
)*
}
}

fn general_opts(&self) -> &wasm_tools::GeneralOpts {
match *self {
$(
#[cfg(feature = $string)]
Self::$name(ref opts) => opts.general_opts(),
)*
}
}
}
}
}
Expand All @@ -58,7 +68,10 @@ subcommands! {
}

fn main() -> ExitCode {
let err = match <WasmTools as Parser>::parse().run() {
let args = <WasmTools as Parser>::parse();
args.general_opts().init_logger();
let color = args.general_opts().color;
let err = match args.run() {
Ok(()) => return ExitCode::SUCCESS,
Err(e) => e,
};
Expand All @@ -72,10 +85,47 @@ fn main() -> ExitCode {
_ => {}
}
}
eprintln!("Error: {:?}", err);

// ignore errors here since if we fail to print an error it's not like we
// can print it again.
let _ = print_error(color, err);
ExitCode::FAILURE
}

fn print_error(color: ColorChoice, err: anyhow::Error) -> Result<()> {
let color = if color == ColorChoice::Auto && !atty::is(atty::Stream::Stderr) {
ColorChoice::Never
} else {
color
};
let mut stderr = StandardStream::stderr(color);
stderr.set_color(ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true))?;
write!(stderr, "error")?;
stderr.set_color(ColorSpec::new().set_fg(None).set_bold(true))?;
write!(stderr, ": ")?;

let msg = err.to_string();
for (i, line) in msg.lines().enumerate() {
writeln!(stderr, "{line}")?;
if i == 0 {
stderr.set_color(ColorSpec::new().set_reset(true))?;
}
}

if err.chain().len() == 1 {
return Ok(());
}
writeln!(stderr, "\nCaused by:")?;
for (i, err) in err.chain().skip(1).enumerate() {
writeln!(
stderr,
"{i:>5}: {}",
err.to_string().replace("\n", "\n ")
)?;
}
return Ok(());
}

/// If CARGO_VERSION_INFO is set, use it, otherwise use CARGO_PKG_VERSION.
fn version() -> &'static str {
option_env!("CARGO_VERSION_INFO").unwrap_or(env!("CARGO_PKG_VERSION"))
Expand Down
15 changes: 15 additions & 0 deletions src/bin/wasm-tools/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ impl Opts {
Opts::Add(opts) => opts.run(),
}
}

pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
match self {
Opts::Show(opts) => opts.general_opts(),
Opts::Add(opts) => opts.general_opts(),
}
}
}

/// Read metadata (module name, producers) from a WebAssembly file.
Expand All @@ -29,6 +36,10 @@ pub struct ShowOpts {
}

impl ShowOpts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(&self) -> Result<()> {
let input = self.io.parse_input_wasm()?;
let mut output = self.io.output_writer()?;
Expand Down Expand Up @@ -58,6 +69,10 @@ pub struct AddOpts {
}

impl AddOpts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(&self) -> Result<()> {
let input = self.io.parse_input_wasm()?;

Expand Down
4 changes: 4 additions & 0 deletions src/bin/wasm-tools/mutate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ pub struct Opts {
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(mut self) -> Result<()> {
let input_wasm = self.io.parse_input_wasm()?;

Expand Down
6 changes: 5 additions & 1 deletion src/bin/wasm-tools/objdump.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::Result;
use termcolor::WriteColor;
use std::io::Write;
use std::ops::Range;
use termcolor::WriteColor;
use wasmparser::{Encoding, Parser, Payload::*};

/// Dumps information about sections in a WebAssembly file.
Expand All @@ -15,6 +15,10 @@ pub struct Opts {
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(&self) -> Result<()> {
let input = self.io.parse_input_wasm()?;

Expand Down
4 changes: 4 additions & 0 deletions src/bin/wasm-tools/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ pub struct Opts {
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(&self) -> Result<()> {
let binary = self.io.parse_input_wasm()?;
self.io.output(wasm_tools::Output::Wasm {
Expand Down
4 changes: 4 additions & 0 deletions src/bin/wasm-tools/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ pub struct Opts {
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(&self) -> Result<()> {
let wasm = self.io.parse_input_wasm()?;
let mut printer = wasmprinter::Printer::new();
Expand Down
4 changes: 4 additions & 0 deletions src/bin/wasm-tools/shrink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ pub struct Opts {
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(self) -> Result<()> {
let input = self.io.parse_input_wasm()?;
let initial_size = input.len();
Expand Down
7 changes: 5 additions & 2 deletions src/bin/wasm-tools/smith.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub struct Opts {
module_config: Config,

#[clap(flatten)]
verbosity: wasm_tools::Verbosity,
general: wasm_tools::GeneralOpts,
}

#[derive(Default, Debug, Parser, Clone, serde::Deserialize)]
Expand Down Expand Up @@ -195,8 +195,11 @@ struct Config {
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
&self.general
}

pub fn run(&self) -> Result<()> {
self.verbosity.init_logger();
let seed = match &self.input {
Some(f) => {
std::fs::read(f).with_context(|| format!("failed to read '{}'", f.display()))?
Expand Down
4 changes: 4 additions & 0 deletions src/bin/wasm-tools/strip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ pub struct Opts {
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(&self) -> Result<()> {
let input = self.io.parse_input_wasm()?;
let to_delete = regex::RegexSet::new(self.delete.iter())?;
Expand Down
4 changes: 4 additions & 0 deletions src/bin/wasm-tools/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ pub struct Opts {
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
self.io.general_opts()
}

pub fn run(&self) -> Result<()> {
// Note that here we're copying the contents of
// `Validator::validate_all`, but the end is followed up with a parallel
Expand Down
7 changes: 5 additions & 2 deletions src/bin/wasm-tools/wit_smith.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,15 @@ pub struct Opts {
arbitrary_config: bool,

#[clap(flatten)]
verbosity: wasm_tools::Verbosity,
general: wasm_tools::GeneralOpts,
}

impl Opts {
pub fn general_opts(&self) -> &wasm_tools::GeneralOpts {
&self.general
}

pub fn run(&self) -> Result<()> {
self.verbosity.init_logger();
let seed = match &self.input {
Some(f) => {
std::fs::read(f).with_context(|| format!("failed to read '{}'", f.display()))?
Expand Down
Loading

0 comments on commit fa52023

Please sign in to comment.